博客

从一个文件生成,规则照样会走样

2026年8月11日untactit

“我们的智能体指令文件老是对不上”,理所当然的解法是别再维护副本。写好 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:

  • agent-fanout —— AGENTS.md 只写一次,其余的生成出来
  • agent-drift —— 找出那些已经对不上的副本

这条路通向哪里

诚实的终点是这两个脚本都不必要,因为资产根本不再是躺在一台台笔记本上的文件 —— 它们放在一个评审过的地方,不需要任何人复制就到达每一台机器。这就是我在 untactit 做的事,目前尚未公开发布。

这两个脚本自己就站得住,不依赖它。用得上的就用,其余的不必理会。

本文也发在 DEV。

相关文章

别再猜智能体在跑什么。

接入一个工作区,约十分钟内,团队在用的每个技能、规则与记忆一览无余。

免费开始 联系我们

无需信用卡。直接接入现有工具。