SKILL 08 / META · DEEP DIVE

AGENTS.md 与跨 Harness 可移植性

一份仓库说明喂给二十个 agent——以及 Claude Code 什么时候读它、什么时候不读

2026-09-09 · BigCat · 2026-10-01 更新

你的仓库里现在躺着 CLAUDE.md、AGENTS.md、.cursor/rules/、.github/copilot-instructions.md。四份文件说的是同一件事,而且已经开始互相矛盾了。

相关 → Skill 06 官方 Authoring 最佳实践精读(skill 是按需加载,本期讲的是每次都进上下文的那一层)
2026-10-01 更新:本期首发时 Claude Code 只读 CLAUDE.md、不读 AGENTS.md,正文曾以此为核心论断。官方自 v2.1.277 起原生读 AGENTS.md(v2.1.281 把这项支持扩到 Bedrock、Vertex AI、Foundry 等会话),下文相关段落已按现行官方文档改写。

// WHY THIS MATTERS

AGENTS.md 是「给 agent 看的 README」:仓库根目录一个纯 Markdown 文件,没有 schema、没有必填字段,各家编码 agent 在干活前把它读进上下文。它现由 Linux Foundation 旗下的 Agentic AI Foundation 托管,规范仓库 agentsmd/agents.md 据 GitHub 仓库页 2026-09 约 2.42 万 star、MIT。

但最该知道的一条有个版本分界:Claude Code 在 v2.1.277 之前只读 CLAUDE.md、不读 AGENTS.md;从 v2.1.277 起,仓库里没有 CLAUDE.md 时它会直接读 AGENTS.md。注意那个条件——工作目录或上级目录里只要有一份 CLAUDE.md(连 CLAUDE.local.md 也算),默认就只读 CLAUDE.md。所以「换个文件名就通用了」仍然只对了一半。本期点名各家真正读哪些文件、给出把它们接起来的具体命令,最后回答那个真问题:仓库级约定里,什么该写、什么不该写。

// 01

它替你干掉什么:干掉四份会打架的仓库说明

论断:多份指令文件的真正成本不是重复劳动,是漂移——你只改了其中一份,另外三份开始教 agent 用你半年前废弃的构建命令。解法是选一份当正本,其余用符号链接或导入指过去。
谁读什么(各家官方文档口径) ────────────────────────────────────────────────────────────── Claude Code CLAUDE.md / .claude/CLAUDE.md / CLAUDE.local.md .claude/rules/*.md AGENTS.md ← v2.1.277+,且仅当没有 CLAUDE.md 时 OpenAI Codex AGENTS.md(git 根 → 当前目录)+ ~/.codex/AGENTS.md GitHub Copilot AGENTS.md(就近生效)· CLAUDE.md · GEMINI.md .github/copilot-instructions.md .github/instructions/**.instructions.md(applyTo 域) Gemini CLI GEMINI.md;context.fileName 可改成 ["AGENTS.md", …] Cursor .cursor/rules/*.mdc · .cursorrules ────────────────────────────────────────────────────────────── 结论:AGENTS.md 是最大公约数,但不是全集。

第一条立刻能跑的用法

# 正本定为 AGENTS.md。Claude Code v2.1.277+ 且仓库里没有 CLAUDE.md:什么都不用做
# 验收:新开会话会出现一行  no CLAUDE.md found; AGENTS.md loaded: <路径>
# 要两份同时生效:/config → Project instructions → claude-md-and-agents-md

# 旧版本、或要追加只给 Claude 的话时,下面两种旧接法照旧可用(内容只会读一次)——
# ① 符号链接(不需要加 Claude 专属内容时最省事,成功时无输出)
ln -s AGENTS.md CLAUDE.md
# Windows 建符号链接要管理员权限,改用下面的 ② 

# ② 导入(还能在下面追加只给 Claude 的话)
# CLAUDE.md 内容:
@AGENTS.md

## Claude Code
改动 src/billing/ 下的代码时用 plan mode。

# 验收:新开一个会话,跑 /context,确认 Memory files 里出现 CLAUDE.md

# Gemini CLI 侧改一个设置就认 AGENTS.md(.gemini/settings.json)
{ "context": { "fileName": ["AGENTS.md", "GEMINI.md"] } }
# 看拼出来到底是什么:/memory show     重新扫盘:/memory reload

# 已经有 Cursor / Copilot 规则、想一次性收编进 Claude Code
/import                # v2.1.213+,连 MCP、命令、subagent、skill 一起搬

/import 和 /init 的区别值得记住:/init 是读旧规则、重新生成一份 CLAUDE.md(默认读 .cursor/rules/、.cursorrules、.github/copilot-instructions.md;设 CLAUDE_CODE_NEW_INIT=1 后还读 AGENTS.md、.devin/rules/、.windsurf/rules/、.clinerules);/import 是一次性追加一份拷贝,并把 MCP server、命令、subagent、skill 一并搬过来。前者做归并,后者做搬家。

失败模式:拷贝比链接更诱人,因为它当场就能跑。但拷贝的那一刻漂移就开始了——三个月后两份文件谁新谁旧没人说得清。/import 官方措辞就是「a one-time copy」,它是迁移工具,不是同步工具。
// 02

机制:它凭什么有效——因为它几乎什么都没规定

论断:AGENTS.md 能被二十家工具接受,恰恰因为它不是协议。没有 schema、没有校验、没有必填字段,接入成本只有「多读一个文件名」。真正有差异的不是格式,是各家的加载语义。

三种加载语义,别混着想

一条容易被忽略的性质

Claude Code 官方明确说:CLAUDE.md 的内容是作为系统提示之后的一条用户消息送进去的,不是配置,也不强制执行。所以「我明明写了却不照做」不是 bug,是这层机制的本性。真要钉死某个动作——比如提交前必须跑 lint——官方给的答案是写成 hook,钩子在固定生命周期点以 shell 命令执行,不取决于模型怎么想。这条对 AGENTS.md 同样成立,而且更甚:跨 harness 时你连对方有没有 hook 机制都不知道。

// 03

真实用法与边界:该写什么、不该写什么

论断:这个问题现在有官方判据了,而且它是个减法。Claude Code 的 /doctor(v2.1.206+)会给已提交的 CLAUDE.md 提瘦身建议,判据一句话:删掉模型能从代码库自己推出来的,留下它推不出来的。

官方瘦身判据(照抄可用)

/doctor 建议删掉 /doctor 建议保留 ────────────────────────────────────────────────────────────── 目录结构树 踩过的坑(pitfalls) 依赖清单 为什么这么做(rationale) 架构综述 与工具默认行为不同的约定 ↑ 这三样模型推不出来 ────────────────────────────────────────────────────────────── 体量硬指标(Claude Code 官方) 目标 < 200 行/文件;超过 4 MiB 直接跳过不读 「更短的文件带来更好的遵循度」——这是官方原话不是玄学

反过来说,判断一条该不该进 AGENTS.md,问三个问题:① 新来的同事需不需要被告知这件事?需要 → 写。② agent 自己 grep 一下就知道吗?知道 → 删。③ 它只在某个子目录成立吗?是 → 挪到路径域规则里去(.claude/rules/ 加 paths:),别占用每次会话的上下文。

三个边界

嵌套不一定按你想的加载。Codex 的目录遍历是「git 根 → 当前目录」,不是「所有子目录」。openai/codex 的 issue #13288(2026-03-02 提出,现已关闭)报的正是这件事:在仓库根启动、改 go/ 下的代码时,go/AGENTS.md 不会被合并进来。Claude Code 的子目录 CLAUDE.md 则是按需加载——读到那个目录里的文件时才进上下文。同一份嵌套布局,在两个 harness 下行为不同。

monorepo 里会被别人的说明污染。Claude Code 给了 claudeMdExcludes(按 glob 匹配绝对路径),写进 .claude/settings.local.json 就只在你这台机器生效:

{ "claudeMdExcludes": ["**/monorepo/CLAUDE.md"] }

私人偏好不要进正本。CLAUDE.local.md(记得进 .gitignore)是给你自己的沙箱地址、测试数据用的。多 worktree 场景下它只存在于创建它的那个 worktree,官方建议改成从家目录导入:@~/.claude/my-project-instructions.md。新坑:在只靠 AGENTS.md 的仓库里加一份 CLAUDE.local.md,默认就会让 Claude Code 不再读 AGENTS.md(它也算「有 CLAUDE.md」);要两份都读,把 Project instructions 设成 claude-md-and-agents-md。

失败模式:两条规则互相矛盾时,官方说法是「Claude 可能任意挑一条」。跨 harness 之后这件事会变糟——AGENTS.md 说用 pnpm,某份没人维护的 .cursorrules 说用 npm,你永远不知道今天生效的是哪条。收编旧规则文件时,删掉源文件比留着更重要。
// 04

代价与替代品:一份文件喂多个 agent,喂的是最小公分母

论断:AGENTS.md 只能承载「每次会话都进上下文的一段纯文本」。MCP server、hooks、subagent、skill、路径域规则——这些真正决定 agent 强弱的东西,它一个都带不走。可移植性是靠放弃能力换来的。

三条路,成本差一个数量级

不装任何东西,你还能怎么办

把正本写成 AGENTS.md,Claude Code(v2.1.277+)、Copilot 和 Codex 天然就读,Gemini CLI 侧改 context.fileName;还在用旧版 Claude Code 就补一条 ln -s。这几步覆盖了绝大多数人的全部需求,成本是零。只有当「每家还要一段自己的话」成为常态时,生成器才开始划算——那时你要维护的不再是一份文件,而是一份模板加 N 份差异。

诚实的代价:AGENTS.md 每次会话都进上下文,它是常驻税,不是按需加载。skill 只在被判定相关时才读进来,规则文件不是。所以每加一段都要问:这段话值不值得在你今年剩下的每一次对话里都出现一遍?大多数「最佳实践」不值得。

// 一页选购卡

先做这三件:① 把正本定成 AGENTS.md。Claude Code v2.1.277+ 且仓库里没有 CLAUDE.md 时无需任何操作,新开会话看到 AGENTS.md loaded 那一行即验收通过;旧版本或已有 CLAUDE.md 的仓库,用 ln -s AGENTS.md CLAUDE.md 或 @AGENTS.md 导入,再用 /memory 确认它在列表里;② 跑 /doctor,按它的判据把目录树、依赖清单、架构综述删干净,只留坑、理由和反默认约定,压到 200 行以内;③ 把只在某个子目录成立的条目挪进 .claude/rules/ 并加 paths: 前置字段,它们不再占用每次会话的上下文。

按场景选工具:只用 1–2 个 agent → 符号链接就够,别装生成器;要给十几家分发且各有差异 → npx @intellectronica/ruler apply(.ruler/AGENTS.md 当正本);手上是一堆 Cursor .mdc、只想转一次格式 → rulesync convert --from cursor --to copilot,claudecode,转完卸载;要把整套 MCP、命令、subagent、skill 一起搬进 Claude Code → /import(v2.1.213+);monorepo 里被别人的说明污染 → claudeMdExcludes。

读数备查:CLAUDE.md 目标 < 200 行 · 超 4 MiB 跳过 · @path 导入最多四跳 · Gemini CLI 用 context.fileName 数组 · Copilot 就近生效、Codex 与 Claude Code 拼接生效 · CLAUDE_CODE_NEW_INIT=1 让 /init 也读 AGENTS.md · Claude Code v2.1.277+ 在没有 CLAUDE.md 时读 AGENTS.md(CLAUDE.local.md 也算有)。

一句话判据:模型 grep 一下就知道的,删;新同事需要被告知的,留;只在一个子目录成立的,挪进路径域规则。

// 术语表

harness(宿主)
跑模型的那层外壳:Claude Code、Codex、Cursor、Copilot 各是一个 harness。同一个模型换 harness,读的文件和权限机制全变。
context file(上下文文件)
会话开始时被读进上下文的指令文件。AGENTS.md、CLAUDE.md、GEMINI.md 都属此类,区别只是文件名和加载语义。
concatenation vs nearest-wins(拼接 vs 就近生效)
多份文件同时命中时的两种处理:全部拼起来(Claude Code、Codex),或只用目录树上最近的那份(Copilot 对 AGENTS.md 的口径)。
path-scoped rule(路径域规则)
只在 agent 碰到匹配文件时才加载的规则。.claude/rules/ 用 paths:,Copilot 用 applyTo。省上下文的主要手段。
drift(漂移)
同一份约定的多个副本随时间各自演化、开始互相矛盾。多指令文件仓库的头号病。
lowest common denominator(最小公分母)
为了让所有 harness 都能读,只能放纯文本,放不下 MCP、hooks、skill。可移植性的定价。

// 延伸阅读