agentstow

文档

agentstow 为你共享的每份配置只保留一份副本,并把它放到每个智能体期望的位置。本页是参考手册:Store 里放什么、每个配置族如何到达每个智能体,以及这个工具会碰什么、不会碰什么。

安装

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

# 或从源码构建 — 需要 Rust 1.97 或更新版本
cargo install agentstow

npm 包只是一个小启动器;真正的二进制按目标平台各打一个包,声明为可选依赖,npm 只会安装与你机器匹配的那一个。在没有预编译二进制的平台上,你会得到一条说明它找过什么、并指向 cargo install 的消息,而不是文件缺失的崩溃。

不支持 Windows。v1 只支持 macOS 和 Linux。让漂移不可能发生的符号链接扇出,前提是创建符号链接不需要特权。

最初五分钟

$ agentstow init
Created the Store at ~/.agents
  skills/
  commands/
  subagents/

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

3 skills not in the Store:
  claude/skills/my-workflow
  claude/skills/review-loop
  codex/skills/notes
  take one with `agentstow adopt <path>`

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

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

$ agentstow adopt ~/.claude/skills/my-workflow
adopted my-workflow from claude into the Store (skills)

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

$ agentstow sync

adopt 把真实文件移进 Store,在原处留下一条链接。如果 Store 里已有同名且内容完全相同的条目,它会把重复副本折叠成链接;内容不同则拒绝并说明原因——决定丢弃哪一边不是 agentstow 该做的事。

Store

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

Store 固定在 ~/.agents/。里面只放生态标准内容——没有任何 agentstow 专属的东西,正因如此其他工具才能直接读取它,opencode 和 oh-my-pi 已经在这么做。工具自身的配置单独放在 ~/.agentstow/agentstow.toml

六大配置族

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

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

归属,无需状态文件

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

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

读懂 status

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

MCP 服务器

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

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

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

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

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

CLI

命令作用
init创建 Store 骨架,并报告有哪些可以纳入。
sync把 Store 扇出到每个已安装的智能体。--dry-run 预览。
status什么已同步、什么没有、什么不是我们的。--json
adopt <path>把现有配置吸收进 Store,留下一条链接。
doctor已安装的智能体、Store 可用性、卫生警告。
mcp listStore 里的服务器及其在每个智能体中的状态。--json
mcp adopt<agent>/<server>,或 --all
mcp remove把服务器从 Store 和每个智能体里删除。

agentstow.toml

可选,位于 ~/.agentstow/agentstow.toml。没有就用默认值。它永远不放进 Store,Store 因此只含生态标准内容。

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

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

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

多台机器

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

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

# 或使用 chezmoi
chezmoi add ~/.agents ~/.agentstow

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

词汇表

Store
规范目录 ~/.agents/,保存 agentstow 同步的一切的唯一真实副本。
目标(Target)
接收扇出的某个智能体的配置面。
扇出(Fan-out)
一个 Store 条目以符号链接形式落到每个目标里。
原生(Native)
直接读取 Store、因此不需要扇出的智能体。
变体(Variant)
目标里有意遮蔽 Store 副本、只对该智能体生效的真实文件或目录。一等公民,永远保留,绝不覆盖。
纳入(Adopt)
把目标里已有的真实文件或目录吸收进 Store,在原处留下链接。
外来项(Foreign)
目标里不属于 agentstow 的链接、文件或服务器条目。永远不碰,由 status 列出。
冲突(Conflict)
占据了 agentstow 本要写入位置的外来文件——报告并指出解法,绝不覆盖。
渲染(Render)
把 Store 条目翻译成某个智能体的原生格式,并合并进该智能体的配置文件。
受管(Managed)
名字出现在 Store 里的条目:agentstow 在每个目标配置里都拥有它,以 Store 为准。
微调(Tweak)
合并进单个智能体渲染结果的按智能体附加项,在 agentstow.toml 中声明,绝不放进 Store。
标记(Marker)
每个生成文件里的那一行注释,让文件无需状态文件即可被认出是 agentstow 的。