CLAUDE.md 项目指令
CLAUDE.md 是 Claude Code 在每一次会话开始时都会自动读进上下文的一份说明书。它不是文档,是命令。你在里面写的每一句话,Claude 都当成你亲口对它说过的话。
CLAUDE.md 是什么
CLAUDE.md 是一份放在项目根目录的 markdown 文件。你在项目里第一次运行 claude 时,Claude Code 会去找它,找到就自动塞进系统提示,让当前会话在读你第一条消息之前就已经知道项目的背景、约束和踩坑记录。同一个 Claude Code 在两个不同项目里表现得像两个不同的助手,就是因为它读到的 CLAUDE.md 不一样。
CLAUDE.md 有两个层级。
- 项目级:
./CLAUDE.md,进入哪个项目就只对该项目生效,通常随代码进 git,团队共享。 - 用户级:
~/.claude/CLAUDE.md,对当前用户在任何项目里都生效,用于放你个人的通用偏好,比如中文回答、禁用某些标点、Git 分支策略等。
两份文件会同时加载,用户级在前,项目级在后,项目级可以覆盖或补充用户级的说法。子目录也可以有自己的 CLAUDE.md,进入该子目录工作时会追加进上下文,适合大型 monorepo。
一句话记住它
CLAUDE.md 不是给人看的 README,是给模型看的 prompt。写的时候脑子里要浮现的画面是新员工入职前你留给他的一张便签,而不是给外部用户看的说明书。
一份合格的 CLAUDE.md 长什么样
不同项目会有差别,但常见的骨架都逃不出下面这几块。
- 项目介绍:一段话讲清项目在解决什么问题、用了什么技术栈、目前处于什么阶段。
- 关键目录:告诉 Claude 每个目录放什么,避免它把新文件塞到错误位置。
- 代码规范:命名、缩进、错误处理、日志格式等硬约束。
- 测试要求:怎么跑测试、覆盖率要求、什么改动必须补测试。
- 提交规范:commit message 格式、分支命名、PR 描述模板。
- 已知踩坑:踩过的坑集中列出来,避免同一个错误犯第二次。
下面是一份中型 Node.js 项目的完整示例,你可以按需裁剪。
# 项目:orderly-api
## 项目介绍
orderly-api 是电商团队的订单服务,负责下单、支付回调、履约状态同步。基于 Node.js 18 + TypeScript + Fastify + PostgreSQL,跑在 Kubernetes 上。日均订单 20 万,峰值 QPS 500。
## 关键目录
- `src/routes/`:HTTP 入口,只做参数校验和调用 service,禁止直接写业务逻辑。
- `src/services/`:业务逻辑,全部纯函数或类方法,不感知 HTTP。
- `src/repos/`:数据库访问层,使用 Prisma。
- `src/helpers/`:跨模块的工具函数,禁止反向依赖 service 或 repo。
- `tests/`:Jest 测试,目录结构镜像 src。
- `scripts/`:运维脚本,不进入生产镜像。
## 代码规范
- TypeScript strict 模式,禁止 any,除非注释说明理由。
- 异步一律 async/await,禁止 .then 链。
- 错误抛自定义 `AppError`,包含 code、message、httpStatus 三个字段。
- 日志用项目内的 `logger.ts`,禁止直接 console.log。
- 命名:文件 kebab-case,类 PascalCase,函数 camelCase,常量 SCREAMING_SNAKE_CASE。
## 测试要求
- 新增 service 或 route 必须补对应单测和集成测试。
- 运行方式:`pnpm test`(全量)或 `pnpm test -- <path>`(单文件)。
- 覆盖率下限 80%,CI 会卡门。
## 提交规范
- 分支:feat/xxx、fix/xxx、refactor/xxx、docs/xxx。
- commit message:Conventional Commits,主题一句话说清为什么改。
- 每完成一个可验证节点立即 commit,不要攒。
## 已知踩坑
- Prisma migrate 在生产禁用,全部走 `migrate deploy`,PR 里带 SQL 预览。
- 支付回调是幂等的,重复投递必须靠 `payment_events` 表的唯一索引挡住,不要在应用层做去重。
- Redis 只做缓存,禁止当作真源,所有关键状态以 Postgres 为准。这份文件长度大约 400 到 600 字,落在一个健康的范围里。它不长,但每一句都在给 Claude 一个具体的约束。
用 /init 自动生成第一版
不用从零手写。进入项目根目录后打开 Claude Code,直接输入 slash 命令:
/initClaude Code 会扫描当前目录,读 package.json、tsconfig、README、常见的入口文件,然后生成一份初稿丢在 ./CLAUDE.md。生成完你必须自己过一遍,理由有三个。
第一,自动生成的内容偏描述性,读起来像 README,但 CLAUDE.md 应该是命令式的,需要你把描述改成约束。第二,/init 不知道你团队的踩坑史,那部分只能自己补。第三,/init 有时会把过时的信息也总结进去,比如它看到旧的 npm scripts 就抄进 CLAUDE.md,你换用 pnpm 之后要手动改。
/init 是起点不是终点
/init 生成完就直接 commit 是一个常见反模式。至少留 15 分钟自己走一遍每一行,把描述改成命令,把用不上的删掉。
什么时候更新 CLAUDE.md
三个明确的信号。
- 同一个错误 Claude 犯了两次。第二次改完顺手把根因写进已知踩坑。
- 项目引入新技术栈或改了目录结构。CLAUDE.md 不同步更新,Claude 就会拿着旧地图找路。
- 团队新加了硬约束。比如决定不再用 CommonJS,全部 ESM,这类决策必须落到 CLAUDE.md,不然 Claude 生成的新文件还会用旧写法。
反过来说,一次性的小事情、临时任务、只关乎某个 PR 的说明,都不应该进 CLAUDE.md,它们该在你和 Claude 的对话里说完就丢掉。
什么时候精简 CLAUDE.md
CLAUDE.md 越长,每次会话上下文里被它占掉的份额越多。上下文是有限资源,Claude 记住的 CLAUDE.md 越长,能记住你本轮对话的空间就越少。一份健康的 CLAUDE.md 通常在 500 到 1500 字之间,超过 2500 字就要考虑瘦身。
瘦身的思路有三条。
- 把过时或已经完成的内容删掉。已经上线的功能没必要再讲历史决策。
- 把细节挪到子目录的 CLAUDE.md 或独立文档里。前端相关的规范可以放到
frontend/CLAUDE.md。 - 把重复的话合并。同一个约束用一句话说清就够了,别在三个地方各写一遍。
一个实用检查
CLAUDE.md 的每一行都问自己一个问题:如果 Claude 没读到这一行,它会不会做错事?答案是不会的,就删掉。答案是会的,就留下。