“我们的智能体指令文件老是对不上”,理所当然的解法是别再维护副本。写好 AGENTS.md,从它生成 CLAUDE.md、.cursor/rules/*.mdc 和 .github/copilot-instructions.md,收工。
这个我做了。它能用。它同时也没解决问题,而这两句话之间的落差值得摊开讲清楚,因为我也是在真机上跑过之后才看见的。
python3 agent_fanout.py
create CLAUDE.md
create .cursor/rules/from-agents-md.mdc
create .github/copilot-instructions.md
一个源头,若干衍生文件,每一份顶上带一行头注,免得有人顺手就改了衍生副本:
<!-- Generated from AGENTS.md by agent-fanout. Do not edit this file. -->
把它加进 CI,直接改 CLAUDE.md 的那个合并请求就会让构建变红:
- run: python3 agent_fanout.py . --check
这覆盖的是这个仓库,而且是在跑 CI 的那些机器上。听起来像是全都覆盖了,直到你把它没覆盖的部分列出来。
别的仓库。 你的团队不止一个仓库。每个仓库都有自己的 AGENTS.md,而它们某个时刻是从彼此复制粘贴来的。生成让每个仓库内部保持一致,仓库与仓库之间照样分家。
全局配置。 Claude Code 除了项目文件还会读 ~/.claude/CLAUDE.md。Cursor 有用户级规则。这些都在所有仓库之外,永远不进 CI,而它们恰恰是大家安放“不想在评审里争论的那条规则”的地方。
两次生成之间的窗口。 生成只在有人跑它的时候发生。从那一刻到下一次 CI 之间,衍生文件可以被改、被用。智能体立刻就读到了;CI 要等推送才发现,前提是有人推送。
没有 CI 的仓库。 原型、随手克隆的副本、上周二谁建的那个仓库。指令在这些地方被改得最随意,而它们一道关卡都没有。
是机器,不是仓库。 跑智能体的单位是一台笔记本。一台笔记本上有许多检出目录、同一个仓库的好几份副本,还有一个主目录。任何按仓库运作的东西都看不到这一层。
预防是制度。检测是测量。制度会以你看不见的方式被绕过去,除非你去测。
python3 agent_drift.py ~/work ~/side-projects
Scanned 47 instruction files.
DRIFT: 2 documents, 5 distinct versions between them.
claude-code:CLAUDE.md
6 copies, 3 versions
9b01aeaa204d 3 files, 406 lines
2dc3c616c279 2 files, 411 lines
这个扫的是路径而不是仓库,分组依据是内容相似度而不是文件名 —— 两个互不相干的项目有不一样的 CLAUDE.md,那不是漂移,把它报成漂移会让整份输出变成废纸。(把这套分组做对花了三次重写,同一个 CLAUDE.md,在一台笔记本上有 18 个版本。)
拿整个工作目录去跑,不要只跑一个项目。有价值的结果都是跨仓库的那些。
| 范围 | 回答 | |
|---|---|---|
agent-fanout | 单个仓库 | “衍生文件是不是最新的?” |
agent-drift | 整台机器,多条路径 | “副本到底是在哪里分的家?” |
生成消掉的是副本存在的*理由*。检测抓的是那些因为你没预料到的理由而存在的副本。两者都不多余,只做前一件会给你一种覆盖到了的错觉 —— 这才是我真正想提醒的失效模式,因为我自己就掉进去过。
两个都是单文件 Python,无依赖,该只读的地方只读,MIT:
AGENTS.md 只写一次,其余的生成出来诚实的终点是这两个脚本都不必要,因为资产根本不再是躺在一台台笔记本上的文件 —— 它们放在一个评审过的地方,不需要任何人复制就到达每一台机器。这就是我在 untactit 做的事,目前尚未公开发布。
这两个脚本自己就站得住,不依赖它。用得上的就用,其余的不必理会。