写好 CLAUDE.md
如果你打开过一份六个月前写的 CLAUDE.md,然后立刻后悔点开了它,你已经懂这个问题了。这个文件本来应该是项目的长期记忆。AI agent 每次会话开始、碰第一行代码之前,都要先读它。但现实里它很容易漂。规则是在生气时加进去的,之后没人复查。章节慢慢长成 300 行的大墙,没人真的读。一半是愿望,一半已经过期,而 agent 会悄悄忽略其中的差别。
这篇文章讲的是怎样让 CLAUDE.md 真的有用:怎么组织,放什么,不放什么,以及为什么“能写多短就写多短,但仍然写清真实约束”的 CLAUDE.md,永远比那份你一直想抽空清理的长文件更好。
CLAUDE.md 到底是用来做什么的
让我真正想明白这件事的,是 2026 年的一次讨论。Mitchell Hashimoto、OpenAI 和 LangChain 团队最后都落到同一个定义:Agent 是 model 加 harness。model 是 LLM。harness 是包在它外面的所有东西:工具、状态、反馈循环,还有它在会话开始时会读的长期规则。CLAUDE.md 是这个 harness 里承重的一块。AGENTS.md、.cursor/rules、你的 CI 配置、pre-commit hooks、.gitignore 也是。它们做的是同一件事:在 agent 自己摸索之前,先告诉它自己正在什么世界里工作。
这个说法重要,是因为它会改变你优化的目标。你不是在写一份漂亮的宣言。你是在写一个自主程序的启动流程。每一行要么承重,要么就是负担。如果一条规则不够具体,agent 不能在不追问的情况下执行,它就会被忽略。更糟的是,agent 会悄悄发明自己的解释。模糊规则不是“安全默认值”。它们是在默许漂移。
“好”是什么样子
好的 CLAUDE.md 有三个属性,顺序不能反:它是正确的,它能在一次会话里读完,它被周围的 harness 执行。
正确性排第一。如果文件说“use bun”,但你的 CI 用的是 npm,这个文件就是错的。如果文件说“所有改动都走 PR”,但你着急时自己直接 push 到 main,这个文件也是错的。错误规则不是中性的。它们会主动训练 agent 忽略这个文件,因为 agent 会看到规则和项目真实状态冲突,然后学会“CLAUDE.md 不可靠”。让 agent 停止遵守 CLAUDE.md 最快的方法,就是把一条明显坏掉的规则留在里面两周。
可读性是第二个约束,而且很残酷。agent 每次会话开始都会读 CLAUDE.md,阅读成本付在 context window 里。你往 CLAUDE.md 里加的每一行,都在和真实代码、真实 diff、真实问题抢空间。600 行 CLAUDE.md 很奢侈,大多数项目负担不起。如果你愿意删除,150 行 CLAUDE.md 通常就能表达同样的约束。
执行是第三条腿,也是最常被跳过的一条。只存在于 CLAUDE.md 里的规则,是愿望。存在于 CLAUDE.md 里,同时也存在于 Husky pre-commit hook、GitHub Actions check,或者 CI pipeline 里的 linter step 的规则,才是事实。agent 会更愿意遵守那些也被 harness 执行的规则,因为这些规则有牙齿。它很快会学到:带着 console.log push 会让 pre-push check 失败,然后它会调整。只写在 prose 里的规则只是建议。两层都要用。
每份 CLAUDE.md 都需要的章节
我审过大约一百份 CLAUDE.md。真正能用的文件里,总会出现同样五个章节。名字会变,内容不会。
第一是 这个项目是什么。一段话,不要 marketing。这个 codebase 做什么,给谁用,跑在什么 stack 上。agent 之后需要靠它来分辨那些名字很像的文件。
第二是 我们怎么工作。一小组不可谈判的流程规则。branch 策略、commit 约定、PR policy、test 期待。六到十行。agent 在这里学会它能不能直接 push、test 是否必跑、commit 是否要 atomic。
第三是 语言和风格。项目用什么语言,哪些 framework 不能用,命名怎么走。这里也要写沟通语言:你想让 agent 用英文还是中文跟你说话,要短还是要细。选一个,写下来。
第四是 操作备注。环境里那些让人意外的事实。看起来正常但其实是 symlink 的 path。Windows 上会失败的 CI check。每周二过期的 token。这个章节最常救命,因为它记录的是新贡献者本来要靠踩坑才知道的隐性知识。
第五是 原则。你想让 agent 内化的一小组设计规则。不是“write good code”。而是像“不要给不可能发生的情况加 error handling”或“不要手改 lockfiles”这样的具体原则。三到七条,每条最多两句话。如果你有二十条,就等于没有。
常见问题
我最常见到的失败是 模糊。像“follow best practices”或“be careful with errors”这种规则,就是一张许愿便利贴。agent 没法执行。改成具体、可证伪的规则:“每个外部 API call 都加 5 秒 timeout,对 transient errors 重试一次。”现在 agent 知道该怎么做,你也知道怎么检查。
第二是 冲突。两条规则互相打架,通常是隔了几个月才被加进同一个文件。“所有 commit 都走 PR”和“typo 可以直接 push 到 main”不能同时为真;agent 会选一个,忽略另一个。AgentLint 把这类冲突当硬规则来报,因为冲突会训练 agent 把文件当成建议。
第三是 过期引用。文件提到一个已经删掉的 script、一个改名的 service、一个搬走的 directory。每个过期引用都是一个小谎言,agent 得自己发现再绕开。每次改 CLAUDE.md 前跑一次 grep:每个 path、每个 command、每个 URL 都还要能解析。
第四是 没有边界的章节。有人开了一个 “Principles” list,里面五条。六个月后变成三十条。一半互相重复。没有一条被执行。给原则数量设硬上限,把它当永久预算:想加一条,就退休一条旧的。
第五是 语言漂移。文件里混着英文流程、中文 commit messages、复制来的 Slack 讨论。代码和规则选一种语言。沟通可以选另一种,也可以同一种。保持一致。agent 的 parser 不在乎,但人类 reviewer 会在乎,而且这种不一致通常说明没人真正维护这个文件。
一个完整例子
这是我在 workshop 里常用的 before/after。before 来自一个真实项目的真实 CLAUDE.md,只做了轻微匿名:
## How we work
- We try to write good code
- Tests are important
- Use TypeScript when possible
- Don't break things
- All changes should be reviewed
- Commit often
六个 bullet,零条可证伪规则。“Try” 不是承诺。“Important” 不是行为。“When possible” 是给 agent 跳过 TypeScript 的许可。“Don't break things” 没法执行。“Should” 只是建议。
同一个项目,同一个意图,after 是这样:
## How we work
- All TypeScript. No new JavaScript files. Existing JS files migrate when touched.
- Vitest for unit, Playwright for integration. Both must pass before merge.
- Branch from main, open PR, squash-merge. No direct pushes to main.
- One logical change per commit. If you can't summarize the diff in one sentence, split it.
- Pre-push hook runs lint + typecheck + unit tests. Don't disable it.
还是六行。现在 agent 每一条都能执行,你也能写 check 去发现违规。
为什么 harness 需要 linter
我们做 AgentLint 的原因,是再小心的作者也会漂。你周一写了一份好的 CLAUDE.md,周二 ship 一个 feature,周三在一次烦躁会话里加三条规则,到了周五文件里就有了你没注意到的冲突。AgentLint 自带的 33 项 checks,就是我在审计里反复看到的失败模式:模糊规则、冲突、过期引用、没有边界的章节、语言漂移、缺少执行、无法验证的说法。每个 check 都会引用它检查时依据的 primary source,所以 linter 报问题时,你能追到为什么。这个文件不需要完美。它需要的是不要悄悄坏掉,而这件事可以检查。
如果你从零开始写 CLAUDE.md,就写上面五个章节,控制在 200 行以内,然后用 AgentLint 跑一遍。如果你已经有一份漂了的文件,先跑 AgentLint,再修它报的问题。目标不是拿到一份干净报告。目标是确保文件里最贵的那条规则,也就是 agent 每次会话都会读的规则,真的在表达你想表达的东西。