CLAUDE.md 你只写过一次。半年后笔记本上有十八份,而你说不出哪一份才是对的。
这不是假设。我扫了自己的机器,结果正是如此。下面讲的是它为什么会发生,以及那个看上去理所当然的解法为什么解不掉。
每个智能体都从它自己认定的路径读指令。
| 工具 | 路径 |
|---|---|
| Claude Code | CLAUDE.md、~/.claude/CLAUDE.md |
| Cursor | .cursor/rules/*.mdc |
| GitHub Copilot | .github/copilot-instructions.md |
| Codex / 其他 | AGENTS.md |
你没有决定要留四份副本。你决定的是用四个工具。副本是跟着工具一起来的。
有三种机制在制造它,没有一种需要谁马虎。
在用的地方就地改。 智能体在任务中间跑偏了。你顺手改掉眼前打开的那个指令文件。那个文件只是四份中的一份,改动也只落在那一份里。
检出目录不是单位。 同一个仓库你克隆了两份 —— 一份跟主分支,一份跟长期分支。两份都带着指令文件。只要有一边被碰过,它们当场就分家了。
主目录里的规则是看不见的。 ~/.claude/CLAUDE.md 不属于任何仓库。它不进任何 CI。那些你不想在评审里争论的规则,最后都落在这里。
顺理成章的反应是别再留副本:只写一次 AGENTS.md,其余的都生成出来。
这个我做了。它能用。就是 agent-fanout —— 单文件 Python,零依赖,MIT。
python3 agent_fanout.py
create CLAUDE.md
create .cursor/rules/from-agents-md.mdc
create .github/copilot-instructions.md
生成出来的文件都带一行头注,免得有人直接去改,CI 里加上 --check,谁手改了衍生文件,构建就变红。
这覆盖的是这个仓库,而且是在跑 CI 的地方。 听起来像是全都覆盖了,直到你把漏在外面的部分列出来:
预防是制度。检测是测量。制度会以你看不见的方式被绕过去,除非你去测。
agent-drift 扫的是路径而不是仓库,分组依据是内容相似度而不是文件名:
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,这本来就是对的,把这个报成漂移的工具没人会再用第二次。把它指向你整个工作目录,而不是某一个项目 —— 有价值的结果都是跨仓库的那些。
| 范围 | 它回答的问题 | |
|---|---|---|
| agent-fanout | 单个仓库 | 衍生文件是不是最新的 |
| agent-drift | 整台机器,多条路径 | 副本是在哪里分的家 |
生成消掉的是副本存在的理由。检测抓的是那些因为你没预料到的理由而存在的副本。只做一件,你会觉得自己盖住了,这比知道自己没盖住更糟。我自己就掉进去过。
老实说,终点是这两个脚本都不再需要 —— 资产不再以文件的形式散落在一台台机器上,一份评审过的内容自己到达每一台机器。这就是我在 untactit 做的事,目前尚未公开发布。
这两个脚本不依赖它。哪一部分有用就拿哪一部分。