Type to search the docs and updates.

Browse documentation

Global configuration

Source and targets

agnostic-ai sync --global installs user-level instructions, rules, hooks, and skills for 22 of the 26 targets. Global output lists the paths. It works from any directory and loads no packs or project specs.

The source folder is $AGNOSTIC_AI_HOME, or ~/.agnostic-ai/ when unset.

~/.agnostic-ai/
├── agnostic-ai.yaml        # optional: targets, builtins, requires, lint, on-unsupported, models
├── AGNOSTIC_AI.md
├── agents/*.md
├── rules/*.md
├── hooks/*.yaml
├── settings/*.yaml         # default model and effort
├── mcps/*.yaml             # user-level MCP servers
├── skills/<name>/SKILL.md
└── local/                  # optional personal layer, same layout

Specs in local/ merge into shared specs of the same kind and name, field by field, and new names append. A ::parent line extends the shared body. See local overrides. local/AGNOSTIC_AI.md comes last in the managed instructions block. Add /local/ to the source root's .gitignore before adding personal files.

To sync a fixed set of tools without --only on every run, list them in the source root's agnostic-ai.yaml:

targets: [claude, codex, cursor]
  • sync --global, lint --global, and validate --global then use only those targets. A targets list in local/agnostic-ai.yaml replaces the shared one.
  • --only and --except narrow the list for one run and must name configured targets. --target replaces it and skips the home config's targets.
  • A target with no user-level files, such as aider or continue, is skipped with one warning. An unknown name stops the run.
  • builtins, requires, lint, and models work as in a project. For each key, local/agnostic-ai.yaml replaces the shared value. A models tier replaces the same-name tier whole. When a file's tiers do not load, sync --global stops. With -t, it warns, skips that file's tiers, and omits the model of any spec that names one.
  • on-unsupported sets what sync --global does with a skill line that Claude Code expands and another target reads as plain text: warn prints a note, error fails the sync, silent hides it. See Claude Code body syntax.
  • Other keys except version print a warning and are ignored.
  • A target dropped from the list keeps its synced files and ownership records until you remove them by hand.

list --global shows the specs in effect with their builtin, global, or global-local layer. validate --global and lint --global check before a sync writes. migrate --global rewrites old spec forms. Global layers never merge with project specs.

  • Accepted sync flags are in the CLI reference.
  • Nested rules, rules with scope, path, glob, or target conditions, commands, settings permissions rule lists for targets other than Claude Code, inheritance, and merging with project specs are unsupported.
  • Skills copy their supporting files unchanged. Shared directories such as ~/.agents/skills/ keep neutral frontmatter. See skill invocation support for disable-model-invocation, including OpenCode V2.
  • Hooks and skills honor target, targets, and targets-exclude. Supported portable on events and match values translate for each tool. Native event and matcher values pass through unchanged; set those per target. See portable hooks.
  • Copilot user hooks write ~/.copilot/hooks/agnostic-ai.json; COPILOT_HOME moves the native home. import --global copilot adopts matching handlers from neighboring user JSON files without adding a second copy. See Copilot hooks for conflict recovery.
  • Cline SDK/CLI global hooks write ~/.cline/hooks/<Event>; CLINE_DIR moves the root. The VS Code extension uses a separate Documents folder that sync does not write. See Cline global hooks.
  • Kiro CLI V3 global hooks write one ~/.kiro/hooks/<name>.json per spec, using the same format as project hooks. KIRO_HOME moves the hooks and scripts with Kiro's other global folders. Shared scripts go to ~/.kiro/scripts/. Unrelated hook files stay; a conflicting file stops sync.
  • Targets without global agent output warn and skip agents.
  • Output is real files, never symlinks. A user file that is itself a symlink, such as a dotfiles-managed CLAUDE.md, is written through. A symlink inside a skills, agents, or rules directory stops the run.
  • Sync records what it wrote in $AGNOSTIC_AI_HOME/state/global.json and removes only those files and settings for the targets in the run. With --only, other targets' output stays in place.
  • A hand edit to a file sync owns, or to an instructions file's managed block, stops the run and names the file. Move the edit into the source, or rerun with --backup to overwrite it and keep <path>.bak. Text outside the managed block never counts.
  • A file or hook that already matches what sync would write is adopted. One that differs, even by one byte, stops the run. So do an unmanaged agent, skill, or rule collision, a damaged marker, invalid native JSON, corrupt state, and state recorded under another HOME.
  • Without --only, explicit targets, or a home targets list, a target with a relative root variable or an invalid agent name is skipped with a warning. Naming it makes that an error.
  • Each tool decides which settings win when global and project configuration both exist. See shared names. Sync Goose and OpenHands together to update their shared agent file.

Ordinary agnostic-ai sync reads only the names of ~/.agnostic-ai/ specs, to warn about shared names.

Inside the global source root, sync stops before any write and points you to sync --global. init, import, new, packs, cleanup, revert, and install-hook stop the same way. Read-only commands such as lint, validate, and doctor still run. Put project-only defaults in a project's .agnostic-ai/ or a pack.

For a home kept in Git, install-hook --global writes a pre-commit hook that runs lint --global --strict, validate --global, and sync --global --check. To start a home from what your tools already hold, run agnostic-ai import --global. See import.

Shared names

A project skill or agent can share its name with one in the home. Sync writes both, and each tool decides which one it loads. sync and doctor print one warning per shared name, naming each target where one copy hides the other, which copy wins, and the fix:

! .agnostic-ai/skills/gh-issue/SKILL.md: skill "gh-issue" also exists in ~/.agnostic-ai/skills/gh-issue/SKILL.md with different content; claude loads the global one, which exists only on this machine, gemini loads this one; to load both, rename the global one (such as gh-issue-personal), or delete it to drop it, then run `agnostic-ai sync --global`; project sync cannot select this skill instead on claude

A home skill can hide a project skill with the same name. Claude Code and Amp do not document a project setting that selects only that project copy while keeping other home skills. Amp's amp.skills.disableGlobalAgentsSkills disables discovery of all skills from the global agents folders; it does not choose one conflicting name. Sync keeps both copies and explains that limit; it does not change your home files. Renaming a copy lets both load, but changes the name you use to call it. Doctor reports the limit even when sync warnings are silenced.

A winning global copy changes what you run, not what others run from the repository. When only project copies win, the warning says the global one is unused here. When both copies hold the same content, it says to delete one before they drift apart.

TargetSkill with the same nameAgent with the same name
AmpGlobal wins when both sync amp: ~/.agents/skills/ masks .agents/skills/ (skills)No global agents
Claude CodeGlobal wins (skills)Project wins (subagents)
CodexBoth can appear in skill selectors, so no warning (skills)Not checked
Gemini CLIProject wins (skills)Not checked

Other tools do not document which settings win, so sync does not warn for them.

Which pairs the check compares
  • Targets that both the project and the home's targets write. A spec whose target, targets, or targets-exclude leaves one of them out is skipped.
  • Claude Code skill names match ignoring case, spacing, invisible characters, and fullwidth forms. Other targets compare names exactly.
  • A spec shared through a link is not a clash. Neither is a project that is the home.

To layer on purpose, give the project spec its own name, such as a gh-issue-project skill beside a global gh-issue. Both then load everywhere.

To keep one name in both places, list it in sync.allow-global-names. To stop the warning for every shared name, set sync.global-name-clash: ignore.

Default model and effort

Settings specs in the home set each tool's default model and effort in its user settings file. model and effort each take one string for every target, or a per-target map with an optional default:

# ~/.agnostic-ai/settings/defaults.yaml
model:
  claude: opus
  codex: gpt-6-luna
effort:
  claude: high
  codex: high
TargetFileKeys
codex~/.codex/config.tomlmodel, model_reasoning_effort
claude~/.claude/settings.jsonmodel, effortLevel, permissions.defaultMode, permissions.allow, ask, deny
copilot~/.copilot/settings.jsonmodel, effortLevel
qoder~/.qoder/settings.jsonmodel.name, model.reasoningEffort
gemini~/.gemini/settings.jsonmodel.name

Other targets, and permission lists for every target but Claude, raise a coverage note, and so does effort on Gemini. Augment has no default model or effort key but takes x-augment keys, such as shell.

Accepted effort values:

  • Claude and Copilot: low, medium, high, xhigh.
  • Qoder: disabled, off, none, low, medium, high, xhigh, max.
  • Codex: any string.

A dotted key is a nested JSON object: sync sets name inside model and leaves the other keys alone. lint --global (LINT014) and validate --global flag a value a target cannot take.

Set Claude Code's starting permission mode in a home settings spec:

# ~/.agnostic-ai/settings/defaults.yaml
permissions:
  default-mode: acceptEdits

sync --global --only claude writes permissions.defaultMode in ~/.claude/settings.json, or under CLAUDE_CONFIG_DIR. It accepts default, manual, acceptEdits, plan, auto, dontAsk, and bypassPermissions. A later settings spec wins. Removing the field removes the managed mode, unless you changed it by hand.

Claude permission-list import and sync were added after v0.85.0. The v0.85.0 release does not support these lists.

Home permissions.allow, ask, and deny rules, and the same lists under x-claude.permissions, merge into ~/.claude/settings.json rule by rule:

  • Sync appends each rule a list lacks after the rules already there. A rule already there is adopted.
  • Sync records both added and adopted rules in state/global.json. Dropping a rule from the specs removes it, including a rule you wrote before adoption.
  • Rules absent from the home specs and ownership record keep their order.
  • --check fails while a spec rule is missing or a dropped one remains. --plan and --dry-run list each rule added or removed.
  • Run import --global claude to copy user-level rules into settings/permissions-claude.yaml, so they reach your other machines.

Claude Code saves standing permission approvals to the project's .claude/settings.local.json, which global import does not read. See Claude's settings scopes.

Other targets report a coverage note. For Codex, set x-codex.approval_policy and x-codex.sandbox_mode instead. Claude's auto and bypassPermissions need user, managed, or session settings. See Claude's mode reference.

Set personal transcript age limits with session-retention-days in a home settings spec. Global sync maps it to Claude Code, Gemini CLI, and Qoder CLI; project sync leaves it out. It is unset by default and does not enable disabled cleanup. See session retention for the native keys, deletion warning, and restoration rules.

Each item wins over the one before it:

  1. settings/*.yaml in the home.
  2. local/settings/*.yaml. A same-named file merges into the shared one field by field. A new file comes after the shared ones, so its model and effort win.
  3. The project tier: a project's settings file, such as .codex/config.toml or .claude/settings.json, wins according to the tool's own settings order.
  4. An agent's own model and effort, for that agent.
  5. The tool's flag for one run, such as codex -m or claude --model.

Sync edits only the keys it writes. Removing the spec removes only those keys, and a file sync created is deleted once it is empty.

  • A key that already holds the value sync would write is adopted.
  • A key with another value stops the run and names the file, key, and both values. This is normal for Codex, whose /model picker saves to config.toml. --backup overwrites the key and keeps <path>.bak.
  • --dry-run lists each key a write sets or removes, and --check fails on a changed key.
  • An x-<target> block sets that target's own keys in the same file. Nested objects merge leaf by leaf. An x-claude key wins over the portable field it shares a key with. A later spec wins key by key, and null drops an earlier key.
  • Global sync writes Codex top-level scalars and arrays, such as x-codex.notify, to ~/.codex/config.toml. Tables such as profiles, x-claude.hooks, and x-claude.permissions keys other than allow, ask, and deny raise a coverage note. Project sync does not route x-codex into .codex/config.toml.
  • agnostic-ai explain --global settings/defaults.yaml names the file and key each target gets.

MCP servers

MCP specs in the home's mcps/ install each server in the user MCP file of every target that has one, rendered as the target's project MCP file renders it:

TargetFileWhere
claude~/.claude.json ($CLAUDE_CONFIG_DIR/.claude.json when set)top-level mcpServers.<name>
codex~/.codex/config.toml[mcp_servers.<name>] table
cursor~/.cursor/mcp.jsonmcpServers.<name>
copilot~/.copilot/mcp-config.jsonmcpServers.<name>, with tools: ["*"] when the spec sets none
gemini~/.gemini/settings.jsonmcpServers.<name>
qoder~/.qoder/settings.jsonmcpServers.<name>
warp~/.warp/.mcp.jsonmcpServers.<name>: {command, args, env, working_directory} or {url, headers}
augment~/.augment/settings.jsonmcpServers.<name>
antigravity~/.gemini/config/mcp_config.jsonmcpServers.<name>: {command, args, env, cwd} or {serverUrl, headers}, with optional disabled
openhands~/.openhands/mcp.json ($OPENHANDS_PERSISTENCE_DIR/mcp.json when set)mcpServers.<name>: {command, args, env} or {url, transport, headers, auth}

Each server follows the per-key rules above:

  • A hand-written server that means the same as the spec is adopted. A different one with the same name stops the run, and --backup overwrites it.
  • A server sync wrote is removed when its spec goes. Servers you add under other names stay.
  • In ~/.claude.json, sync edits only its own mcpServers entries and creates a missing file at 0600. If the file changed after sync read it, sync stops without writing. Run it again.
  • A spec with disabled: true stays out of the Augment, Claude, Cursor, Copilot, OpenHands, and Warp user files, where a listed server is live in every project.
  • Antigravity keeps disabled servers with disabled: true in its user file.
  • When CLAUDE_CONFIG_DIR or another root variable moves a file, the next sync removes its entries from the old one.

A personal agent such as ~/.agnostic-ai/agents/reviewer.md with targets: [claude, codex] installs with:

agnostic-ai sync --global --only claude,codex
agnostic-ai sync --global --only claude,codex --check

Sync writes ~/.claude/agents/reviewer.md and ~/.codex/agents/reviewer.toml. If a hand-copied file sits at an output path, save its edits in the source and move it aside first. --backup does not bypass unmanaged collisions.

Global output

sync --global writes user-level configuration for 22 of the 26 targets, separate from project files. A dash means global sync writes nothing for that kind.

TargetInstructionsRulesHooksSkillsAgentsSession retention
claude~/.claude/CLAUDE.mdinlined~/.claude/settings.json~/.claude/skills/<name>/~/.claude/agents/<name>.mddays
cursor~/.cursor/AGENTS.md (bridged)inlined~/.cursor/hooks.json~/.cursor/skills/<name>/~/.cursor/agents/<name>.md-
codex~/.codex/AGENTS.mdinlined~/.codex/hooks.json~/.agents/skills/<name>/~/.codex/agents/<name>.toml-
gemini~/.gemini/GEMINI.mdinlined~/.gemini/settings.json~/.gemini/skills/<name>/~/.gemini/agents/<name>.mddays
qoder~/.qoder/AGENTS.mdinlined~/.qoder/settings.json~/.qoder/skills/<name>/~/.qoder/agents/<name>.mddays
copilot~/.copilot/copilot-instructions.mdinlined~/.copilot/hooks/agnostic-ai.json~/.copilot/skills/<name>/~/.copilot/agents/<name>.agent.md-
cline~/.agents/AGENTS.mdinlined~/.cline/hooks/<event>~/.cline/skills/<name>/~/.cline/agents/<name>.yml-
windsurf~/.config/devin/AGENTS.mdinlined-~/.agents/skills/<name>/~/.config/devin/agents/<name>.md-
amp~/.config/amp/AGENTS.mdinlined-~/.agents/skills/<name>/--
zed~/.config/zed/AGENTS.mdinlined-~/.agents/skills/<name>/--
warp~/.agents/AGENTS.mdinlined-~/.agents/skills/<name>/--
opencode~/.config/opencode/AGENTS.mdinlined-~/.config/opencode/skills/<name>/~/.config/opencode/agents/<name>.md-
antigravity~/.gemini/GEMINI.mdinlined-~/.gemini/config/skills/<name>/~/.gemini/config/agents/<name>/agent.md-
junie~/.junie/AGENTS.mdinlined-~/.junie/skills/<name>/~/.junie/agents/<name>.md-
kiro~/.kiro/steering/AGENTS.mdinlined~/.kiro/hooks/<name>.json~/.kiro/skills/<name>/~/.kiro/agents/<name>.md-
crush~/.config/crush/CRUSH.mdinlined-~/.config/crush/skills/<name>/--
factory~/.factory/AGENTS.mdinlined-~/.factory/skills/<name>/~/.factory/droids/<name>.md-
kilo~/.config/kilo/AGENTS.mdinlined-~/.kilo/skills/<name>/~/.config/kilo/agents/<name>.md-
goose~/.config/goose/.goosehintsinlined-~/.agents/skills/<name>/~/.agents/agents/<name>.md-
openhands---~/.agents/skills/<name>/~/.agents/agents/<name>.md-
trae---~/.trae/skills/<name>/~/.trae-cn/agents/<name>.md-
augment-~/.augment/rules/<name>.md~/.augment/settings.json~/.augment/skills/<name>/~/.augment/agents/<name>.md-
  • MCP reaches the user MCP files of Antigravity, Augment, Claude Code, Codex, Cursor, Copilot, Gemini, OpenHands, Qoder, and Warp. See MCP servers.
  • Settings reach the user settings of Claude Code, Codex, Copilot, Qoder, Gemini (model and session retention), and Augment (x-augment keys only). Claude also maps permissions.default-mode and merges the allow, ask, and deny rule lists; Claude, Gemini, and Qoder map global-only session-retention-days; other targets' global permission lists are unsupported. Other tools raise a coverage note. See default model and effort.
  • Agents use the same formats as project agents. Amp, Zed, Warp, and Crush have no global agent output. See global configuration.
  • Rules are inlined into the instructions file, in the same ## Rules block as the shared body. Augment has no user-level instructions file for the CLI, so its ~/.augment/rules/ entries are always on.

Paths marked ~/.config/ follow XDG_CONFIG_HOME when set. Devin agents use ~/.config/devin/agents/ on Linux and macOS and %APPDATA%\devin\agents\ on Windows.

Native discovery and shared paths

  • Discovery: Copilot's path is for its CLI. OpenHands discovery applies to local conversations. Devin custom profiles are experimental. Trae needs Settings > Beta > Subagents > Enable Subagents Directory.
  • Configuration roots: CLAUDE_CONFIG_DIR, CODEX_HOME, COPILOT_HOME, CLINE_DIR, QODER_CONFIG_DIR, KIRO_HOME, and JUNIE_HOME replace the matching ~/.<tool>/ folder. GEMINI_CLI_HOME is the parent of .gemini/. Everything under that folder moves together. Paths outside it, such as ~/.agents/skills/, stay put. Use absolute paths.
  • Shared paths are written once: ~/.agents/skills/ (codex, windsurf, amp, zed, warp, goose, openhands), ~/.agents/agents/ (goose, openhands), ~/.agents/AGENTS.md (cline, warp), ~/.gemini/GEMINI.md (gemini, antigravity). If two tools would write different content to one path, the run stops before writing and names the path.
  • Copilot agent effort: Copilot agent profiles have no effort key. A portable agent effort of low, medium, high, or xhigh goes to subagents.agents.<name>.effortLevel in ~/.copilot/settings.json. Sync stops when the file has comments, since a rewrite drops them. Rerun with --backup to rewrite it and keep settings.json.bak. A hand-set effortLevel with a different value stops the run. Other effort values raise a coverage note.
  • Cursor does not load the home-level AGENTS.md. Global sync installs a sessionStart hook and a script under ~/.cursor/hooks/ (POSIX shell on macOS and Linux, PowerShell on Windows) that passes the instructions to Cursor. It needs neither agnostic-ai, Python, nor jq, and it adds context without enforcing policy. Existing sessionStart entries stay.
  • OpenCode keeps disable-model-invocation in project and global skills. V2 honors it; V1 does not. See OpenCode skills for native metadata precedence.
  • OpenCode V1 reads ~/.claude/CLAUDE.md only when ~/.config/opencode/AGENTS.md does not exist. Syncing both tools moves V1 onto its own file, so text that lived only in the Claude file stops reaching it. V2 discovers only AGENTS.md; move any guidance from the Claude fallback into OpenCode's AGENTS.md.
  • Devin CLI and VS Code Copilot read ~/.claude/ by default, so syncing claude plus windsurf or copilot delivers the same instructions through two paths.

Targets left out

  • Aider reaches a home instructions file only through a read: entry in ~/.aider.conf.yml.
  • Continue's one documented home setting is the rules: list in the config.yaml it rewrites itself.
  • Jules documents nothing at user level.

Hooks reach nine tools at user level: Claude Code, Codex, Gemini, Qoder, Cursor, Augment, Kiro CLI V3, Copilot, and Cline SDK/CLI. The other tools have no user-level hook output:

  • Factory, Devin CLI, Antigravity, Goose, and Crush use hook formats that global sync does not write. Crush supports only PreToolUse. Junie's hooks are Early Access.
  • Amp, OpenCode, and Kilo expose hooks only as TypeScript plugins. Only OpenCode (.opencode/plugins/) and Kilo (.kilo/plugin/) get project-level ones. OpenCode defaults to V1; each hook selects V2 with x-opencode.plugin-api: v2 on macOS and Linux. On Windows, V2 refuses matching callbacks; use OpenCode V1 with the default V1 hooks.
  • Cline global hooks write ~/.cline/hooks/<Event> for the SDK and CLI. The VS Code extension reads only its Documents Cline/Hooks/ folder at user level. See Cline global hooks.