01 · CLAUDE.md 怎么写
项目宪法。不是 README,不是说明书。
写在最前面
很多人把 CLAUDE.md 想象成"给 Claude 的项目说明书"。错。
更准确的比喻是道路上的交通标志——限速牌、禁行标志、单行道指示。Claude 每次进来干活,都是开车经过。你的任务不是给它讲这条路的历史、沿途风景、建造动机,而是告诉它:
- 这里限速 60(→ 项目约定)
- 那个路口禁止左转(→ 禁区)
- 前方施工改道(→ 踩过的坑)
说明书是给开车新手看的,交通标志是给所有司机看的。CLAUDE.md 属于后者。
一句话记住
CLAUDE.md 是写给 Claude 看的,不是写给人看的。
这句话听起来像废话,但 90% 的 CLAUDE.md 翻车都是因为忘了它。
该写什么
| 类别 | 例子 |
|---|---|
| 技术栈和版本 | Next.js 16 + React 19 + TS strict,防止用过时 API |
| 项目特有约定 | 所有 API 路由必须用 zod 校验输入 |
| 禁区 | 不要修改 legacy/ 目录 |
| 常用命令 | dev: pnpm dev、build: pnpm build |
| 非显而易见的架构决策 | 我们故意不用 ORM,原因是 xxx |
| 反复翻车的教训 | 只能用 pnpm,用 npm 会污染 lockfile |
不该写什么
- 代码能推导的东西:目录结构、文件列表、函数签名——Claude 会
ls会grep,写进去只会过时 - 文学叙事:项目愿景、使用场景——放 README 去
- 一次性任务上下文:今天要做的功能、临时的 debug 线索——这是对话内容
- 长篇重复:同一规则说三遍不会让 Claude 更听话,只会稀释其他规则
- 废话口号:
请写出优雅、可维护、高性能的代码——等于没写
❌ README 式写法(反例)
# MyApp
MyApp 是一个面向企业用户的 SaaS 平台,致力于帮助团队……
我们采用现代化的 Web 技术栈,追求极致的用户体验……Claude 读完——什么约束也没拿到。
✅ 宪法式写法(正例)
# MyApp
## 技术栈(避免用过时 API)
- Next.js 16 App Router(`params` 是 async,必须 await)
- React 19(不需要手动 memo,编译器会处理——前提是启用了 React Compiler)
- TS strict
- Tailwind 4(首选 `@utility`,`@apply` 不再推荐)
## 约定
- 新组件先看 `src/components/` 有没有能复用的
- 所有 server action 用 zod 校验入参
## 禁区
- 不要自己安装新依赖,先讨论每一行都在给 Claude 下一个可执行的约束。
分层加载
Claude Code 会自动叠加加载三层:
~/.claude/CLAUDE.md ← 你的个人偏好(跨所有项目)
<repo>/CLAUDE.md ← 项目宪法
<repo>/<subdir>/CLAUDE.md ← 工作目录在子目录时追加实用技巧:大项目前后端约定不一样?
frontend/CLAUDE.md写 React / Tailwind 约定backend/CLAUDE.md写 API / DB 约定- 根
CLAUDE.md只写全局的
比塞一大坨在根目录清爽得多,Claude 也只会加载相关的。
一个能直接抄的骨架
# <项目名>
## 技术栈
- <语言 / 框架 + 版本 + 关键坑>
## 命令
- `pnpm dev` — 开发
- `pnpm build` — 提交前必须通过
- `pnpm test` — 单元测试
## 约定
- <规则 1,具体可执行>
- <规则 2>
## 禁区
- <别动的目录 / 文件>
- <不要做的事>
## 踩过的坑
- <教训 1>
- <教训 2>演进:CLAUDE.md 是活的
CLAUDE.md 不是写完就锁起来的。
成长公式
每次 Claude 犯错 → 问自己:"这个错误,是不是该进 CLAUDE.md?" → 是 → 加一条
比如 Claude 又一次忘了 await params,你不该只说"这里要 await",你应该同时更新 CLAUDE.md。下一次的 Claude 就不会再犯。
定期瘦身
- 每月扫一遍,删过时的、合并重复的
- 目标:100 行以内
- 超过 200 行多半有冗余,该拆子目录或瘦身
越具体越好
写**"函数超过 50 行必须拆",不写"写高质量代码"**。
| ❌ 废话 | ✅ 可执行 |
|---|---|
| 保持简洁 | 一段不超过 4 行 |
| 多举例子 | 每个观点配 ✅ / ❌ 示例 |
| 写高质量代码 | 函数超过 50 行必须拆 |
| 注意类型 | 禁止 any,用 unknown 窄化 |
| 遵循最佳实践 | 服务层失败返回默认值,不抛异常 |
价值观 vs 规则:前者是情绪,后者 Claude 能自我检查。写 CLAUDE.md 最关键的一步就是把感受翻译成规则。
容易踩的坑:技术断言必须准确
CLAUDE.md 里一条错的规则比不写更糟——因为 Claude 会照执行。
典型案例
错误写法:
- React 19 — 编译器自动 memo,不要手动 memo / useMemo问题:
- React 19 本身不会自动 memo
- React Compiler 是独立编译器,需要手动启用(
experimental.reactCompiler: true) - 即使启用,也不是"禁止手动 memo",而是"未证明必要时优先让编译器处理"
纠正后:
- React 19 + React Compiler(next.config.ts 已启用)
优先让编译器处理 memoization,手动 memo / useMemo 需先证明必要性校准三原则
- 技术断言配具体版本号,或"本项目实际如何"(比如
next.config.ts里到底开没开) - 模糊的倾向用"优先 / 除非"而非"必须 / 禁止"
- 不确定的,宁可不写
三个典型反例
- ❌ "本项目是一个面向企业用户的 SaaS 平台,致力于……"(营销稿)
- ❌ "src/ 目录下有 components/、pages/、utils/……"(Claude 自己会看)
- ❌ "请尽量写出优雅、可维护、高性能的代码"(价值观不是规则)
一句话总结
每一行都要能被 Claude 执行。不能被执行的,挪去别处。
速查
写 CLAUDE.md 前自问
这条信息
↓
Claude 看代码 / git log 能得到? ── 是 → 不写
↓ 否
有版本 / 具体约束 / 可检查? ── 否 → 改具体
↓ 是
过 6 个月还会重要? ── 否 → 放对话
↓ 是
入 CLAUDE.md每行都该能回答
"如果这行没了,Claude 的行为会变差吗?"
答案是"不会"的,就删掉。
← 序言 | 目录 | 02 · 记忆的三层体系 →