Skip to content

About

Synchronize your AI coding agents' memory so you can stop in one agent and pick up in another

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Repository files navigation

agent-sync

agent-sync: one memory, every agent

One memory, every agent. Synchronize your AI coding agents' memory, so you can stop in one agent and pick up in another.

CI Release License: MIT POSIX sh Platforms Last commit Stars

Claude Code Codex Gemini CLI Cursor Copilot CLI Zed Goose Amp OpenCode Windsurf +7 more

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:

  1. Gather: read every agent's own memory stores.
  2. 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.
  3. 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.

Install

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 sh

With 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-sync

From a clone (installs the man page and completions too):

make install                 # /usr/local (may need sudo)
make install PREFIX=~/.local # per-user, no sudo

POSIX 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.

Supported agents

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).

Semantic synthesis

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 sync

CLI 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.

Keeping the file small

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.

Automating

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 compact

CI drift gate (fails the build when instructions drifted):

agent diff

Claude 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"
      }]
    }]
  }
}

Coordinating agents on one task

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 user

To 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.

MCP, skills, packs and hooks

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/qwen mcp add, amp mcp add); tools with a dedicated MCP file get an agent-sync-owned file (Cursor ~/.cursor/mcp.json, Windsurf mcp_config.json, Kiro settings/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, and agent mcp snippet deliberately prints them for pasting. Every command grammar and file shape was verified against official docs.
  • Skills (agent skills sync): additively synchronize ~/.claude/skills (or AGENT_SYNC_SKILLS_SOURCE) into every agent's user-scope skills directory, following the gh skill agent 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 Code SessionEnd, Codex Stop, Gemini AfterAgent, an OpenCode plugin under ~/.config/opencode/plugin), printed for you to paste, never installed behind your back.

Roadmap

  • 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)

Notes

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.

Contributing

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.

Support the project

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.

License

MIT

About

Synchronize your AI coding agents' memory so you can stop in one agent and pick up in another

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages