Sync and gitignore settings
These two keys of agnostic-ai.yaml control how sync writes generated files and what it adds to .gitignore. Every other key is in Configuration.
sync
Per-run flags such as --diff, --format, and --jobs have no config key. See sync and reading a failing --check.
| Key | Default | Effect |
|---|---|---|
collision-policy | prompt | What happens when two targets write the same path. |
target-overview | false | Add a section to each entry-point file that lists where generated files live. |
resolve-imports | passthrough | What tools that cannot resolve @path lines get. |
dropped-summary | false | Print a per-target summary of dropped and downgraded kinds. |
shared-skills | false | Link identical skill folders to one copy. |
unmanaged | empty | Paths sync never touches. |
output-manifest | false | Write .agnostic-ai/outputs.lock, the committed list of generated paths. |
allow-global-names | empty | Names shared with the global home that sync does not warn about. |
global-name-clash | warn | Whether sync warns about names shared with the global home. |
sync.collision-policy
Applies when two targets write different content to one path, such as outputs.codex.rules-file: AGENTS.md and outputs.amp.rules-file: AGENTS.md. Per-target override: outputs.<target>.collision-policy.
| Value | Behavior |
|---|---|
prompt | Default. Fail with an output collision error and a hint. |
prefer-spec | Write the version of the last tool in targets: that writes the file. sync --check expects that version. Sync prints one note per winning tool naming the files it won and the tools it overrode; reorder targets: to change it. Use in CI when the overlap is intentional. |
fail | Hard error with no hint. |
sync:
collision-policy: prefer-spec
sync.target-overview
When true, each entry-point file (CLAUDE.md, AGENTS.md, GEMINI.md, ...) gets a section listing where that tool's generated files live, following outputs.<target>.* overrides.
- A shared entry point such as
AGENTS.mdlists each reader in its own section. - Sync rewrites the section between
<!-- agnostic-ai:target-overview:start -->and<!-- agnostic-ai:target-overview:end -->.importremoves it. Aider and external adapters get no section.
sync.resolve-imports
Controls standalone @path lines in AGNOSTIC_AI.md for tools that cannot resolve imports. CLAUDE.md always keeps the line. An @mention inside a sentence or a fenced code block is untouched. Paths resolve from the project root.
| Value | Tools that cannot resolve it get |
|---|---|
passthrough | Default. The @-line as written, as a dead reference. |
strip | Nothing: the line is dropped. |
inline | The file's content between <!-- agnostic-ai:import:start <path> --> and <!-- agnostic-ai:import:end -->. import restores the @-line. A missing file fails the sync. |
sync:
resolve-imports: inline
sync.dropped-summary
When true, sync ends with a per-target list of kinds that were dropped (the tool has no support) or downgraded (written only behind an opt-in key, or only in the source directory). It groups capability warnings and coverage notes by tool.
sync.shared-skills
When true, tools that share the Agent Skills layout (<dir>/<name>/SKILL.md plus assets: Claude, Cursor, Codex, Amp) keep one real copy of each skill and link the others to it with relative symlinks.
- Only folders with identical content link. Skills with per-tool overrides such as
x-cursorkeep real copies. - Turning the option off restores real copies on the next sync.
- Without symlink support (Windows without the privilege), sync warns once and keeps real copies.
If you commit shared skill links, Git must check them out as links. Git's core.symlinks setting is separate from the system's permission to create links. With core.symlinks=false, sync --check --against index and --against HEAD name each link Git exported as a plain file. To fix it:
- Where the system can create links, run
git config --local core.symlinks trueand rerun the check. - To keep
core.symlinks=false, setsync.shared-skills: false, runagnostic-ai sync, and stage the config and the restored skill copies. Commit that before you check--against HEAD.
sync.unmanaged
Paths you own. sync never writes, merges, copies, or removes them.
sync:
unmanaged:
- .cursor/rules/legacy.mdc # exact path
- .claude/agents/hand-*.md # glob; `*` stays inside one path segment
- .claude/skills/legacy/ # trailing slash: everything under the directory
- Entries are project-relative with forward slashes. Filename patterns use Go
path.Match;**acts like*and stays inside one folder name, so**/xmisses the root and deeper folders anddir/**matches only files directly insidedir/(writedir/). Lint, doctor, and sync warn about it (LINT057). A malformed glob or an empty entry fails config load. syncprints~ skip (unmanaged) <path>.sync --check,status, anddoctornever count it as drift.revertanddoctor --fixnever touch it.- Removing the entry deletes nothing. The next sync rewrites the file.
sync.shared-skillsnever links such a skill folder.agnostic-ai.local.yamlreplaces the entire list.- Hook script bodies copied from
.agnostic-ai/scripts/are not covered.
sync.output-manifest
Use it when you commit generated files. A full sync writes .agnostic-ai/outputs.lock: one line per generated path, with a checksum of what sync wrote. Commit it with the outputs; sync --check fails when it is missing or out of date.
sync:
output-manifest: true
- With no
.sync-state,doctorandsync --checkcount a tracked file the generated-path list includes but no spec produces as a leftover.doctor --fixremoves it. - A file edited since sync wrote it no longer matches its checksum, so it is left for you.
sync --check --againstreads the generated-path list from the state it checks. It catches a deleted spec's outputs even in a shallow clone, unless that list was regenerated in the same commit.
sync.allow-global-names
Skill and agent names this project shares with the global home on purpose. sync prints no warning for a listed name. Other shared names still warn.
# agnostic-ai.local.yaml
sync:
allow-global-names: [gh-issue, gh-issues]
- Put the list in
agnostic-ai.local.yaml, since the home exists only on your machine. A local list replaces the entire shared list. - Names match the way Claude Code folds skill names: case, spacing, and invisible characters do not count.
doctorstill lists each allowed name under Global names, marked as allowed.
sync.global-name-clash
What sync does with every name this project shares with the global home: warn prints the warning, ignore prints nothing.
# agnostic-ai.local.yaml
sync:
global-name-clash: ignore
- Use it when a project shadows global skills or agents as a rule. To accept a few names, use
sync.allow-global-names. doctorstill lists each shared name under Global names, marked as ignored.- Any other value fails config load.
gitignore
| Field | Default | Description |
|---|---|---|
enabled | false when absent; agnostic-ai init writes true | Every sync rewrites a managed .gitignore block listing every path the configured adapters write. |
path | .gitignore | Another file inside the project, such as a nested folder's .gitignore or the local-only .git/info/exclude. Any other path outside the project or in .git/ fails to load. |
commit | empty | Kinds of generated output to keep in Git, for every target or as <target>:<kind> for one. The block leaves out their paths. |
allow | empty | Gitignore globs written as ! lines at the end of the block, so a hand-written file at a generated path (such as a testdata/AGENTS.md fixture) is not ignored. One pattern per entry; a line break fails to load. |
worktree-include | true | Keep the same block in .worktreeinclude. See Claude Code worktrees. |
ignore-worktree-include | false | Keep .worktreeinclude out of Git. See Claude Code worktrees. |
sync --gitignore and init --gitignore override it per run. See the CLI reference.
Use commit for files that review bots and a fresh worktree read before any sync runs:
gitignore:
enabled: true
commit: [instructions, hooks]
- Kinds:
instructions,agents,skills,commands,hooks,mcps,settings,reviews,environments, andignores. An unknown kind fails config loading. instructionscovers entry-point files (AGENTS.md,CLAUDE.md,GEMINI.md) and rule outputs, root and scoped. Every other kind is named after its spec source.- A file written by several kinds, such as
.claude/settings.json, is committed when any of them is listed. ellipsis:reviews,ellipsis:environments, andellipsis:mcpsalso count the settings spec that holdsx-ellipsis, because.ellipsis/code-review.yamland.ellipsis/environments/<name>.yamlneed both (Ellipsis).- A file that only the config or an overlay produces belongs to no kind and stays ignored.
Prefix a kind with a target to commit it for that target only:
gitignore:
enabled: true
commit: [cursor:reviews, cursor:environments]
This keeps .cursor/environment.json, .cursor/worktrees.json, and every BUGBOT.md in Git, and ignores .claude/launch.json and .codex/environments/environment.toml. lint warns (LINT017) when the target is not in targets.
The block sits between # >>> agnostic-ai (managed) >>> and # <<< agnostic-ai (managed) <<<. Lines outside it are kept.
Claude Code worktrees
A new Claude Code worktree has no gitignored files. Claude Code copies the ones that .worktreeinclude lists from the main checkout.
With claude in targets, sync also keeps the block in .worktreeinclude, minus .sync-state, .command-lock, Claude worktree directories, and the task lock. Your local files and packs come along, so the worktree renders what the main checkout does.
- Set
gitignore.ignore-worktree-include: trueto keep the managed file out of Git by listing it in the managed ignore block. It requiresworktree-include: trueandclaudeintargets. If the file is already tracked, runagnostic-ai sync --untrackto remove it from the index and keep the file. - Set
gitignore.worktree-include: falseto manage the file yourself. Sync then removes only its own block.
A fresh clone or git worktree lacks these paths until sync runs. See checkout and merge hooks.
Block contents
- Entries are root-anchored (
/AGENTS.md), so nested same-named files are not ignored. - Files collapse to their generated subdirectory (
/.claude/rules/), never higher, so siblings such as.claude/settings.jsonstay visible. A per-kind dir such asoutputs.<target>.rules-dircollapses at the dir itself. - Output under a rule or review
scopestays one line per file (/services/api/AGENTS.md). - The block always holds
agnostic-ai.local.yaml,/.agnostic-ai/.command-lock,/.agnostic-ai/.sync-state,/.agnostic-ai/packs/, and/.agnostic-ai/local/.initseeds them even withgitignore.enabled: false. - A leftover file from a deleted spec stays ignored until you remove it.
- A target can add entries of its own, such as Claude Code's local settings.
- Built-ins come from
agnostic-ai.yamlalone, so abuiltinslist inagnostic-ai.local.yamlleaves the block and.worktreeincludeunchanged. Outputs only the local list adds go in anagnostic-ai (personal)block in.git/info/exclude, and sync removes those lines when the local list stops adding them. Outputs the local list turns off stay in the block. A linked worktree shares.git/info/excludewith every checkout, so there sync leaves those outputs untracked and names them in a warning.