One memory, every agent. Synchronize your AI coding agents' memory, so you can stop in one agent and pick up in another.
Every coding agent accumulates knowledge about you and your projects: Claude
Code writes memory files, Codex keeps a memory store, Goose keeps memories,
Cursor and Continue collect rules. Each lives in its own silo, so switching
agents means starting over. agent sync breaks the silos with a three-stage
round trip:
- Gather: read every agent's own memory stores.
- Synthesize: fold them into one synthesized memory file. Claude does the semantic merge when available, then Codex; if neither is usable, the deterministic marker-delimited merge remains.
- Redistribute: write the result to every installed agent's global instructions slot.
After a sync, every agent knows what every agent has learned. Unlike one-way rules generators, the loop is bidirectional: what your agents learn flows back into the canon.
| Verb | What it does |
|---|---|
agent sync [--synthesizer MODE] [--dry-run] |
The full round trip: gather, synthesize, redistribute |
agent status |
Parity check; exit 1 if any agent is stale (cron-friendly) |
agent diff |
Stale targets as unified diffs; exit 1 on drift (CI gate) |
agent doctor |
Diagnose the setup and report problems |
agent migrate <agent> |
Fold just one agent's stores in, then redistribute |
agent gather [dir] |
Stage all stores into a directory for editing and review |
agent apply [dir] [--synthesizer MODE] [--dry-run] [--only LIST] [--skip LIST] |
Push edited staged files back to their stores, then run the full sync |
agent link [dir] [--import] |
Make one project-scope AGENTS.md readable by every agent in a repo; --import folds the repo's native per-tool configs into it |
agent revert |
Restore .orig adoption backups and the synthesized file's .bak |
agent pack add owner/repo[@ref][:dir] |
Shareable memory packs, pinned to a commit in a lockfile, folded in on every sync |
agent mcp add/remove/sync |
One MCP server registry pushed to every tool, with applied-state tracking for safe updates and removals |
agent skills sync |
Additively synchronize canonical skills without overwriting unmanaged collisions |
agent hooks [tool] |
Print verified automation snippets (Claude/Codex/Gemini hooks, an OpenCode plugin) |
agent targets |
List targets and detection state |
Target filtering: --only claude,codex / --skip qwen flags on sync,
apply and compact; the AGENT_SYNC_ONLY / AGENT_SYNC_SKIP environment
variables additionally apply to status, diff, skills sync and mcp sync.
The edit loop: agent gather, edit the staged files in one place, agent apply. Your edits land back in each agent's own store, get folded into the
synthesized file, and are redistributed to every agent.
Every command with real output, end to end: docs/walkthrough.md.
Safety: the first time sync would overwrite a pre-existing file it did
not write, the original is preserved beside it as <file>.orig, and agent revert restores everything. It remembers what it wrote, so a target still
holding an earlier sync's output is replaced without a backup and a hand
edit made later still gets one. apply validates every manifest entry
against the supported memory-store paths and rejects path traversal and
symlinks.
Pack subdirectories must resolve inside the downloaded repository. MCP files
are written through private atomic temporary files, and CLI-managed MCP
updates validate before replacement and restore the recorded configuration if
replacement fails. Skill directories are replaced only after agent-sync has
recorded ownership; an unmanaged same-name skill is reported and left alone.
With the installer (pinned release, checksum-verified):
curl -fsSL https://raw.githubusercontent.com/hibeekaey/agent-sync/main/install.sh | sh
# or, per-user without sudo:
curl -fsSL https://raw.githubusercontent.com/hibeekaey/agent-sync/main/install.sh | PREFIX=$HOME/.local shWith Homebrew:
brew install hibeekaey/tap/agent-sync
# Upgrading: brew only refreshes taps once per HOMEBREW_AUTO_UPDATE_SECS
# (24 hours by default), so a fresh release can look like "not outdated"
# until the tap is fetched.
brew update && brew upgrade agent-syncFrom a clone (installs the man page and completions too):
make install # /usr/local (may need sudo)
make install PREFIX=~/.local # per-user, no sudoPOSIX sh only, using standard Unix utilities available on macOS and Linux.
Memory packs require curl and tar; semantic synthesis requires a configured
Claude Code or Codex CLI unless deterministic mode is selected.
Global scope (agent sync writes the synthesized file here):
| Agent | Reads the synced file at | Memory stores gathered from |
|---|---|---|
| Claude Code | ~/.claude/CLAUDE.md (the synthesized file itself) |
~/.claude/projects/*/memory/*.md |
| Codex CLI | ~/.codex/AGENTS.md |
~/.codex/memories/*.md |
| Gemini CLI / Antigravity | ~/.gemini/GEMINI.md |
— |
| Qwen Code | ~/.qwen/QWEN.md |
— |
| Continue | ~/.continue/rules/best-practices.md |
~/.continue/rules/*.md |
| Windsurf | ~/.codeium/windsurf/memories/global_rules.md |
~/.codeium/windsurf/memories/*.md |
| Cursor | ~/.cursor/rules/best-practices.mdc (generated .mdc) |
~/.cursor/rules/*.mdc |
| OpenCode | ~/.config/opencode/AGENTS.md |
— |
| Amp | ~/.config/amp/AGENTS.md |
— |
| Goose | ~/.config/goose/.goosehints |
~/.config/goose/memory/* |
| GitHub Copilot CLI | ~/.copilot/copilot-instructions.md |
— |
| Zed | ~/.config/zed/AGENTS.md |
— |
| JetBrains Junie | ~/.junie/AGENTS.md |
— |
| Kiro | ~/.kiro/steering/agent-sync.md |
— |
| Crush | ~/.config/crush/CRUSH.md |
— |
| Roo Code | ~/.roo/rules/agent-sync.md |
— |
| Cline | ~/Documents/Cline/Rules/agent-sync.md |
— |
Every path above was verified against the tool's official documentation.
Tools are detected by their config directory; absent tools are skipped, so
the same binary serves every machine. Files agent-sync generates are never
gathered, so the tool cannot feed on its own output. Aider is deliberately
absent: it has no global instructions mechanism; point read: in
~/.aider.conf.yml at the synthesized file yourself.
Project scope (agent link): one repo-root AGENTS.md — the
AGENTS.md standard is read natively by Codex, Cursor,
Copilot, Zed, Amp, OpenCode, Junie, Goose, Jules and others. link seeds
it (from an existing CLAUDE.md when present), bridges Claude Code with the
officially documented @AGENTS.md import stub, and configures Gemini CLI's
context.fileName (which does not read AGENTS.md by default).
agent sync automatically selects a semantic synthesizer. The same
selection is used by the full sync at the end of agent apply.
Automatic mode sends the synthesized memory document to the locally
configured Claude Code account, then Codex if Claude is unavailable or fails.
Use --synthesizer deterministic when the document must stay entirely local.
A sync folds rather than rewrites. The model is shown the file as
read-only context and the memories imported since the last synthesis, and
answers with only the sections that change — an existing ## heading
copied exactly, or ## Promoted from <agent> for memories that fit nowhere
else — which agent-sync splices back in. A block folded on an earlier sync
(same fingerprint, every identifier still present in the curated text) is
dropped with no model call, so a sync with nothing new costs nothing, and a
fact you remove from the curated text by hand brings its block back for
folding. An answer that is not sections, echoes an import block, repeats a
heading, shrinks a section past 70% (a fold adds) or drops an identifier is
refused; a model that dropped an identifier is first tried once more, told
exactly what it lost, and only then is the next model tried.
agent sync --rewrite (or AGENT_SYNC_REWRITE=1) asks for a rewrite of the
whole document instead, which is the right tool for a deliberate tidy and
takes minutes.
| Selection | Behaviour |
|---|---|
auto (default) |
Try Claude, then Codex, then retain the deterministic merge |
claude / codex |
Require that CLI and use its configured default model |
deterministic |
No model; refreshed marker-delimited imports |
| Custom command | AGENT_SYNC_SYNTHESIZER reading a prompt on stdin, printing the document |
agent sync
agent sync --synthesizer deterministic
AGENT_SYNC_SYNTHESIZER='claude -p' agent syncCLI selection overrides the environment. Model calls are non-interactive
(Claude runs without session persistence; Codex runs ephemerally in a
read-only sandbox), output is validated (a heading first, at least a quarter
of the document's lines, and every real URL, hostname, environment variable
and long id of the document still present), the previous file is kept at
<file>.bak, and every failure falls through toward the deterministic
merge. A recursion guard stops a synthesizer-spawned agent from re-entering
agent-sync.
The script decides the model, so a sync behaves the same on every machine whatever each CLI is set to interactively. Each vendor has a ladder, tried in order until one produces a document the checks accept:
| Vendor | Models | Effort |
|---|---|---|
| Claude | fable, then opus, then sonnet |
low |
| Codex | gpt-5.6-terra, then gpt-5.5, then gpt-5.4 |
low |
A model that is out of credits, rate-limited or unknown fails in seconds and
the next rung runs; one that answers but drops identifiers costs its minutes
and is refused, and the next rung runs; when every rung of every vendor has
failed the deterministic merge stands. Each hand-over is one plain line
saying which model failed, after how long, and why (the vendor's own last
words, e.g. Your workspace is out of credits). Effort is low on purpose:
the work is copying the document back out (Fable at low effort re-emits a
148 KB file faithfully in about ten minutes), and the smaller models were
measured dropping identifiers, which is why they are fallbacks rather than
the first choice. Each vendor runs with its MCP servers switched off, so a
server that is slow, broken or asking for a login cannot slow or break the
rewrite.
Change any of it for one run with flags on sync, apply and compact, or
standing with environment variables (flag over environment):
agent sync --claude-model sonnet --claude-effort medium
agent sync --synthesizer codex --codex-model gpt-5.5 --codex-effort high
agent sync --claude-model fable,opus # a shorter ladder
AGENT_SYNC_CLAUDE_MODEL=opus agent sync # the same, standing| Setting | Flag | Environment |
|---|---|---|
| Claude models (comma-separated ladder) | --claude-model |
AGENT_SYNC_CLAUDE_MODEL |
| Claude effort | --claude-effort |
AGENT_SYNC_CLAUDE_EFFORT |
| Codex models (comma-separated ladder) | --codex-model |
AGENT_SYNC_CODEX_MODEL |
| Codex effort | --codex-effort |
AGENT_SYNC_CODEX_EFFORT |
A model prints nothing until it finishes, and a --rewrite takes minutes.
sync says what it is doing, a dot lands on stderr every 30 seconds on a
terminal (AGENT_SYNC_SYNTH_HEARTBEAT seconds; 0 turns it off), and a model
still running after AGENT_SYNC_SYNTH_TIMEOUT seconds (default 1200; 0 for
none) is stopped so the next rung runs instead of the sync hanging.
One sync writes at a time. A second run started while another holds
~/.config/agent-sync/sync.lock exits 1 naming the holder's pid (dry runs
are not blocked); a lock left by a killed run is reclaimed. A file edited
while the model ran is kept and distributed as edited rather than overwritten
by a rewrite that never saw the edit; run agent sync again to synthesize
it.
The synthesized file is read into every session on every tool, so its size
is paid on every turn. A budget keeps that in check (150 KB by default,
AGENT_SYNC_BUDGET or --budget to change it), and a sync that leaves the
file over it trims it back in the same run: a model rewrites the largest
sections first, asking each for at most a 30% cut until the deficit is
covered, and only when that is not enough deepens the same sections toward
their floors — so a small overrun costs one or two big appendices a light
trim and never touches the dense small ones. This budget pass runs only
after a model synthesis (never with --synthesizer deterministic, so a hook
stays fast), never touches an imported block or archives a store, stands
down when the file is over budget only because of a block still to be
folded (trimming curated text to make room for it would trade what is kept
for what is not), and keeps the .bak the synthesis wrote, so .bak is
still the file as the run found it. --no-compact or AGENT_SYNC_COMPACT=0
skips it.
agent compact does the same by hand, plus what a sync will not: it
promotes raw imported sections into curated notes (## Promoted from claude) and archives their store files to ~/.config/agent-sync/archive/
and removes them, so the next sync has nothing to re-import.
agent compact # exits at once while the file is within budget
agent compact --dry-run # the plan: which sections shrink, to what size
agent compact --force # compact anyway
agent compact --jobs 8 # rewrite eight sections at a time (default 4)Only sections of 2 KB or more are candidates. A rewrite may forget how a
lesson was learned, items marked settled, refuted, muted or parked, one-off
references (commit shas, PR numbers, run ids, past versions) and anything
else of low value, but it is refused and the section kept unless it starts
with the same heading, is at least a quarter of the original, and still
contains every real URL, hostname, environment variable and long id the
original had: those route traffic or unlock access and cannot be re-derived,
while paths, commands and code words are asked for but may go with a story
the rewrite forgets. A rewrite that drops one gets a second attempt naming
what it lost. --keep-all forbids forgetting and protects every backtick
span and bare letter-and-digit token. sync reports the size after every
run; status and doctor fail while the file is over budget. compact
needs a model and rejects --synthesizer deterministic.
Only store versions captured by the preceding sync are archived. A store
created or changed while compaction runs stays live and is folded on the next
sync.
Cron staleness gate:
0 9 * * * agent status || osascript -e 'display notification "agent memory is stale" with title "agent-sync"'Size gate, weekly by cron or daily by launchd on macOS (agent hooks launchd
prints the plist; the run costs a model call only when the file has grown
past its budget):
0 9 * * 1 agent compactCI drift gate (fails the build when instructions drifted):
agent diffClaude Code hook that re-syncs whenever the canon is edited:
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "f=$(jq -r \".tool_input.file_path // empty\"); if [ \"$f\" = \"$HOME/.claude/CLAUDE.md\" ]; then agent sync --synthesizer deterministic; fi"
}]
}]
}
}Shared memory makes cross-agent handoffs coherent; the file-mediated protocol for splitting work between two agents (headless invocation, task directories, mkdir locks, git worktrees) is documented in docs/coordination.md, including a verified Claude Code to Codex round trip.
The same protocol ships as an installable coordinator skill at
skills/coordinate-agents. Install it
with gh skill into whichever agent
should play coordinator:
gh skill install hibeekaey/agent-sync coordinate-agents \
--agent claude-code \
--scope userTo pin a specific version, add --pin vX.Y.Z using any agent-sync release
tag; the skill ships with the CLI and shares its version line. Without gh,
copying skills/coordinate-agents/ into your agent's skills directory works
too.
Beyond memory, agent syncs the rest of your agent setup:
- MCP servers (
agent mcp): register a server once, push it everywhere. Tools with an MCP CLI get it through their own CLI (claude mcp add-json,codex mcp add,gemini/qwenmcp add,amp mcp add); tools with a dedicated MCP file get an agent-sync-owned file (Cursor~/.cursor/mcp.json, Windsurfmcp_config.json, Kirosettings/mcp.json), never touched if you created it yourself. Tools that keep MCP inside shared settings (Zed, OpenCode, Goose, Continue) get a printable snippet instead of risky edits. CLI entries successfully applied by agent-sync are tracked so later updates can validate and roll back, and removal from the registry is propagated on the next sync. Entries first installed before v1.5.2 may require one manual removal. MCP environment values and headers can be secrets: registry files are private, andagent mcp snippetdeliberately prints them for pasting. Every command grammar and file shape was verified against official docs. - Skills (
agent skills sync): additively synchronize~/.claude/skills(orAGENT_SYNC_SKILLS_SOURCE) into every agent's user-scope skills directory, following thegh skillagent registry mapping. Target-only skills remain. Identical copies are adopted, agent-sync-owned copies update atomically, and conflicting unmanaged copies are left untouched with a nonzero exit. - Memory packs (
agent pack): install shareable markdown packs from any GitHub repo, pinned to a commit in a lockfile, folded into the synthesized file on every sync and cleanly removable. - Hooks (
agent hooks): verified snippets that keep memory fresh automatically (Claude CodeSessionEnd, CodexStop, GeminiAfterAgent, an OpenCode plugin under~/.config/opencode/plugin), printed for you to paste, never installed behind your back.
- Hook-based automatic session capture into the canon (beyond re-sync)
- Per-agent content overrides (vary sections per tool)
- Native Windows (PowerShell) port; WSL is supported today (docs/windows.md)
| Item | Note |
|---|---|
| Privacy | Memory files and MCP credentials can contain private context. Keep the synthesized file, gathered output, MCP state and snippets out of public repositories; deterministic synthesis keeps memory out of model calls. |
| Synthesized source | AGENT_SYNC_SOURCE overrides its location. When it lives elsewhere, sync redistributes it to Claude too. |
| Test isolation | AGENT_SYNC_HOME points the tool at a fixture root; make test never touches your real config. |
| Colour | Status output is coloured on a terminal and plain everywhere else, so pipes, cron and CI keep the exact bytes they had. --no-color or NO_COLOR turns it off; --color=always or FORCE_COLOR keeps it through a pipe or a pager. Escapes never reach a file. |
| Walkthrough | Every command with real output: docs/walkthrough.md. |
| Manual | man agent after make install, or agent help. |
| Name clash | Cursor's CLI installer also creates an agent command in ~/.local/bin. If agent version answers with anything but agent vX.Y.Z, another program is first on PATH; agent doctor reports it, and hook and cron snippets then need the full path or a distinct symlink such as agent-sync. |
| Compatibility | Supported platforms, what agent-sync depends on in each tool, versioning and the deprecation policy: docs/compatibility.md. |
Contributions are welcome, especially support for new agents (see the feature request template for what a new target needs). Start with CONTRIBUTING.md; this project follows a Code of Conduct and takes security reports privately per SECURITY.md.
If agent-sync saves you from re-teaching your agents who you are:
- Star the repo. It genuinely helps others find it.
- Share it with someone juggling more than one coding agent.
- Sponsor if it earns a place in your daily loop.
