← 返回博客

    AGENTS.md 作为 single source of truth

    agent-fragmentation 问题是一开始慢慢出现,然后突然爆发的。团队先用 Claude Code,写了 CLAUDE.md。有人加 Cursor,写了 .cursor/rules。Codex 进来后拿到 AGENTS.md。GitHub Copilot 又有 .github/copilot-instructions.md。几个月后,repo 里有五个 rule files,其中三个对 tests 写法不一样,没人知道哪个才是 authoritative。

    这不是 documentation 问题。它是 harness 问题。

    当两个 agents 对同一个 repo 读到不同规则时,你就不再有一个 engineering process。你有的是每个 tool 一套 process。一个 agent 以为可以直接改 lockfiles。另一个以为 lockfiles 是 package-manager-owned。一个 agent 用 pnpm test。另一个用 npm test。一个 agent 开 PR。另一个直接 push 到 main,因为那条规则只存在它从来没读过的文件里。

    把 AGENTS.md 当 single source of truth 的理由很简单:cross-agent project rules 应该放在一个 canonical file 里,tool-specific files 要么指向它,要么声明自己的偏差。目标不是崇拜某个 filename。目标是阻止 repo 变成 rule fork。

    为什么 AGENTS.md 是合适候选

    AGENTS.md 有两个实际优势。

    第一,名字是 tool-neutral。CLAUDE.md 对 Claude Code 很好,但作为 Codex、Cursor、Copilot 或下一个 tool 的 canonical file,这个名字会有点别扭。AGENTS.md 说清楚这个文件是给谁的:agents。在 multi-tool codebase 里这很重要,因为 contributor 不应该先知道是哪家 vendor 流行了这个 rule file,才知道项目规则在哪里。

    第二,Codex 把 AGENTS.md 当 first-class project instructions。当前 OpenAI docs 描述了 global 和 project discovery、nested overrides、fallback filenames、byte limits。这给 AGENTS.md 带来了具体 harness behavior,而不只是约定。它会在做事前被读。它参与 scope 和 precedence。它可以分层。

    这不表示每个 tool 今天都完美读取 AGENTS.md。意思是 AGENTS.md 是一个很强的 canonical document,可以从它适配到别的 tool。如果某个 tool 需要另一个文件,就生成或 pointer 到那个文件。content source 留在一个地方。

    文件名背后的共识

    更大的 agent-harness 讨论正在从不同方向收敛到同一个形状。

    Mitchell Hashimoto 的 harness-engineering 框架很操作化:agent 出错时,改善环境,让同样错误下次更不容易发生。这个环境包括 instructions、tools、checks、feedback loops。

    OpenAI 关于 Codex harness 的写法把 repository knowledge 讲得很直接:给 agent 一张 map,不要给一千页 manual。把 durable knowledge 放在 repo 里。instruction layer 要短到真的有用。

    LangChain 最近关于 harness 和 memory 的写法从 agent-framework 角度推同一个点:agent 不只是 model;它是 model 外面的系统,memory/instructions 是这个系统的一部分。如果 AGENTS.md 和 CLAUDE.md 会被不同 harness 加进 context,它们就是 memory surfaces。碎片化 memory 会产生碎片化 behavior。

    共同教训不是“写更多规则”。而是“设计承载规则的系统”。single source of truth 是一个系统决定。

    要集中管理什么

    集中管理描述项目的规则,而不是描述 tool 的规则。

    Package manager:

    - Use npm only. package-lock.json is canonical.
    - Do not add pnpm-lock.yaml, yarn.lock, or bun.lock.
    

    Validation:

    - Before opening a PR, run npm run lint and npm run build.
    - If a test cannot run locally, say which command failed and include the error.
    

    Repo process:

    - Branch from main and open a PR. No direct pushes to main.
    - One logical change per commit. Do not mix content, code, and dependency churn.
    

    Architecture:

    - Route metadata lives in src/lib/seo.ts and scripts/generate-sitemap.ts.
    - Do not introduce a second routing source of truth.
    - Generated dist/ files are build output and are never edited by hand.
    

    Security:

    - Never print secret values. Refer to secrets by environment variable name only.
    - Do not add .env files to git.
    

    这些规则对 Codex、Claude Code、Cursor 和 human reviewer 都应该是同一件事。如果它们住在五个地方,就会漂。如果它们只住一次,adapters 指向它,drift surface 就会小很多。

    什么留在每个 tool 自己那里

    不要集中管理只有一个 tool 看得懂的 harness mechanics。

    Claude Code hooks 和 skills 应该靠近 Claude Code:

    .claude/settings.json
    .claude/skills/
    

    Codex-specific discovery details 属于 Codex-facing notes:

    - Codex reads AGENTS.md from global and project scopes.
    - Nested AGENTS.override.md files may narrow local rules.
    - If instructions look stale, restart the Codex session.
    

    Cursor rule globs 属于 Cursor 的 rule files。Copilot-specific prompt behavior 属于 Copilot 的 instruction file。single source of truth 不代表所有 tool-specific behavior 都被压平进 AGENTS.md。它代表 project rules 是 canonical,adapter 只承载 tool-specific edge。

    这个边界很重要。一个试图解释每个 harness 的臃肿 AGENTS.md,会变成 OpenAI 警告过的那种 unreadable manual。让 AGENTS.md 做 cross-agent map。把 rich procedures 放进 tool-specific skills、hooks 或 docs。

    迁移方式

    先做 inventory。列出 repo 里每个 agent instruction file:

    AGENTS.md
    CLAUDE.md
    .cursor/rules/*
    .github/copilot-instructions.md
    .claude/skills/*
    

    然后把每条规则分成三类。

    Project rule:不管哪个 agent 工作都适用。移到 AGENTS.md。

    Tool rule:只对一个 harness 有意义。留在对应 tool file。

    Reference material:对 always-loaded instructions 来说太长。移到 docs/,再从 AGENTS.md 链过去。

    分类这一步,通常就是团队发现混乱的时候。一个 40 行的 “Claude rules” section,常常有 30 行 project rules、5 行 Claude Code mechanics、5 行过期偏好。拆开它。不要因为坏结构已经存在,就继续保留。

    接着,把 AGENTS.md 重写成 canonical project map。保持短。包括 project facts、commands、working rules、architecture boundaries、references。不要复制旧文件里的所有解释。

    然后把 tool files 变成 adapters。薄 CLAUDE.md 可以这样写:

    # CLAUDE.md
    
    AGENTS.md is the canonical project instruction file.
    Read it before making changes.
    
    Claude Code-specific behavior:
    - Hooks live in .claude/settings.json.
    - Workflow-specific procedures live in .claude/skills/.
    

    .github/copilot-instructions.md 可以用 Copilot 更喜欢的形状写同样的事。Cursor rules 可以指向 AGENTS.md,并只在需要时添加 Cursor-only globs。

    最后,加一条 review rule:任何 cross-agent project behavior 的改动,都必须先改 AGENTS.md。Adapter files 只在 tool-specific behavior 改变时才改。

    什么时候 single source of truth 不适合

    确实有例外。

    受监管团队可能需要为不同 tools 保留分开 approved 的 instruction files,因为每个 tool 的 risk controls 不一样。这种情况下,source of truth 可能是 policy document 或 generator,不是 AGENTS.md。

    一个 subprojects 差异很大的 monorepo,可能需要 nested AGENTS.md files。root file 应该是 map;local files 应该为 apps/webservices/paymentspackages/sdk 收窄规则。这仍然是在每个 scope 内用 single-source thinking,而不是一个巨大 root manual。

    一个正在从 Claude Code 迁移中的团队,可能暂时让 CLAUDE.md canonical,并生成 AGENTS.md。如果迁移是显式的,而且 generated file 写着 “do not edit by hand”,这也可以。

    标准不是纯洁度。标准是每条规则有没有一个 owner。如果没人能回答“我要为所有 agents 改 test command,应该改哪里?”,系统就坏了。

    收益

    收益是最好的那种无聊。更少互相矛盾的 edits。更快的 agent onboarding。不同 tools 间更少奇怪 behavior。review 更容易。instruction files 更短。更多规则被真实 enforcement 兜住。当 agent 做错事时,你知道应该 patch instruction layer 的哪里。

    AGENTS.md as single source of truth 不是魔法约定。它是一种维护策略,适合每个 repo 都会被不止一个 agent 触碰的世界。AgentLint 在这个世界里有用,因为它会在 drift 变成 behavior 之前,检查 source-of-truth file 和旁边的 harness files。

    相关文章