一个文件我抄了三遍#

我的项目根目录里长期躺着几个长得很像的文件:AGENTS.md、CLAUDE.md,以及一个把前者软链到后者的符号链接。同一份规则,我说了三遍,还要记得在改完一份之后同步另外两份。

这种冗余通常会随着生态演化自然消失:谁的工具用得人多,谁的约定就变成大家的约定。但这次消失的方式有点特别,赢的那个格式不是来自市场占有率最高的玩家,甚至不是由任何委员会投票决定的。它只是被写下来,被几个工具默默读走,然后等了十三个月。

2026 年 9 月的这一周,这件事基本收尾了。9 月 18 日,Claude Code 2.1.277 开始在没有 CLAUDE.md 的目录里读取 AGENTS.md;9 月 24 日,Linux 内核邮件列表出现了一份把 AGENTS.md 引入内核源码树的提案。一份最初属于 Codex 生态的 Markdown 约定,走到了两个完全不同的方向上。

而这两件事连在一起看,比单独看任何一件都有意思。因为它暴露的不是「谁赢了」,而是「赢了之后还剩什么问题」。

十三个月的时间线#

把这条线拉直,节奏其实很慢。

2025 年 8 月,AGENTS.md 作为一个「指导编码 Agent 的开放格式」被提出来,当时在社区里的反响相当大,讨论的焦点是「Agent 到底需要一个专属的指令文件吗」。这个阶段它更像一个倡议,不是事实标准。

之后的几个月,Codex 把它做成了完整的加载体系:仓库根目录的项目文件、各子目录的渐进式文件,以及用户级的 ~/.codex/AGENTS.md 三层结构,从根往下拼接,直到触及配置里的字节上限。同时 Codex 还从项目的 .agents/skills/ 和用户目录的 ~/.agents/skills/ 读取技能。这套设计让这个文件名从「一个建议」变成了「一个真实的加载路径」。

真正的转折发生在 2026 年。8 月 19 日,Anthropic 的仓库里出现了一份要求 Claude Code 支持 AGENTS.md 的功能请求,投票数很高。9 月 18 日,支持落地,版本号 2.1.277,实现方式是通过 /config 里的一个开关,当目录里没有 CLAUDE.md 时改读 AGENTS.md。社区的第一反应很直接:终于可以把那一堆软链接删掉了。

然后 9 月 24 日,内核那边来了。

内核邮件列表里那个很小的实验#

我认为整条时间线上最有价值的信息,不是「又一家采用了」,而是这份内核提案里附带的一个对比实验。

提案人是内核社区的老面孔 Sasha Levin,他此前已经在给内核做 AI 相关工作,包括判断哪些补丁需要回移到稳定分支。这次他想做的,是在内核源码树里放一份 AGENTS.md。内容本身很克制:它只指向内核自己的 README,再从那里引导到关于编码助手的文档。

真正说明问题的是他做测试时观察到的行为。

在没有 AGENTS.md 的情况下,第一个被测的 AI Agent 在生成补丁时加上了一个 Signed-off-by 标签。这个标签在内核流程里代表开发者本人对代码来源和许可的确认,必须由人明确签署,Agent 不能自己加。它同时还用了一个自创的署名标签,而不是内核已经标准化的那个用于标记 AI 协助的 Assisted-by 标签。

第二个被测的 Agent 在没有文件时干脆什么署名都不加。加上 AGENTS.md 之后,两个 Agent 都开始遵守内核规范,第二个还更好地贴合了内核的开发最佳实践。

这个实验小到什么程度?只有两个 Agent,一次前后对比。但它回答了一个很多人一直在猜的问题:这种指令文件到底有没有用。

答案是,有,而且作用点可能和大家想的不一样。它修的不是代码质量,而是流程元数据。

最容易被忽略的一类规则:署名和签署#

上面那个 Signed-off-by 的案例值得单独说。

大部分团队写 AGENTS.md 的时候,脑子里想的是代码规范:用什么框架、几空格缩进、要不要写测试、依赖能不能加。这些都是「代码工件」层面的规则。

而内核案例里被违反的是一条「流程工件」层面的规则。补丁写得好不好不是重点,重点是它附带了不该有的法律含义。这类错误的特征很讨厌:

第一,它不会被编译器、lint 或者测试抓到。CI 全绿,代码也能跑,问题在别的地方。

第二,它不会出现在成功回报里。Agent 不会告诉你「我给这个补丁加了署名」,你只会在某个流程环节被下游质问。

第三,它对时间的敏感性很高。署名、许可、合规声明这类东西一旦进了版本历史,清理成本远高于预防成本。

所以如果让我排一个 AGENTS.md 内容的优先级,我会把「绝对禁止的流程动作」放在「代码风格偏好」前面。禁止自动签名、禁止改测试使其通过、禁止动锁文件、禁止安装新依赖、禁止在没确认前改远程配置,这些条文的价值高于任何一条格式约定。原因是风格问题最多让你多改几行,流程问题可能让你回滚历史。

内核提案里还有一个细节:加上文件之后,两个 Agent 都收敛到了规范行为。这说明这类规则的可执行性其实很高,不需要模型理解你的整个工程文化,只需要它读到一句明确的否定句。

提案后面的反对意见:Token 账单#

内核不是一个会轻易接受新增文件的地方,这份提案也有反对声音。

反对的理由和格式无关,是成本。提案里那份 AGENTS.md 只链接到内核的 README,而内核的 README 会继续指向关于编码助手的文档。也就是说,为了让 Agent 搞清楚规矩,它得先把一大段文档读进上下文。内核社区有人直接指出,这会显著增加 token 消耗,更合理的做法是写一份专门面向 AI Agent 的、更聚焦的文档来压低开销。

这个反对意见其实指向了一个会被长期忽视的张力。

指令文件是「每次会话都要付的成本」。它不像文档,读一次就存在人脑子里;它是每一轮都要重新加载的固定开销。文件越长,能留给真正任务的上下文就越少,单价也越高。一个只做跳转的文件看起来清爽,但如果跳转目标是几千行文档,账单并不会因为文件本身很短而变小。

这也是「把知识放进 AGENTS.md」这个思路需要克制的原因。真正有效的形态可能是反过来:把绝大部分内容留在按需查阅的文档里,让指令文件只做路由和硬约束。它应该像一份目录加一页禁令,而不是一本手册。

Claude Code 的实现:开关、遥测和一个安静的失败#

时间线上另一件事,提供了一个关于「采用」的注脚。

9 月 18 日支持落地之后,9 月 23 日出现了一份很扎实的实地拆解。作者在关掉遥测的 shell 环境里发现,AGENTS.md 根本没有被加载。

他一层层挖到了原因。这个加载器是以一个内置插件形式发布的,名字叫 agents-md。在 2.1.280 的打包代码里,插件的默认开启值是 false,而可用性判断读的是一个远程特性开关,取不到时回退到「不可用」。于是出现了一个奇怪的状态:读取工作目录里的一个本地 Markdown 文件,本身完全不需要网络,但它要等一个服务端开关。

他的验证方法值得记住。他在空目录里放了一份只含一个验证词的 AGENTS.md,然后用非交互方式问模型这个验证词是什么,并要求它不要读文件。在清空两个环境变量之前,答案是「没有」。这两个变量分别是 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 和 DISABLE_TELEMETRY,只要被设置,无论值是什么都会拦住这个功能;把它们设成 0 也没用,因为判断的是「是否存在」。

更值得注意的是失败的姿态:整个过程没有任何警告。会话正常启动,模型正常回答,只是完全不知道项目指令的存在。作者还发现项目级的 .claude/settings.json 里清空这两个变量不起作用,只有会话级参数从第二个会话起生效;使用第三方网关、Bedrock 或 Vertex 的环境也会有同样的问题,因为开关在那里根本解析不到。

最后他自己找的绕法很朴素:CLAUDE.md 支持 @ 路径导入,而这种导入不依赖那个开关,所以在旁边写一行指向 AGENTS.md 的 CLAUDE.md 就能加载。代价是每个仓库多一个文件,而这恰好是支持 AGENTS.md 本来想消除的东西。

我在这件事上最认同的不是结论,而是那个态度:他先接受了一条反直觉的结论(一个本地读取居然依赖遥测),然后用一个可复现的最小实验把因果钉死了,而不是直接发帖抱怨。这种最小验证实验,我觉得应该变成所有 Agent 工作流的常规动作。

格式赢了,语义没有#

现在说我的判断。

AGENTS.md 这个格式能赢,恰恰因为它足够无聊。Markdown,没有 schema,没有校验器,没有厂商前缀,也没有需要注册的命名空间。任何人写下文件名就是「支持」,任何工具读它就能「实现」。对比一下 CLAUDE.md 这种带品牌前缀的方案:它从命名上就注定只能是一家之言,不可能被别家采用。

但无聊的格式换来的是统一的接口,不是统一的语义。这一点在这一周的事件里已经看得很清楚:

  • 发现路径不同。Codex 有用户级的 ~/.codex/AGENTS.md,Claude Code 目前只在项目目录里找,没有对应的用户级文件,/import 能把内容复制进用户级配置,但复制之后不再跟随原文件的后续修改。
  • 可用性不同。一个默认加载,一个默认关闭、还要经过远程开关。
  • 优先级与合并策略不同。三层目录怎么合并、有没有字节上限、冲突时谁覆盖谁,各家都是自己定的。
  • 技能目录不同。Codex 原生读 .agents/skills/,另一边的对应路径目前只在导入命令里被识别。

所以「我们团队统一用 AGENTS.md」这句话,在 2026 年 9 月的含义是:我们统一了文件名。它不等于你在每个工具里得到同样的行为,也不等于你把指令写进去就一定会被加载。

我认为接下来一年真正有价值的工程问题会从「用哪个文件」变成「怎么确认它真的生效」。因为统一接口之后,故障模式变得更隐蔽了:以前加载失败你会立刻发现,因为文件名都不对;现在文件名对了,工具也声称支持了,失败可以是静默的。

顺带说一句,跨工具统一还有一个副作用,就是这份文件的攻击面变大了。一份被多个 Agent 自动读取、内容又往往被赋予高权重信任的文件,本身就是一条提示注入通道,这一点在 8 月底的构建期注入事件里已经被演示过,不再重复展开。这里只想加一句:统一带来的杠杆是双向的,写恶意内容的人和写规则的人用的是同一根杠杆。

一份可执行的落地清单#

把上面的分析压缩成动作,我会这么做:

第一,把 AGENTS.md 当共享入口,不当跨工具契约。 共享的是文件名和内容,行为差异必须逐个工具实测。不要假设「支持了」就等于「按你的预期加载了」。

第二,优先级排序:禁令在前,规范在后。 先写绝对禁止的流程动作(自动署名、自动改测试、自动改依赖、自动改远程配置),再写代码风格。前者出问题的代价高一个量级。

第三,保持短,把它做成路由。 指令文件是每轮都要付的固定成本。让长文档留在按需查阅的地方,文件本身只放硬约束和指向。

第四,加一个自检机制。 在文件里放一个只可能从这里得到的验证词,定期用它问一次模型。上面那份拆解就是这么诊断出问题的。成本几乎为零,能覆盖一整类静默失败。

第五,对特殊环境做显式兜底。 关掉遥测、走第三方网关、用 Bedrock 或 Vertex 的环境,在 CLAUDE.md 里写一行指向 AGENTS.md 的导入。等实现稳定了再删掉这个补丁。

第六,把它当代码管理。 它现在会被多个工具读取,改动的影响面比一年前大得多,版本化、评审、变更记录一样都不能少。

结语#

十三个月,从一份倡议到一个内核提案。这件事最反直觉的地方在于,它没有经过任何一次真正的标准化流程。没有人投票,没有 RFC 编号,没有厂商联盟。它只是因为足够简单、足够中立,于是每个需要它的工具都顺手实现了它。

但收尾的方式也提醒了另一件事:采用一个格式,比实现一个格式的一致性容易得多。 内核那份提案里的 Signed-off-by 案例说明文件确实能改变行为,而 Claude Code 那个被遥测卡住的加载器说明「声称支持」和「真的读到」之间还有一整段距离。

我的结论是,这一轮真正的赢家不是某个文件名,而是「可验证性」这件事本身。当格式之争结束、接口看起来一致之后,区分工程水平的地方就只剩下一个:你能不能证明它真的按你以为的方式工作了。

参考来源#