agent-sync

文档

agent-sync 为你共享的每份配置只保留一份副本,并把它放到每个智能体期望的位置。本页是参考手册:Commons(共享配置区)——规范的 ~/.agents/ 目录——里放什么、每个配置族如何到达每个智能体,以及这个工具会碰什么、不会碰什么。

安装

# macOS、Linux 和 Windows 的预编译二进制 — 无需工具链,没有 postinstall 脚本,
# 因此可以离线安装,也可以在沙箱化的 CI 里安装
npm install -g agent-sync-sh

# 或以 PyPI wheel 形式安装同一个二进制 — 不含任何 Python 代码
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 上,从本仓库自带的 Homebrew 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

npm 包只是一个小启动器;真正的二进制按目标平台各打一个包,声明为可选依赖,npm 只会安装与你机器匹配的那一个。在没有预编译二进制的平台上,你会得到一条说明它找过什么、并指向 cargo install 的消息,而不是文件缺失的崩溃。npx 能直接跑通也是同一个设计的结果:没有 postinstall 步骤,除了二进制本身没有任何东西需要下载;而 doctor 只读——它会报告这台机器上装了哪些智能体,不会创建 Commons。

PyPI wheel 里没有任何 Python 代码——每个 wheel 都把同一个编译好的二进制放在 wheel 的 scripts/ 目录里,因此 pip installuvx 会直接把可用的 agent-sync 放到 PATH 上,中间不经过任何解释器包装层。每个平台一个 wheel,pip 解析正确二进制的方式,和 npm 挑选正确的可选依赖是一样的。在没有预编译 wheel 的平台上,安装依然会正常完成,运行时会得到一条指明你的平台并指向 cargo install 的消息,而不是 pip 那句干巴巴的 no matching distribution found——这与 npm 启动器的处理方式一致。

Homebrew tap 就放在 agent-sync 仓库自身,而不是另开一个 homebrew-agent-sync 仓库,因此需要按 URL 添加,不能用简写的 brew tap agent-sync-sh/agent-sync。它安装的正是发布流程附加到 GitHub Release 上的预编译二进制,并对照已发布的 SHA256SUMS.txt 校验;formula 由 CI 在每个标签上重新生成,因此它只可能指向真实存在的产物。Homebrew 6 在你信任之前拒绝加载第三方 tap,这就是那行 brew trust 的用途。

在 Windows 上,创建符号链接需要开发者模式(设置 → 系统 → 开发者选项)或提升权限的 shell;sync 在无法创建链接时会明确说明这一点。

最初五分钟

$ agent-sync init
Created the Commons at ~/.agents
  skills/
  commands/
  agents/

Found 6 agents: claude, codex, opencode, pi, oh-my-pi, gemini

3 skills not in the Commons:
  claude/skills/my-workflow
  claude/skills/review-loop
  pi/agent/skills/notes
  take one with `agent-sync adopt <path>`

4 MCP servers not in the Commons: serena, xapi, node_repl, computer-use
  take them all with `agent-sync mcp adopt --all`

init 回答的是一台用过的机器真正关心的问题:不是 agent-sync 能做什么,而是你现有配置里有哪些可以被接管。把想共享的纳入(adopt)进来,然后 sync。

$ agent-sync adopt ~/.claude/skills/my-workflow
adopted my-workflow from claude into the Commons (skills)

$ agent-sync mcp adopt --all
adopted serena from claude
  scoped to claude — remove the allowlist in agent-sync.toml to share it

$ agent-sync sync

adopt 是一个动词,路径在哪里决定用哪种机制:智能体目录里的真实配置会被移入 Commons,原处留下一条链接;git 仓库里的路径会成为一个 Sourced 条目——Commons 链接出去,真相仍留在仓库里;其余的都复制进来。--dry-run 会在动手之前说出将采用哪种机制。如果 Commons 里已有同名且内容完全相同的条目,它会把重复副本折叠成链接;内容不同则拒绝并说明原因——决定丢弃哪一边不是 agent-sync 该做的事。

Commons

~/.agents/
├── skills/<name>/         每个技能一个目录
├── commands/<name>.md     Claude 方言的 markdown
├── agents/<name>.md       Claude 方言的 markdown
├── AGENTS.md              你共享的指令
├── mcp.json               标准 mcpServers 结构
└── hooks/<Event>.toml     [[hook]] 条目:command、matcher、timeout

Commons 位于 ~/.agents/。里面只放生态标准内容——没有任何 agent-sync 专属的东西,正因如此其他工具才能直接读取它,opencode、oh-my-pi 和 Hermes 已经在这么做。它也正如其名,是一块共享区,不是 agent-sync 的私有领地:其他工具也把自己的文件放在这里,doctor 会点名那些不属于 agent-sync 的条目,并对它们秋毫无犯。工具自身的配置单独放在 $XDG_CONFIG_HOME/agent-sync/(默认 ~/.config/agent-sync/)。

六大配置族

技能、命令、子智能体
符号链接扇出。每个条目在每个智能体目录里有一条规范的相对链接;我们的链接悬空即清理;其他一概不动。原生读取 ~/.agents/skills 的智能体——Codex、opencode、oh-my-pi、Gemini CLI、Cursor——完全不会得到技能链接;如果 Codex 或 Cursor 还在读取旧的扇出目录,sync 会把我们如今重复的链接从中清理掉。
指令
三种机制,因为智能体天生不同。整个文件可以归我们时用普通符号链接(Codex、opencode、pi、oh-my-pi、Gemini CLI、Windsurf)。Claude 的 CLAUDE.md 里有你自己的内容,所以用一行导入行——agent-sync 只确保 @~/.agents/AGENTS.md 存在,只增不改、幂等。Roo 会通配整个目录,所以用规则目录链接
MCP 服务器
渲染成每个智能体的方言并做键级合并。见下文。
钩子
命令钩子在 hooks/<Event>.toml 里声明一次,按命令字符串合并进 Claude、Codex 和 Gemini:agent-sync 只拥有命令与 Commons 钩子匹配的那些数组元素,同一事件数组里其他工具的钩子原样保留。Codex 的信任哈希绝不写入——批准代码执行始终是你的决定。

已被其他工具占有的文件——比如 opencode 的 AGENTS.md 里 claude-mem 的样板内容——是一个冲突(Conflict):报告并指出解法,绝不覆盖。

归属,无需状态文件

agent-sync 写下的一切,都必须在之后的运行中不查任何数据库就能认出是自己的。三种身份覆盖所有机制。

链接身份(Link identity)
解析进 Commons 的符号链接是我们的——会被规范化,悬空时被清理。解析到别处的链接是外来项(Foreign),永远不碰。
名字身份(Name identity)
键级合并进共享文件的条目,名字出现在 Commons 里才是我们的;对钩子而言,命令字符串就是名字。同一文件里陌生的名字都是外来项。有一个后果是刻意保留的:sync 从不删除 MCP 服务器,因为从 Commons 里消失的名字与你手工添加的名字无法区分。删除要用 agent-sync mcp remove
标记身份(Marker identity)
完全生成的文件带有一行注释声明这一点。这正是清理之所以安全的原因:删除带标记的文件,机器回到的是 agent-sync 创建过的状态。同一路径上没有标记的文件出自别人之手。

读懂 status

状态含义
linked指向正确 Commons 条目的规范链接。无事可做。
missingCommons 里有,这个智能体还没有。
stale我们的链接,但不是规范形式——会被重写。
dangling我们的链接,指向的 Commons 条目已不存在。会被清理。
variant有意遮蔽 Commons 条目的真实文件或目录。保留。
variant-identical同上,但与 Commons 副本字节完全相同——一个可以折叠掉的重复副本。
foreign不是我们的。只报告,绝不修改。
conflictagent-sync 本要写入的文件已被另一个工具占有。
退出码:0 干净,1 出错,2 有可执行的事。内容已分叉的变体和外来项都是尘埃落定的状态,不是待办工作,所以都不会让退出码变成 2。

MCP 服务器

一份标准结构的 mcp.json 被渲染成每个智能体的方言:Codex 用带 http_headers 的 TOML 表;opencode 要 local/remote,命令压平成一个数组,env 改名 environment;Gemini 靠使用哪个 URL 键来区分 SSE 和可流式 HTTP;Windsurf 则叫它 serverUrl

# ~/.config/agent-sync/agent-sync.toml
[mcp.serena]
agents = ["claude", "codex"]      # 默认:每个具备能力的智能体

[mcp.node_repl.tweaks.codex]
startup_timeout_sec = 120         # 只作用于 Codex

密钥在 Commons 里写作 ${env:VAR},sync 时从环境变量解析,并从每一行输出中脱敏——Commons 因此始终可以提交进版本库。如果解析后的密钥会落进一个他人可读的文件,agent-sync 会明说。

mcp disable 把服务器停放起来而无需重新输入:定义和它的规则留在 Commons 里,各处的渲染结果被移除,mcp enable 再把它们恢复回来。

agent-sync mcp adopt claude/serena 把已有的服务器反向翻译进 Commons,将智能体专属的旋钮变成微调(Tweak)。它会先验证结果:如果重新渲染无法复现你现有的配置,它会拒绝,而不是报告一个下次 sync 就会推翻的成功。

CLI

命令作用
init创建 Commons,并报告有哪些可以纳入。
adopt <path>把一个路径纳入管理;路径在哪里决定机制——移入、Sourced 或复制。--dry-run 会说出是哪种。
sync把 Commons 扇出到每个已安装的智能体——先完整规划,再落下第一笔写入。--dry-run 打印完整计划。
status什么已同步、什么没有、什么不是我们的。--json
doctor已安装的智能体、Commons 卫生状况、Sourced 条目(缺失的克隆会被标出),以及按名字归属的 .agents 协议面。
revert <agent>移除 agent-sync 放进某个目标的一切——链接、合并的 MCP 和钩子键、渲染的文件。目标未停用前拒绝执行。
mcp listCommons 里的服务器及其在每个智能体中的状态。--json
mcp adopt<agent>/<server>,或 --all
mcp remove把服务器从 Commons 和每个智能体里删除。
mcp enable | disable停放或恢复一个服务器——无论哪种,定义和规则都留在 Commons 里。

agent-sync.toml

可选,位于 $XDG_CONFIG_HOME/agent-sync/(默认 ~/.config/agent-sync/agent-sync.toml)。没有就用默认值。它永远不放进 Commons,Commons 因此只含生态标准内容。锁——agent-sync 唯一的机器本地状态——位于 $XDG_STATE_HOME/agent-sync/(默认 ~/.local/state/agent-sync/)。

[targets]
cursor = false                    # 完全不碰这个智能体

[custom.myagent]                  # 注册表不认识的智能体
root = ".myagent"
skills = ".myagent/skills"

[mcp.heavy-server]
agents = ["codex"]

多台机器

agent-sync 刻意不做跨机器同步——那意味着要自建冲突解决,而这场争论 git 早已赢了。Commons 是一个普通目录,用版本管理就好:

# 作为 git 仓库
cd ~/.agents && git init && git add . && git commit -m "my agent config"

# 或使用 chezmoi
chezmoi add ~/.agents ~/.config/agent-sync

在第二台机器上,克隆下来并运行 agent-sync sync

词汇表

Commons
规范目录 ~/.agents/,保存 agent-sync 同步的一切的唯一真实副本——一块其他工具也居住其中的共享区;agent-sync 是租户,从来不是房东。
目标(Target)
接收扇出的某个智能体的配置面。
扇出(Fan-out)
一个 Commons 条目以符号链接形式落到每个目标里。
原生(Native)
直接读取 Commons、因此不需要扇出的智能体。
变体(Variant)
目标里有意遮蔽 Commons 副本、只对该智能体生效的真实文件或目录。一等公民,永远保留,绝不覆盖。
纳入(Adopt)
用一个动词把路径纳入 agent-sync 的管理;路径在哪里决定机制——移入 Commons 并在原处留下链接、位于 git 仓库时成为 Sourced 条目、其余则复制进来。
Sourced 条目
一个以符号链接指向其来源(Source)的 Commons 条目——来源是一个外部路径,通常在 git 仓库里,持有内容的唯一真实副本。Commons 保管指针,来源保管真相。
退管(Revert)
移除 agent-sync 放进某个目标的一切,是一次深思熟虑的退出动作。目标仍处于启用状态时拒绝执行,这样之后的 sync 不会悄悄重做 revert 撤掉的东西。
外来项(Foreign)
目标里不属于 agent-sync 的链接、文件或服务器条目。永远不碰,由 status 列出。
冲突(Conflict)
占据了 agent-sync 本要写入位置的外来文件——报告并指出解法,绝不覆盖。
渲染(Render)
把 Commons 条目翻译成某个智能体的原生格式,并合并进该智能体的配置文件。
受管(Managed)
名字出现在 Commons 里的条目:agent-sync 在每个目标配置里都拥有它,以 Commons 为准。
停用(Disabled)
Commons 定义里带有 "disabled": true 的受管服务器——有定义但哪里都不渲染,重新启用即可在各处恢复,无需重新输入。
协议面(Protocol surface)
Commons 根部的 .agents 协议路径——tasks/memories/models.jsonsystem-prompt.md——doctor 会按名字归属它们,agent-sync 永远不碰。
微调(Tweak)
合并进单个智能体渲染结果的按智能体附加项,在 agent-sync.toml 中声明,绝不放进 Commons。
标记(Marker)
每个生成文件里的那一行注释,让文件无需状态文件即可被认出是 agent-sync 的。