← 返回博客

    “你不需要 CLAUDE.md”——一篇反驳

    有一小群声音很响的人认为 CLAUDE.md 没必要。论点大概是:如果你的代码写得好,agent 自己能看出 conventions。如果你的 tooling 配得好,agent 会从 linter 和 CI 里学到规则。如果项目结构清楚,agent 不需要另一个文件告诉它东西该放哪。在这个观点里,CLAUDE.md 是给组织很差的项目打补丁。正确做法应该是修项目,而不是写一个文件描述它有多坏。

    这是一个真实论点。它也错了。而它错在哪里值得弄明白,因为正确回应不是“你傻,快写 CLAUDE.md”。正确回应是看清 CLAUDE.md 实际做了什么,然后发现这个反驳提出的替代方案并不存在。

    这个反驳说对了什么

    先从真实的部分开始。乱糟糟的 CLAUDE.md 经常是乱糟糟项目的症状。如果你的 CLAUDE.md 需要 60 行解释怎么跑 dev server,那你的 dev server setup 太复杂了。如果你的 CLAUDE.md 有十五条关于 import format 的规则,那你的 linter 没配好。如果你的 CLAUDE.md 描述的是你希望拥有的 layered architecture,那是 fiction,不是 documentation。

    这个反驳正确指出了:很多 CLAUDE.md 内容是在补 tooling 缺口。Lint rules 属于 linter。Test conventions 属于 test runner config。Build commands 属于 package.json scripts。如果你在一个 config file 就能解决的地方写 prose,那 prose 就是错误工具,写更多只是在隐藏问题。

    这个反驳也正确注意到:agents 越来越擅长从 context 里提取 conventions。2024 年的 agent 需要你告诉它所有事;2026 年的 agent 会读 package.json,看 src/ 里的三个文件,然后在你发问前推断出大部分项目 conventions。所以,CLAUDE.md 作为“convention documentation”的边际价值确实比以前低。

    这个反驳错在哪里

    但这个反驳把 CLAUDE.md 压扁成了“convention documentation”,而这只是这个文件做的三件事之一。它还编码 项目明确做过、但代码里看不出来的决定,并提供 一个稳定的启动流程,让 agent 在碰代码前的会话开始就读到。这两件事都不能被好代码或好 tooling 取代。

    代码里看不出来的决定,才是承重案例。规则 “we tried Redux, then Zustand, then settled on Jotai — do not propose moving to Valtio” 不在代码里。代码只显示 Jotai 正在被用。agent 读代码会知道 Jotai 在用。agent 读 CLAUDE.md 会知道 Jotai 是刻意选择,并且不要再提迁移 state library。没有这条规则,agent 总有一天会看着项目,觉得 Valtio 更 idiomatic,然后认真写一个迁移提案。你并不想要这个迁移。这个提案仍然花掉你一个会话。

    类似的还有:“这个 codebase 看起来像 microservices project,但它刻意是 monolith,不要建议拆分。” 或者:“我们用 LaunchDarkly 的 feature flags,不用 Statsig。旧代码里两者都有,只有 LaunchDarkly 路径是当前的。” 或者:“每次 database write 都必须有 audit log,不要为了优化删掉它。” 这些都不能从代码里推出来。它们都能帮你省下 agent 自信提出错误建议的会话。

    会话启动这个案例更难替代。agent 开始新会话时,对你的项目没有任何 context。它当然可以读文件,但为了弄清 conventions 去读每个文件,会消耗你本来想花在真实任务上的 context budget。CLAUDE.md 是便宜的 pre-commit briefing。用“让 agent 自己弄明白”取代 CLAUDE.md,意味着每个会话都要重新付一次弄明白的成本,而且这个过程发生在你的 context window 里。

    “但 agent 可以读 linter” 这句话

    常见反驳是:linter 编码了 conventions,所以 agent 可以读 linter config,不用读 CLAUDE.md。有时可以。很多时候不行。

    Linter configs 只能编码适合 linter ergonomics 的一部分 conventions。linter 可以执行 “TypeScript 里 no any”。linter 不能执行 “如果你想用 any,先提一个 discriminated union,再考虑 cast。” 前者是规则;后者是规则背后的 reasoning。agents 两者都需要:要遵守的规则,以及遇到 edge case 时怎么应用的 reasoning。

    Linter configs 对冷读的 agent 来说,signal-to-noise ratio 也很差。典型 eslint config 有几百行 plugin extensions、rule overrides、ignore patterns。agent 得 parse 整个文件,才能找到当前任务相关的三条规则。CLAUDE.md 里一句 “TypeScript strict, no any, no implicit JSX returns” 大概要快十倍。

    linters 覆盖面也很窄。流程规则(PR policy、commit conventions、testing requirements)不在 linter 里。操作备注(这个 path 是 symlink,这个 CI step 周二会 flaky)不在 linter 里。原则(不要给不可能发生的情况加 error handling)不在 linter 里。“linter config 就够了” 这个说法只在你项目规则刚好都能干净塞进 linter format 时成立,而大多数项目不是这样。

    “但我的项目很小” 这句话

    另一个版本的反驳是:“我的项目小到 agent 不用帮忙也能看懂。” 这是一个真实 edge case。对一个 200 个文件、三个贡献者的 repo 来说,CLAUDE.md 的边际价值确实低。但注意条件:小、近、单语言、单 stack、单团队。大多数项目第一年内至少会打破其中两个条件。一旦打破,agent “从 context 自己弄明白”的方式就会开始以细微、难 debug 的方式失败。

    正确 policy 不是“先不写 CLAUDE.md,等后悔了再说”。而是“从第一天开始写一份 50 行 CLAUDE.md,然后随着模式出现再长”。50 行文件几乎没有维护成本,并且会在第一个新人加入项目,或者 agent 第一次需要做代码看不出来的决定时回本。

    CLAUDE.md 怀疑者至少也该做什么

    如果你确信 CLAUDE.md 没必要,至少也该 ship 这个最小版本:一段话说明项目,三到五条硬规则(禁止直接 push、lockfile edit policy、test requirement),以及一个 section 列出团队明确做过但代码里看不出来的决定。也就 30 行。它不是零,和完全没有文件有实质区别。

    哪怕只有 30 行,它也给未来明确决策一个落点。第一次有人说“我们已经决定不用 feature X,让 agent 知道”,你有一个文件可以加规则。没有这个文件,决定就住在某个人脑子里,直到六个月后 agent 提出 feature X,然后让所有人意外。

    诚实评估

    做坏的 CLAUDE.md 比没有 CLAUDE.md 更糟。一个臃肿、冲突、过期的文件,会主动训练 agent 忽略它。这个反驳正确观察到:真实世界里很多 CLAUDE.md 糟到净负收益。正确回应不是删掉文件,而是把文件做好。短、正确、可机器检查、承重。

    好的 CLAUDE.md 不是给组织差的项目打补丁。它是组织良好的项目的显式记忆,放在 agent 最先读取的位置。替代方案是让这些记忆只存在团队集体脑子里,在那里它们比代码漂得更快,而且对每个中途加入项目的 agent 都不可见。那是更差的位置,而这个反驳无意中支持的正是那个位置。

    写这个文件。保持短。用 AgentLint 跑它,让它保持正确。实际工作里,“你不需要它” 这个论点,等于在说你不需要显式的组织记忆。而试图在没有显式记忆的情况下工作的项目,最后总会付钱。

    相关文章