agent-sync

一个规范的 .agents/ 目录,扇出到你所有的 AI 编程智能体。

位于 ~/.agents/ 这一规范目录的 Commons(共享配置区)保存着你共享的每一份配置的唯一真实副本——技能、指令、MCP 服务器、斜杠命令、子智能体、钩子。agent-sync sync 把它扇出到你安装的每一个智能体,共支持十二个:字节可以完全相同的地方用符号链接,不能相同的地方用渲染后的键级合并。没有状态文件,将来也不会有。

# Commons — 你共享的一切,只有这一份真实副本
~/.agents/
├── skills/          research/  tdd/  code-review/
├── commands/        ship.md  triage.md
├── agents/          reviewer.md
├── AGENTS.md        你的指令,只写一次
├── mcp.json         标准 mcpServers 结构
└── hooks/           SessionStart.toml  PreToolUse.toml

扇出

只改一个文件,每个智能体都能看到。

$ ls -l ~/.claude/skills/
research    -> ../../.agents/skills/research
tdd         -> ../../.agents/skills/tdd
code-review -> ../../.agents/skills/code-review

$ ls -l ~/.pi/agent/skills/
research    -> ../../../.agents/skills/research
tdd         -> ../../../.agents/skills/tdd
code-review -> ../../../.agents/skills/code-review

加进 Commons 的技能,会以相对符号链接的形式出现在 Claude Code、pi、OpenClaw 和 Hermes 里——链接是计算出来的,不是手写的,所以整棵目录树被移动或在别处恢复之后依然有效。

Codex、opencode、oh-my-pi、Gemini CLI 和 Cursor 本来就会自己读取 ~/.agents/skills,所以 agent-sync 完全不为它们写技能链接——如果 Codex 或 Cursor 还在读取旧的扇出目录,sync 会把我们如今重复的链接从中清理掉。我们自己的链接一旦悬空就会被清理;指向别处的链接属于外来项(Foreign),一律不动。

两种机制

能用符号链接就用符号链接,不能用就渲染。

技能、指令、斜杠命令和子智能体在每个智能体那里都可以字节完全相同,所以它们是同一个文件被十处引用——漂移在构造上就不可能发生。MCP 服务器和钩子存在于智能体自己也拥有的文件里,而且格式各不相同,所以采用渲染加键级合并:你的其他键原样保留,只有 Commons 中点名的条目会被改写。

# ~/.agents/mcp.json — 只需写这一次
{
  "mcpServers": {
    "serena": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "serena-agent", "serena"]
    }
  }
}
# ~/.codex/config.toml — 合并,而不是替换
model = "gpt-5.3-codex"        # 原样保留

[mcp_servers.serena]
command = "uvx"
args = ["--from", "serena-agent", "serena"]

[projects."/Users/you/work"]   # 原样保留
trust_level = "trusted"

无状态

文件系统就是状态。

同类工具靠复制、渲染,并在你的配置旁边留一份记录来记住自己拥有什么。一旦记录与磁盘不一致,输掉的是你的手工修改。agent-sync 完全不留记录,因为归属可以直接从磁盘上读出来。

链接身份
解析进 Commons 的符号链接就是我们的:它会被规范化,悬空时会被清理。
名字身份
名字出现在 Commons 里的 MCP 服务器,或命令出现在 Commons 里的钩子,是我们的。同一文件里的其他名字都是外来项(Foreign),原样保留。
标记身份
完全由生成得到的文件带有一行注释声明这一点。有标记的是我们的;没有标记的出自别人之手。

克制

变体是特性,不是冲突。

$ agent-sync status
claude (.claude/skills)  12 linked
  variant           plannotator — left alone
  variant-identical old-notes — identical to the
                    Commons, could be re-linked
  foreign           vendor-thing — not ours

mcp (mcp.json)
  managed           serena → claude
  foreign           xapi → claude — not in the
                    Commons — left alone

2 items need attention — run `agent-sync sync`.

遮蔽 Commons 条目的真实目录是一个变体(Variant):有意为之,永远被保留,只有当内容与 Commons 副本完全相同时才会被标出——去重因此是你主动的决定,而不是一次意外。

凡不是 agent-sync 写下的都是外来项(Foreign)——只报告,绝不修改。退出码就是契约:0 干净,1 出错,2 有事可做。

覆盖范围

十二个智能体,六大配置族。

智能体技能 指令MCP 命令子智能体 钩子
Claude Codefan-outimport-linekey-mergefan-outfan-outkey-merge
Codexnativesymlinkkey-merge (TOML)fan-outnonekey-merge
opencodenativesymlinkkey-mergefan-outfan-outnone
pifan-outsymlinknonenonenonenone
oh-my-pinativesymlinknativenativenonenone
OpenClawfan-outnonenonenonenonenone
Hermesfan-outnonenonenonenonenone
Gemini CLInativesymlinkkey-mergerendernonekey-merge
Cursornativenonekey-mergefan-outnonenone
Windsurfnonesymlinkkey-mergefan-outnonenone
Roononerules-dir linknonefan-outnonenone
Clinenonenonekey-mergenonenonenone
每个智能体支持什么、通过哪种机制。none 表示该智能体没有这类配置面——不是 agent-sync 跳过了它。native 表示该智能体自己读取 Commons,因此不写任何链接——如果 Codex 或 Cursor 还在读取 Commons 旁边旧的扇出目录,sync 会把 agent-sync 如今重复的链接从中清理掉。

安全

还没建立信任,也可以放心运行。

$ agent-sync sync --dry-run
dry run — no changes will be made

claude (.claude/skills)
  missing   research
  missing   tdd
mcp (mcp.json)
  missing   serena → codex — not in this agent's config yet

3 changes would be made.
先规划,后写入
每个配置族都在第一次写入之前完成勘察;Commons 里的任何错误都会报告完整清单并且什么也不写,所以一次配置失误绝不会留下一台半同步的机器。
第二次 sync 是空操作
连续运行两次,第二次会报告 Everything is up to date,文件字节完全相同。
每次写入都是原子的
私有临时文件、fsync、再原子重命名——目标路径先经符号链接解析,所以 dotfiles 的接线不会被破坏。
密钥不进 Commons,也不进终端
${env:VAR} 在 sync 时解析,并从每一行输出中脱敏,Commons 因此始终可以提交进版本库。
它向 CI 汇报
status --jsonmcp list --json,退出码 2 专门表示「有事要做」。

安装

macOS、Linux 与 Windows。

# 预编译二进制 — 无需工具链,没有 postinstall 脚本
npm install -g agent-sync-sh

# 或以 wheel 形式安装同一个二进制
pip install agent-sync-sh

# 或从源码构建,需要 Rust 1.97+
cargo install agent-sync-sh

# 或者先试用,无需安装
npx agent-sync-sh doctor
uvx agent-sync-sh doctor

# 或在 macOS 与 Linux 上,从本仓库自带的 tap 安装
brew tap agent-sync-sh/tap https://github.com/agent-sync-sh/agent-sync
brew trust agent-sync-sh/tap
brew install agent-sync

# 然后,在一台你已经用了一段时间的机器上
agent-sync init

init 先创建 Commons,然后告诉你现有配置里有哪些可以接管——按配置族列出,并附上对应的命令。

边界

它不做什么。

不做跨机器同步。Commons 是一个普通目录——用 git 或 chezmoi 做版本管理。自建同步就意味着自建冲突解决,而这场仗 git 早已赢了。

不做记忆同步。智能体记忆不是一种有明确定义的产物,agent-sync 不会假装它是。

没有 GUI,没有守护进程,没有文件监听,也没有撤销——拒绝发生在写入之前,syncadopt 都可以用 --dry-run 预览。它不负责安装技能——Commons 里有什么就扇出什么,不管是谁放进去的。也没有 mcp add,因为添加服务器不过是编辑一个有文档的标准文件。