Every AI coding tool wants instructions in its own format and directory: .claude/CLAUDE.md, .cursor/rules/*.mdc, .github/instructions/*.instructions.md, AGENTS.md, .windsurf/rules/...
Use more than one tool — or work on a team where different people use different tools? You end up maintaining the same rules in 5+ formats. They drift. They go stale. You copy-paste forever.
AgentSync syncs from a single source (.ai/src/) into 11 AI tools: Claude Code, GitHub Copilot, Cursor, Gemini CLI, OpenAI Codex, Windsurf, JetBrains Junie, Cline, Amazon Q, Zed, Google Antigravity.
Write once → agentsync sync → every tool gets instructions in its native format.
.ai/src/rules/testing.md
↓ agentsync sync
├── .claude/rules/testing.md # + @rules/testing.md import in CLAUDE.md
├── .cursor/rules/testing.mdc # + globs/alwaysApply frontmatter
├── .github/instructions/testing.instructions.md # + applyTo frontmatter
├── .windsurf/rules/testing.md # + trigger: always_on frontmatter
├── .amazonq/rules/testing.md
├── AGENTS.md # inlined rule reference (Codex, Gemini, Junie)
└── .rules # merged into single file (Zed)
- ...symlink the files? Tools demand different extensions (
.mdc,.instructions.md), different frontmatter, different nesting. Symlinks can't transform content — AgentSync does. - ...a shell script per tool? You'd be writing the same copy / rename / header-injection logic 11 times. AgentSync is that script, declarative (YAML), already tested on macOS, Linux, and Windows (Git Bash).
- ...stick to the one tool I use today? Teammates pick different ones. Your future self might too. A single source file future-proofs you.
- Zero runtime dependencies. Pure Bash. No Node, Python,
yq, orjq. Install with onecurl | bash.
Table of contents
- The problem
- The solution
- Why not just...?
- Installation
- Quick Start
- Project Structure
- What Each Part Does
- CLI Commands
- Tool Configuration
- Tool YAML Schema
- Supported Tools
- Format Conversions
- Adding a New Tool
- Git Hooks
- Gitignore
- How Sync Works
- Customization workflow
- How Resources Resolve
- Migrating from the 0.10 flat layout
- Path Overrides
- Migrating Existing Configurations
- Workspaces — nested AgentSync projects
- Development
- Uninstall
Requirements: git, bash. Works on macOS and Linux out of the box. On Windows, use WSL or Git Bash (included with Git for Windows).
curl -fsSL https://raw.githubusercontent.com/yelmuratoff/agent/main/install.sh | bashWhat the installer does:
- Clones the repository to
~/.agentsync/ - Creates a symlink
agentsyncin/usr/local/bin/(falls back to~/.local/bin/) - Adds
AGENTSYNC_HOMEto your shell config (~/.zshrcor~/.bashrc)
Restart your terminal or run source ~/.zshrc after installation. Running the installer again updates via git pull.
cd your-project
agentsync init # 1. Interactive wizard in a TTY; auto-detect elsewhere
agentsync enable claude cursor # 2. Turn on the tools you use (prints where to edit)
agentsync add mcp github --command … # 3. (Optional) wire up shared MCP servers
agentsync generate | pbcopy # 4. (Optional) AI-generate a project-specific config
agentsync sync # 5. Distribute to all enabled toolsWhat each step does:
-
agentsync init— Scaffolds the.ai/directory. In a terminal it opens a short wizard to pick which tools and content sections you want; in scripts/CI it runs silently using auto-detection (.claude/,.cursor/,CLAUDE.md, ...) and sensible defaults. Only the payloads you opt into get scaffolded — other tools use shipped base templates at sync time. Useful flags:--tools claude,cursor(explicit list),--content agents,rules(narrow content),--no-detect(blank slate),--yes(accept defaults),--dry-run(preview). Safe to run twice — if.ai/src/already exists, it skips. -
agentsync enable <tool>— Adds the tool totools.enabledand scaffolds editable copies of its settings / hooks at.ai/src/tools/<tool>/, then prints the exact file path to edit plus the shared MCP path. Pass--no-scaffoldto skip materializing files; pass--yesto accept the TTY confirm non-interactively. -
agentsync add mcp <server>— Writes an MCP server entry into the shared.ai/src/mcp.json. On the nextsync, every enabled tool gets the same server map — no copy-pasting across five JSON files. Useagentsync customize <tool> mcponly when a tool needs a divergent map. -
agentsync generate— Prints a detailed prompt that you paste into any AI (Claude, ChatGPT, Gemini). The AI analyzes your project description and generates a complete.ai/src/config tailored to your stack: project-specific AGENTS.md, rules, skills, commands, agents, and settings. Pass optional context:agentsync generate "React + Next.js + Prisma". Use| pbcopy(macOS) or| xclip(Linux) to copy to clipboard. -
agentsync sync— Reads each enabled tool's config (user override + shipped base — see How Resources Resolve), then copies and transforms your source files into tool-specific formats. Rules get renamed (.mdcfor Cursor,.instructions.mdfor Copilot), frontmatter headers are added, commands are converted to TOML for Gemini, agents get the right extensions, and settings/MCP/hooks are placed where each tool expects them. Also updates.gitignoreto exclude generated files.
After sync, tool-specific directories appear (.claude/, .cursor/, .github/, .windsurf/, etc.), each with instructions in that tool's expected format.
Important:
agentsync syncoverwrites generated tool directories entirely. If you already have custom rules, skills, commands, settings, or MCP configs in.claude/,.cursor/,.github/, etc., move them into.ai/src/first. See Migrating Existing Configurations.
AgentSync supports two source layouts:
Structured (default, created by init):
.ai/
├── agent_sync.yaml # project config (tools.enabled, version pin, paths)
└── src/ # Source of truth. Edit ONLY here.
├── AGENTS.md # Agent identity: role, approach, principles
├── rules/ # Rules — always-on constraints
│ ├── core.md
│ └── git.md
├── skills/ # (optional) on-demand step-by-step recipes
│ └── .../SKILL.md
├── commands/ # (optional) custom slash commands
├── agents/ # (optional) subagent personas
├── mcp.json # (optional) shared MCP servers, applied to every tool
└── tools/ # (optional) per-tool overrides
├── claude.yaml # tool YAML (same file as before 0.11)
└── claude/ # per-tool payload dir (NEW in 0.11)
├── settings.json # settings override
├── hooks.json # hooks override
└── mcp.json # per-tool MCP override (shadows mcp.json above)
Note:
initis minimal.mcp.jsonand every file undertools/<tool>/are overrides — they appear only when you opt in viaagentsync enable,agentsync customize, oragentsync add mcp. Missing overrides fall back to shipped base templates automatically — see How Resources Resolve and Customization workflow.
Flat (auto-detected): .ai/AGENTS.md, .ai/rules/, .ai/skills/, .ai/tools/
| Source | Purpose | Tools that use it |
|---|---|---|
| AGENTS.md | Agent identity — role, approach, principles. Copied as-is (renamed per tool: CLAUDE.md, GEMINI.md, .junie/AGENTS.md, 00-context.md). |
All |
| rules/ | Always-on constraints. One file per topic. Auto-converted per tool: .mdc (Cursor), .instructions.md (Copilot), trigger frontmatter (Windsurf). |
All |
| skills/ | On-demand recipes in the open agentskills.io format. Each skill = directory with SKILL.md + optional references/, scripts/, assets/. Description is the trigger (imperative + pushy + ≤1024 chars). Gotchas section prevents repeated mistakes. Inlined as index for tools without native skills support. |
All |
| commands/ | Custom slash commands. review.md → /project:review. Support $ARGUMENTS and !`shell` syntax. Auto-converted to TOML for Gemini. For tools without a native commands surface, AgentSync converts: Codex gets generated skills (command-*/SKILL.md); Amazon Q and Zed get a ## Commands index inlined into the agents file. |
Claude, Cursor, Copilot (.prompt.md), Gemini (TOML), Junie, Cline, Windsurf, Antigravity; Codex (as skills); Amazon Q, Zed (inlined) |
| agents/ | Subagent personas. Isolated context, restricted tools. Frontmatter: model, tools, readonly. Auto-converted to TOML for Codex and to JSON for Amazon Q. |
Claude, Cursor, Copilot (.agent.md), Gemini, Junie, Codex (TOML), Amazon Q (JSON) |
| settings/ | Permissions & config. Per-tool files (claude.json, gemini.json, codex.toml, zed.json). Controls allow/deny rules. Claude hooks also go here. |
Claude, Gemini, Codex, Zed |
| mcp/ | MCP server configs. Per-tool JSON files. Define external tool servers. | Claude, Cursor, Windsurf, Junie, Amazon Q |
| hooks/ | Event hooks. Per-tool JSON files. Scripts that run before/after tool actions (file edits, shell commands, etc.). | Cursor, Copilot, Codex, Windsurf |
| tools/ | YAML configs — define where and how files are synced per tool. | — |
agentsync <command> [options]
| Command | Alias | Description |
|---|---|---|
init [dir] |
Create .ai/ structure with starter templates |
|
sync |
Sync to all enabled tools (--only, --skip, --dry-run, --force, --workspace) |
|
check |
Verify outputs match source (CI-friendly, exit code 0/1) | |
enable <tools…> |
Opt in to one or more tools (scaffolds editable settings/hooks payloads) | |
disable <tools…> |
Opt out of one or more tools | |
add <kind> <name> |
Scaffold a rule, skill, command, subagent, or mcp server |
|
customize <tool> [res] |
Create a per-field override for a tool | |
simplify [tool] |
Remove override fields that match the base (--apply) |
|
show <tool> |
Show effective (merged) config for a tool | |
diff [tool] |
Show user overrides vs base defaults | |
resolve |
Interactively reconcile overrides with base values | |
refresh |
Pull new template files into existing .ai/src/ (three-way diff; --status to list declined) |
|
dedupe |
Interactively remove source files duplicated against a parent .ai/src/ |
|
migrate |
Move legacy flat-layout overrides into per-tool dirs; clean up pre-v0.6 .agent/ |
|
adopt <dest> |
Promote a manual edit in a generated file back into .ai/src/ |
|
doctor |
Validate setup and surface drift / config warnings / cross-project advisories | |
generate [context] |
gen |
Print AI prompt for project-specific config generation |
setup-hooks |
Install git hooks for auto-sync on pull/checkout | |
export |
Bundle .ai/src/ into a shareable archive |
|
import <src> |
Import config from a GitHub repo, archive, or directory | |
list |
ls |
Show configured tools and status |
update |
Self-update via git pull (auto-check every 24h) | |
upgrade-config |
Re-pin agentsync_version in agent_sync.yaml |
|
release |
Bump version, tag, and push (maintainer) | |
version |
-v |
Print version |
help |
-h |
Show help |
agentsync sync # All enabled tools
agentsync sync --only claude,cursor # Only specified tools
agentsync sync --skip gemini # All except specified
agentsync sync --dry-run # Preview without writing
agentsync sync --force # Overwrite even if dest files were edited manually
agentsync sync --workspace # Run sync in every .ai/ below cwd (bottom-up alphabetical)agentsync generate # Generate bootstrap prompt
agentsync generate | pbcopy # Copy to clipboard (macOS)
agentsync generate "React + Next.js" # With project contextWorks like claude /init — generates a prompt that you paste into any AI (Claude, ChatGPT, Gemini). The AI analyzes your codebase description and creates a complete .ai/src/ config: AGENTS.md, rules, skills, commands, and agents tailored to your project's stack and conventions.
Each tool = one YAML file in .ai/src/tools/. Filename = tool identifier for --only/--skip. Files starting with _ are ignored.
Example — .ai/src/tools/claude.yaml:
name: "Claude Code"
enabled: true
targets:
agents:
dest: "CLAUDE.md"
rules:
dest: ".claude/rules"
skills:
dest: ".claude/skills"
commands:
dest: ".claude/commands"
subagents:
dest: ".claude/agents"
settings:
source: ".ai/src/settings/claude.json"
dest: ".claude/settings.json"
mcp:
source: ".ai/src/mcp/claude.json"
dest: ".mcp.json"name: "Tool Name"
enabled: true
targets:
agents:
dest: ".tool/AGENTS.md"
# source: ".ai/src/custom.md"
rules:
dest: ".tool/rules"
# source: ".ai/src/my-rules"
# extension: ".mdc"
# header: "---\nkey: value\n---"
# include: "flutter-*.md"
# exclude: "secret-*.md"
# append_imports: true
# merge_to_file: true
# inline_into_agents: true
skills:
dest: ".tool/skills"
# source: ".ai/src/my-skills"
# include: "flutter*"
# exclude: "python*"
# inline_into_agents: true
commands:
dest: ".tool/commands"
# extension: ".prompt.md"
# format: "toml"
subagents:
dest: ".tool/agents"
# extension: ".agent.md"
# format: "toml"
settings:
source: ".ai/src/settings/tool.json"
dest: ".tool/settings.json"
mcp:
source: ".ai/src/mcp/tool.json"
dest: ".tool/.mcp.json"
hooks:
source: ".ai/src/hooks/tool.json"
dest: ".tool/hooks.json"
# post_sync: "npx prettier --write .tool/**/*.mdc"| Field | Purpose |
|---|---|
extension |
Rename file extension (.mdc, .instructions.md, .agent.md, .prompt.md) |
header |
Prepend text to each file (YAML frontmatter for Cursor, Windsurf, Copilot) |
append_imports |
Append @rules/* import lines to AGENTS file (Claude) |
merge_to_file |
Merge all rules into a single file (Zed) |
inline_into_agents (rules) |
Append lightweight rule REFERENCES (name + title) into AGENTS file (Codex, Gemini, Junie) |
inline_into_agents (skills) |
Append lightweight skill INDEX (name + description) into AGENTS file (Cline, Amazon Q, Zed) |
as_skills (commands) |
Emit each command as a generated skill at <skills.dest>/command-<name>/SKILL.md (Codex) |
inline_into_agents (commands) |
Append a ## Commands index (`/<name>` — description) into AGENTS file (Amazon Q, Zed) |
prepend_agents |
Prepend AGENTS.md content before merged rules (Zed) |
format: "toml" |
Auto-convert MD→TOML (Gemini commands, Codex subagents) |
format: "amazonq_json" |
Auto-convert subagent MD→Amazon Q CLI custom-agent JSON (Amazon Q subagents) |
source (settings/mcp/hooks) |
Required — per-tool source file path |
| Tool | Config | Syncs |
|---|---|---|
| Claude Code | claude.yaml |
CLAUDE.md, rules, skills, commands, agents, settings.json, .mcp.json |
| GitHub Copilot | copilot.yaml |
copilot-instructions.md, .instructions.md rules, skills, .prompt.md commands, .agent.md agents, hooks.json |
| Cursor | cursor.yaml |
AGENTS.md, .mdc rules, skills, commands, agents, mcp.json, hooks.json |
| Gemini CLI | gemini.yaml |
GEMINI.md (+inlined rules), skills, commands (MD→TOML), agents, settings.json |
| OpenAI Codex | codex.yaml |
AGENTS.md (+inlined rules), skills, commands (as command-* skills), subagents (MD→TOML), hooks.json, config.toml |
| Windsurf | windsurf.yaml |
AGENTS.md, rules (trigger frontmatter), skills, workflows (commands), mcp_config.json, hooks.json |
| JetBrains Junie | junie.yaml |
.junie/AGENTS.md (+inlined rules), skills, commands, agents, mcp.json |
| Cline | cline.yaml |
00-context.md, .clinerules/, workflows (commands), +inlined skills index |
| Amazon Q | amazonq.yaml |
00-context.md, .amazonq/rules/, +inlined skills index, +inlined commands index, mcp.json, cli-agents (MD→JSON) |
| Zed | zed.yaml |
.rules (prepend AGENTS.md + merged rules), +inlined skills index, +inlined commands index, settings.json |
| Google Antigravity | antigravity.yaml |
GEMINI.md, .agents/rules (trigger frontmatter), .agents/skills, .agents/workflows (commands) |
AgentSync auto-converts between formats during sync:
| Source format | Target format | Used by |
|---|---|---|
Rules .md |
.mdc + YAML frontmatter |
Cursor |
Rules .md |
.instructions.md + applyTo header |
Copilot |
Rules .md |
.md + trigger: always_on header |
Windsurf |
Rules .md |
Single merged file | Zed |
Rules .md |
Inline references (name + title) in AGENTS.md | Codex, Gemini, Junie |
| Skills dirs | Inline index (name + description) in AGENTS.md | Cline, Amazon Q, Zed |
| AGENTS.md | Copied as 00-context.md in rules directory |
Cline, Amazon Q |
| AGENTS.md | Prepended before merged rules | Zed |
Commands .md |
.toml (prompt field, !{} syntax, {{args}}) |
Gemini CLI |
Commands .md |
.prompt.md |
Copilot |
Agents .md |
.agent.md |
Copilot |
Agents .md |
.toml (developer_instructions field) |
Codex |
Agents .md |
.json (Amazon Q CLI custom-agent) |
Amazon Q |
You write everything in Markdown. AgentSync handles the rest.
cp .ai/src/tools/_TEMPLATE.yaml .ai/src/tools/newtool.yaml
# Edit newtool.yaml, then:
agentsync sync --only newtoolagentsync setup-hooksInstalls post-merge and post-checkout hooks. agentsync sync runs automatically on git pull and git checkout. Safe to run multiple times.
agentsync sync auto-manages a block in .gitignore between AI SYNC GENERATED START/END markers. Generated files are gitignored — only .ai/src/ needs to be committed.
- Reads
config.yamlfor default source paths. - Auto-detects structured (
.ai/src/) or flat (.ai/) layout. - For each tool YAML:
- Copies AGENTS.md → tool-specific name (or as
00-context.mdfor directory-based tools) - Syncs rules with extension/header/merge transforms
- If
inline_into_agents(rules): appends lightweight rule references (name + title) to agents file - If
prepend_agents(rules): prepends AGENTS.md content before merged rules - Syncs skills directories (or inlines skill index into agents file if
inline_into_agents) - Syncs commands. Four modes pick the first that fits: native
dest→format: toml→as_skills(writes<skills.dest>/command-*/SKILL.md) →inline_into_agents(appends## Commandsindex to AGENTS file) - Syncs subagents (with optional extension rename or MD→TOML)
- Resolves settings / MCP / hooks per the base + override rules below
- Runs optional
post_synccommand
- Copies AGENTS.md → tool-specific name (or as
- Updates
.gitignore - Disabled tools get their generated files cleaned up automatically.
Three commands cover every customization, each with a single responsibility.
┌───────────────────────────────────────────────────────────────────────────────┐
│ agentsync enable <tool> │
│ → adds tool to tools.enabled │
│ → scaffolds .ai/src/tools/<tool>/{settings,hooks}.<ext> from base │
│ → prints the exact file path to edit │
│ │
│ agentsync add mcp <server> [--command|--url ...] │
│ → creates / updates the shared .ai/src/mcp.json │
│ → applied to every enabled tool on next sync │
│ │
│ agentsync customize <tool> <resource> │
│ → for the rare case you need a per-tool override that differs from │
│ the shared MCP map, or to materialize a payload enable --no-scaffold │
│ skipped (`customize cursor hooks`) │
└───────────────────────────────────────────────────────────────────────────────┘
Mental model:
enableis the entry point. One command turns a tool on and gives you the file to edit.- Shared MCP is the default.
add mcpwrites to.ai/src/mcp.jsonwhich every tool picks up — no per-tool duplication. customizeis the escape hatch. Use it only when you need a per-tool override that diverges from the shared source, or whenenable --no-scaffoldskipped materializing a file you later want.
All three write to .ai/src/tools/<tool>/ (per-tool) or .ai/src/mcp.json (shared). Nothing is scattered across .ai/src/hooks/, .ai/src/mcp/, .ai/src/settings/ — the old flat layout is kept around for backward compatibility (see migrate).
Every payload resource — tool YAML, hooks, MCP config, settings — follows the same layered lookup. Nothing is cloned into every project by default; overrides are opt-in and merge on top of a shipped base.
┌─ 1. Per-tool override ─────────┐ ┌─ 2. Shared MCP (mcp only) ──────┐ ┌─ 3. Shipped base ──────────────────────┐
│ .ai/src/tools/<tool>/ │ │ .ai/src/mcp.json │ │ <install-dir>/lib/templates/<resource>/│
│ <resource>.<ext> │►► │ (applies to every tool) │►► │ <tool>.<ext> │
└────────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────────────┘
per-tool wins → shared fills in (for MCP) → base fills in otherwise
| Resource | Base path | Per-tool override | Shared override |
|---|---|---|---|
| tool YAML | lib/templates/tools/<tool>.yaml |
.ai/src/tools/<tool>.yaml |
— |
| hooks | lib/templates/hooks/<tool>.json |
.ai/src/tools/<tool>/hooks.json |
— |
| mcp | lib/templates/mcp/<tool>.json |
.ai/src/tools/<tool>/mcp.json |
.ai/src/mcp.json |
| settings | lib/templates/settings/<tool>.<ext> |
.ai/src/tools/<tool>/settings.<ext> |
— |
The legacy flat-layout overrides (.ai/src/hooks/<tool>.<ext>, .ai/src/mcp/<tool>.<ext>, .ai/src/settings/<tool>.<ext>) from 0.10 and earlier are still read and still win over base, but print a one-shot deprecation warning. Run agentsync migrate --apply to move them into the canonical per-tool layout; the legacy paths may be dropped in a future release.
Why it matters:
- Lean by default.
agentsync initcreates.ai/agent_sync.yaml,AGENTS.md, and your chosen content sections — no pre-written hooks / MCP / settings for 11 tools you don't use. - Updates flow through. Because the base lives in the install dir,
agentsync updateimproves every project that hasn't locked the file in as an override. - Shared MCP is shared. One
.ai/src/mcp.jsonreaches every enabled tool — no copy-pasting the same server map into five JSON files. - Opt in per tool. Need to edit Cursor's hooks?
agentsync customize cursor hookscopies the current base into.ai/src/tools/cursor/hooks.json. Delete the file later to resume inheriting. - Safe hooks.
customize <tool> hooksprints the base content first and requires--yesin non-interactive mode — you never scaffold executable intent silently. simplifyprunes noise. Scaffolded payloads that are still byte-identical to base are flagged byagentsync simplifyand removed with--apply, so you don't accidentally pin yesterday's defaults forever.
Projects upgraded from 0.10 keep working without intervention — the resolver still reads .ai/src/{hooks,mcp,settings}/<tool>.<ext>. When you are ready to move them into the canonical per-tool layout:
agentsync migrate # dry-run; prints the planned moves
agentsync migrate --apply # performs the moves; consolidates identical MCP files
agentsync migrate --apply -y # non-interactive — accepts MCP consolidation by defaultmigrate moves each legacy file to .ai/src/tools/<tool>/<resource>.<ext>. When every .ai/src/mcp/*.json is byte-identical, it offers to collapse them into the shared .ai/src/mcp.json; if they differ, they migrate per-tool. Existing files at the target are never overwritten — such collisions are skipped with a warning so you resolve them by hand. Empty source directories are cleaned up on success.
migrate also detects the pre-v0.6 monolithic .agent/ (singular, no s) layout — a single directory holding AGENTS.md, workflows/, rules/, skills/ without per-tool separation. The current engine doesn't recognise it, so sync --cleanup never sweeps it. Dry-run lists the contents; --apply --yes removes the directory. Detection runs alongside the flat-layout move logic, so a single migrate --apply --yes cleans up both in one pass.
Create agent_sync.yaml in the project root to override source paths:
source:
agents: ".ai/src/AGENTS.md"
rules: ".ai/src/rules"
skills: ".ai/src/skills"
tools: ".ai/src/tools"If you already have tool-specific configs (.claude/rules/, .cursor/rules/, custom settings.json, etc.), move them into .ai/src/ before running agentsync sync. Sync treats generated directories as fully managed — any files not present in the source will be overwritten or removed.
-
Run
agentsync initto create the.ai/src/structure (skips files that already exist). -
Move your rules from tool-specific directories into
.ai/src/rules/:# Example: you had custom Cursor rules mv .cursor/rules/my-api-conventions.mdc .ai/src/rules/my-api-conventions.md # Remove Cursor-specific frontmatter (---/globs/alwaysApply) — AgentSync adds it automatically # Example: you had custom Claude rules mv .claude/rules/testing.md .ai/src/rules/testing.md
-
Move your skills into
.ai/src/skills/:mv .claude/skills/my-skill/ .ai/src/skills/my-skill/
-
Move your commands into
.ai/src/commands/:mv .claude/commands/deploy.md .ai/src/commands/deploy.md
-
Move your agents into
.ai/src/agents/:mv .claude/agents/security-auditor.md .ai/src/agents/security-auditor.md
-
Move settings, MCP, and hooks into
.ai/src/settings/,.ai/src/mcp/,.ai/src/hooks/:mv .claude/settings.json .ai/src/settings/claude.json mv .mcp.json .ai/src/mcp/claude.json mv .cursor/mcp.json .ai/src/mcp/cursor.json
-
Run sync and verify:
agentsync sync --dry-run # Preview what will be generated agentsync sync # Apply
| Target | Behavior |
|---|---|
Rules directories (.claude/rules/, .cursor/rules/, etc.) |
Files matching the synced extension (.md, .mdc, .instructions.md) are managed by sync. Files not present in source are removed. |
| AGENTS/CLAUDE.md/GEMINI.md | Fully replaced from .ai/src/AGENTS.md on every sync. |
| settings.json, .mcp.json, hooks.json | Fully replaced from their respective source files. |
| Skills, commands, agents directories | Synced contents replace existing files. Extra files are removed. |
| .gitignore | Only the AI SYNC GENERATED START/END block is managed. Your other entries are safe. |
After every successful sync, AgentSync writes .ai/.sync-manifest — one line per generated file with its SHA-256 hash. Commit it to git. On the next sync, every destination is compared against the manifest:
- File untouched → sync rewrites silently (idempotent).
- File deleted manually → sync rewrites silently.
- File edited since last sync → sync aborts with the list of edited paths and your unsynced changes are preserved.
[ERROR] Manual edits detected in 1 destination file(s) since last sync:
.claude/rules/core.md
These files would be silently overwritten. Choose one:
• Move your edits into .ai/src/, then re-run sync
• Re-run with --force to discard the edits and rewrite from source
agentsync check and agentsync doctor both surface drift, so CI catches a forgotten manifest commit before merge.
Quickly iterating in Claude Code or Cursor and edited a generated file directly? Skip the manual cp + sync --force dance:
agentsync adopt .claude/rules/core.md # interactive, with diff preview
agentsync adopt --dry-run .claude/rules/core.md # show plan, write nothing
agentsync adopt --yes .claude/rules/core.md # non-interactive (CI / scripts)Resolves the destination back to its source file (.ai/src/rules/core.md), copies the edited content, and refreshes the manifest entry — the next sync is drift-free.
Refused targets (the round-trip would corrupt your source):
- Tools that inject a frontmatter header (
cursorrules) — adopting would propagate the cursor-specific header to every other tool. - Tools that merge rules into a single file (
gemini,cline) — multiple sources collapsed into one dest can't be split back. - Tools that inline rules/skills into AGENTS.md (
codex,junie). - Format-converted outputs (
codexsubagents → TOML,amazonqsubagents → JSON).
For these cases, edit .ai/src/ directly. AgentSync tells you which file when it refuses.
If you want to keep managing a tool manually, disable it in its YAML config:
# .ai/src/tools/cursor.yaml
enabled: falseOr exclude it at sync time:
agentsync sync --skip cursorA parent project at workspace/.ai/src/ with sub-projects below (workspace/foo/.ai/src/, workspace/bar/.ai/src/) is supported as a first-class workflow. Two patterns to manage shared content between the layers:
Pattern A — declarative inheritance via shared:. Each child project declares which categories it inherits from the parent. At sync time, AgentSync builds a transient shadow .ai/src/ (child + parent fillers, child wins on collisions) and materialises the result into every enabled tool's output — works for tools without parent-loading (Codex, Cursor, JetBrains Junie) and tools with it (Claude Code) equally. Inherited files are never written into the child's .ai/src/; they live only in the shadow tree during a single sync run.
# child/.ai/agent_sync.yaml
shared:
path: "../"
inherit: rules,skills,commands,agentsPattern B — interactive cleanup via dedupe. When child and parent both have the same source file (a copy-paste duplicate), dedupe compares them by hash:
agentsync dedupe # walk up to nearest parent .ai/src/ (bounded by git boundary)
agentsync dedupe --against ../ # explicit parent path
agentsync dedupe --workspace # bottom-up alphabetical fan-out across every nested .ai/
agentsync dedupe --yes # non-interactive: delete identical-hash dupes, leave divergentIdentical-hash files become a [d]elete / [k]eep / [v]iew prompt; for shipped templates the deletion also writes a template_overrides.declined entry so refresh won't re-offer the file. Divergent files (same path, different content) show a diff and leave the decision to the human — dedupe never auto-resolves a divergence.
Detection — agentsync doctor. Doctor walks up to the nearest parent .ai/src/ (same boundary as dedupe) and flags identical-hash duplicates as advisories and divergent files as info. Rules and skills marked with category: governance in their frontmatter are upgraded to advisories when divergent, with explicit "likely a mistake, not an override" framing. All cross-project findings are exit-code-0 advisories — visible during interactive runs, invisible to CI gates, so pre-commit hooks running doctor don't break on workspace techdebt.
Workspace-wide sync. agentsync sync --workspace runs sync in every AgentSync-managed .ai/ below cwd, bottom-up alphabetical (deeper paths first; siblings sorted by LC_ALL=C for reproducibility). Continues past per-project failures; reports max exit code at the end. All other sync options (--only, --skip, --dry-run, --force) forward to each per-project invocation.
The walk-up logic stops at the start's git repository boundary, so a child project with its own .git never picks up an unrelated parent .ai/src/ from above the boundary.
Run the test suite from the repo root:
# Full suite in parallel (needs GNU parallel — `brew install parallel` or
# `apt-get install parallel`). ~2x the CPU count is the sweet spot because
# tests block on git/filesystem. On an 8-core Mac: jobs=16, ≈ 25-30s.
bats --jobs "$(( $(getconf _NPROCESSORS_ONLN) * 2 ))" tests/
# A single file, or a subset:
bats tests/sync.batsCI runs --jobs 4 on Linux and macOS; Windows falls back to serial because
GNU parallel isn't available under git-bash.
# Global
rm -rf ~/.agentsync && rm -f /usr/local/bin/agentsync
# Remove AGENTSYNC_HOME from ~/.zshrc
# Per project
rm -rf .ai/
# Remove AI SYNC GENERATED block from .gitignore