← 返回博客

    创建一份完美的 CLAUDE.md

    “完美 CLAUDE.md” 这个说法本身就是陷阱。没有一份柏拉图式的 CLAUDE.md 飘在你的项目上方,等你抄下来。只有一份适合你的 codebase、团队、tooling,以及你对流程繁琐度容忍度的 CLAUDE.md。唯一有用的“完美”定义,是 agent 每次会话开始读一遍,然后表现得像你状态好时亲手做一样。这篇讲的就是怎么写出那份文件:从空白的 touch CLAUDE.md 开始,到一份真正承重的文件结束。

    为什么空白文件通常赢

    当人们问“我的 CLAUDE.md 里该放什么”时,手边通常已经有一份 400 行草稿,然后想知道还要加什么。这是错误起点。我见过的草稿通常有两种膨胀方式:从别人的 CLAUDE.md 抄行,但不检查是否适用;或者每次团队被某件事惹烦,就加一条规则,从不修剪。一年后,这个文件一半是考古,一半是愿望。

    从空白文件开始,会强迫你问另一个问题。不是“什么可以放进去”,而是“没有什么,项目会真的坏掉?” 这个过滤器第一轮就能砍掉 70%。剩下的 30%,通常比任何靠不断添加写出来的草稿都更接近真实 CLAUDE.md。

    “完美”在操作上是什么意思

    实践里,完美的 CLAUDE.md 有三个可衡量属性。它 一遍能读完,大概 80 到 250 行,取决于项目大小,并且没有一个 section 超过 50 行。它 完全可以被机器检查,每条规则都有一个 CI 里跑的 check、一个本地 hook,或者一个 agent 可以按需运行的 verifier。它 承重,也就是每条规则如果被删掉,agent 的行为会在一周内出现你能注意到的变化。

    最后一条最严格。如果你删掉一条规则,两周什么都没变,那条规则可能从来没起作用。要么这个行为本来就在发生(规则重复),要么 agent 本来就在忽略它(规则只是建议)。两种情况都说明该删。

    七步构建法

    这是我给新项目 bootstrapping CLAUDE.md 时用的顺序。小 repo 大概一个下午,复杂 repo 两天。

    第一步:写项目介绍段落。 一段话,100 词以内。这个项目做什么,谁用它,跑什么 stack。不要 marketing。agent 用它来分辨名字很像的 repo。

    第二步:列出不可谈判项。 agent 绝对不能做什么:没 PR 就 push 到 main、手改 lockfiles、commit secrets、修改已经 apply 的 migrations。六到十条。每条都是可证伪、可机器检查的指令。

    第三步:写清语言和风格决定。 项目用哪些语言,哪些 framework 被允许,哪些不能用,命名约定是什么。要具体。“Use TypeScript” 太模糊,要写 “TypeScript with strict mode, no any, no implicit JSX returns.” 三到六条。

    第四步:捕捉操作坑。 那个其实是 symlink 的 path。Windows 上会失败的 CI matrix。90 天过期一次的 credential。需要真实 database 的 integration test。这个章节回报最大,因为每条规则都代表避开一个具体 bug。

    第五步:选三到七条原则。 不是格言。是带理由的具体设计规则。“不要给不可能发生的情况加 error handling”,再加一句 rationale。“Trust internal code; validate at boundaries.” 硬上限七条;如果你有十条,就等于没有。

    第六步:接上执行层。 对第二步到第四步的每条规则,加对应的 hook、CI check 或 verification command。如果某条规则没法机械执行,就在文件里明确标成 advisory。不要假装它能被执行。

    第七步:跑 AgentLint,修它报的问题。 过期 path、冲突、模糊规则、缺少阈值。linter 是最后一遍扫地,抓的是你作为作者最难看见的漂移。

    要刻意不放什么

    大多数 CLAUDE.md 最大的改进,不是加了什么,而是删了什么。下面几类几乎总该放到别处:

    架构文档。 CLAUDE.md 不是放 ADRs(architecture decision records)、system diagrams 或设计历史的地方。把它们放进 docs/,需要时从 CLAUDE.md 链过去。会话开始时读一遍架构文档,大部分是在浪费 context budget。

    入门说明。 “Run npm install then npm run dev” 属于 README。CLAUDE.md 是给 agent 当前会话用的,不是给人类贡献者第一天用的。onboarding doc 和 agent rules 很快会分叉。

    愿景价值观。 “We value collaboration.” 这没法执行。要么变成具体行为规则,要么移到 values doc。

    过去决策的背景。 “我们试过 Redux,又试过 Zustand,最后定了 Jotai。” 对人类很有趣,对 agent 是负担。如果规则是 “use Jotai”,agent 只需要这个。

    Marketing copy 或对外 pitch。 如果你发现自己在为 agent 之外的读者写,你就在写错文件。

    一个完整例子

    这是一份真实项目里的 CLAUDE.md,在七步重写前。原文件 380 行:

    ## Overview
    We are a passionate team building the next generation of...
    [180 lines of mission, history, philosophy]
    
    ## Coding Standards
    - Write good, clean code
    - Follow best practices
    - Be careful with errors
    - Test thoroughly
    [60 lines of similar rules]
    
    ## Architecture
    [100 lines of system diagrams in ASCII art]
    
    ## Onboarding
    [40 lines of git clone / npm install instructions]
    

    同一个项目,七步重写后。142 行:

    ## Project
    A real-time collaboration tool. Users edit shared documents from
    their browsers; conflict resolution is CRDT-based. Stack: TypeScript,
    React, Yjs, Postgres, Redis, deployed on Fly.io.
    
    ## Non-negotiables
    - All changes through PR — no direct pushes to main.
    - Tests must pass before merge — Vitest unit + Playwright E2E.
    - No edits to bun.lock by hand. Use `bun add` or `bun remove`.
    - No secrets in commits — `.env*` is gitignored, secrets via 1Password.
    - Migrations are append-only — never modify a migration after it's applied.
    
    ## Language & Style
    - TypeScript strict mode. No `any`. No implicit JSX returns.
    - Components are functional with hooks. No class components.
    - State: server state via TanStack Query, client state via Zustand.
    - File naming: kebab-case for files, PascalCase for components.
    - Tests live next to source as `<name>.test.ts`.
    
    ## Operational notes
    - `apps/web/` builds with Vite, `apps/api/` builds with esbuild.
    - Local dev needs Docker (Postgres + Redis) — see `pnpm dev:up`.
    - Playwright requires Playwright browsers installed: `pnpm exec playwright install`.
    - CI matrix runs on Linux only — local Windows/macOS issues won't fail CI.
    
    ## Principles
    - Don't add error handling for cases that can't happen.
    - Trust internal code; validate at boundaries.
    - Three identical lines is better than a premature abstraction.
    - If a rule isn't enforced by a hook or CI, it's advisory.
    - Comments explain WHY, never WHAT.
    - When stuck, write less code, not more.
    
    ## Enforcement
    - Pre-commit (Husky): lint, typecheck, format on staged files.
    - Pre-push: full unit test suite.
    - CI: lint + typecheck + unit + Playwright on PR.
    - Required status checks: ci-lint, ci-test, ci-e2e.
    - AgentLint runs in CI on changes to CLAUDE.md.
    

    同一个项目,同一个意图,小了 60%,同时 100% 可机器检查。agent 不到一秒就能读完,并且知道自己在哪个世界里工作。

    为什么这一个下午值得花

    坏 CLAUDE.md 的成本是安静的。agent 每个会话会做 80 个你看不见的决定,而每个决定都会被这个文件影响。一份 380 行、全是模糊建议的 CLAUDE.md 不会 crash。它只会产出一个比 142 行版本稍微差一点的 PR。把这个差距乘以一年里每次会话,代价就很大。这个文件是自主程序的启动流程。花一个下午把它写对,会在 agent 开始下一次会话时立刻回本,而它一周会开始几十次。

    如果你想要起点,AgentLint 有一个 --init mode,会生成一份 70 行 skeleton,匹配上面的七步结构。跑它,填空,用 AgentLint 检查结果,然后 commit。这就是你项目的完美 CLAUDE.md:存在、正确,而且 agent 真的会读。

    相关文章