课程0基础Agent开发课 / Claude-Code实战教程 / CLAUDE.md项目说明书
— 19 min read

CLAUDE.md项目说明书

> **时效说明**:本文内容以 2026 年 3 月为基准。

Claude Code:CLAUDE.md:给 Claude 的项目说明书

时效说明:本文内容以 2026 年 3 月为基准。

7.1 CLAUDE.md——它是什么,为什么重要

每次你在某个项目里启动Claude Code,它都会自动读取项目里的CLAUDE.md文件,把内容注入到上下文里。这相当于你在每次会话开始前,先给Claude做了一个项目背景汇报。

没有CLAUDE.md,Claude只能靠推断——它看到Spring Boot的代码,能猜出大概是个Web服务,但不知道你们的接口命名规范、不知道某些看起来奇怪的代码其实是有意为之、不知道测试要求。有了CLAUDE.md,这些背景信息就不用每次重复说了。

类比一下:CLAUDE.md相当于你们团队Wiki里的"项目README",但专门写给Claude看的版本——你会把那些"新来的程序员必须知道但代码里看不出来"的东西都写进去。


7.2 文件层级与加载顺序

CLAUDE.md有三个层级,优先级从低到高:

全局~/.claude/CLAUDE.md,对所有项目生效。适合写你的个人偏好,比如"总是用中文回复"、"代码注释用中文"。

项目根目录/your-project/CLAUDE.md,对整个项目生效。这是最常用的层级,应该提交到Git,团队共享。

子目录:比如/your-project/backend/CLAUDE.md,只对这个子目录里的操作生效。适合monorepo,不同模块有不同的规范。

当Claude在某个子目录里工作时,它会从当前目录向上逐层读取所有CLAUDE.md文件,合并生效。

7.2.1 加载顺序和覆盖规则

理解加载顺序很重要,因为有时候你会发现Claude的行为和你期望的不一样,原因可能就是层级之间的覆盖关系:

code
加载顺序(从先到后):
1. ~/.claude/CLAUDE.md(全局,最先加载)
2. 项目根目录/CLAUDE.md(项目级)
3. 中间目录/CLAUDE.md(如果有)
4. 当前工作目录/CLAUDE.md(最后加载,优先级最高)

如果全局CLAUDE.md写了"代码注释用中文",但项目CLAUDE.md写了"注释用英文",项目级的规则会覆盖全局规则。

7.2.2 加载时机

CLAUDE.md在每次会话开始时读取,不是实时监听的。如果你在会话进行中修改了CLAUDE.md,需要新开一个会话才能生效。这是一个容易踩的坑——修改了CLAUDE.md但Claude的行为没变,先检查是不是用的还是旧会话。


7.3 用/init自动生成

不知道从哪里下手?在项目根目录执行:

bash
/init

Claude Code会分析你的项目结构,自动生成一份CLAUDE.md草稿。内容包括:检测到的技术栈、发现的构建命令、推断出的项目结构。

这份草稿不会很完整,但能帮你快速建立起一个框架,然后你在上面补充真正重要的信息。

生成后要做的事:

  1. 检查技术栈版本是否准确
  2. 确认构建命令是否正确
  3. 补充"重要背景"部分——这是草稿里最弱的地方,Claude靠代码结构无法推断业务约束

7.4 一份好的CLAUDE.md该写什么

从三个维度来想:

WHAT(项目是什么):技术栈、版本号、项目背景。不用太啰嗦,但关键信息要准确。

WHY(为什么这么做):解释那些看起来奇怪、但其实有原因的设计决策。比如"这个接口故意返回200而不是201,因为某个老版本的客户端不支持"。这类信息是最值得写进去的,因为这是Claude最容易犯错的地方。

HOW(怎么做事):代码规范、命名约定、测试要求、提交规范、构建命令。

7.4.1 完整的CLAUDE.md模板

下面是一个比较完整的模板,覆盖了大多数项目需要说明的内容:

markdown
# [服务名称] 项目说明

## 项目概述

[一两句话说明这个服务是干什么的]

**技术栈**- 语言:Java 17
- 框架:Spring Boot 3.2
- 持久层:MyBatis-Plus 3.5
- 数据库:MySQL 8.0(主从)
- 缓存:Redis 7(单机)
- 消息队列:RocketMQ 5.x
- 注册中心:Nacos 2.x

**依赖的外部服务**(含接口地址):
- 用户服务:user-service(获取用户信息)
- 支付服务:payment-service(支付回调)

## 开发环境

### 前置条件
- JDK 17+(不要用JDK 8,有些语法不兼容)
- Maven 3.8+
- 本地MySQL和Redis(Docker启动方式见下)

### 快速启动

```bash
# 启动依赖服务(MySQL + Redis)
docker-compose up -d

# 编译(跳过测试)
mvn clean package -DskipTests

# 启动(使用本地配置)
mvn spring-boot:run -Dspring-boot.run.profiles=local

# 运行所有测试
mvn test

# 运行单个测试类
mvn test -Dtest=OrderServiceTest

常用命令

bash
# 生成MyBatis代码
mvn mybatis-generator:generate

# 检查代码规范
mvn checkstyle:check

# 打包Docker镜像
mvn jib:build

代码规范

分层规范

  • Controller层:只做参数校验和响应封装,禁止写业务逻辑
  • Service层:核心业务逻辑,使用构造器注入(不用@Autowired)
  • Mapper层:只写数据库操作,不含业务判断

命名规范

  • 接口路径:全小写 + 连字符,如 /api/order-items
  • 方法命名:动词+名词,如 createOrdergetOrderById
  • 常量:大写 + 下划线,统一放在 Constants 类里

响应规范

  • 所有接口响应用 Result<T> 包装
  • 错误码在 ErrorCode 枚举里定义
  • 分页响应用 PageResult<T>

重要背景(请务必阅读)

这一节记录了不从代码里能直接看出来、但非常重要的信息。

金额处理

  • 所有金额字段用 BigDecimal绝对不能用 double 或 float
  • 数据库里存的是分(整数),显示给用户时转成元
  • 计算折扣时保留4位小数,最终金额四舍五入到分

订单状态机

  • 状态流转:待支付 → 已支付 → 待发货 → 已发货 → 已完成
  • 取消只能从"待支付"状态发起,已支付的订单走退款流程
  • OrderStatus 枚举的整数值和数据库直接对应,不要改枚举值的整数

特殊接口

  • /api/payment/callback:支付回调接口,有幂等逻辑(同一笔支付重复回调会被忽略)
    修改前先看懂再动,这里改错会导致重复扣款
  • /api/order/cancel:取消订单需要同时释放库存,
    整个逻辑在事务里,不要把库存操作移到事务外

已知的技术债

  • OrderService 里的 batchUpdateStatus 方法性能差,后面要改,暂时别动它
  • UserClient 使用的是同步调用,后面要改成异步,现在不要加新的同步调用

测试规范

  • 所有Service方法必须有单元测试
  • 数据库测试用 @Transactional + @Rollback,不污染数据
  • Controller测试用 MockMvc,不起真实服务
  • 不要用 Thread.sleep 做时间控制,用 @MockBean mock掉定时任务

禁止做的事

  • 不要修改 BaseEntity(被所有实体继承,改了会影响全部表)
  • 不要在代码里写明文密钥或密码
  • 不要在Service里直接操作订单表,必须通过 OrderDomainService
  • 不要在测试里写固定的日期(比如 "2024-01-01"),用 LocalDate.now()
code

### 7.4.2 写CLAUDE.md的实用技巧

**优先写"坑"而不是写"常识"**:

Claude能从代码里推断出"这是个Spring Boot项目",但推断不出"这个字段不能用double"。CLAUDE.md的价值在于记录那些代码里看不出来的东西。

**给规范写上理由**:

```markdown
# 差:
- 不要用 double 存金额

# 好:
- 不要用 double 存金额(浮点精度问题,历史上出过一次生产事故,
  1000元订单因精度误差显示为999.9999元)

有理由的规范,Claude在执行时会更认真,也不会"聪明地"觉得这条规范不合理然后忽略它。

用层次清晰的结构

CLAUDE.md不是纯文字叙述,用Markdown标题、列表、代码块来组织,Claude读起来更准确。


7.5 Spring Boot项目完整示例

markdown
# 订单服务(order-service)项目说明

## 项目概述

电商平台的核心订单服务,负责订单全生命周期管理。
技术栈:Spring Boot 3.2 + MyBatis-Plus + MySQL 8.0 + Redis 7 + RocketMQ

## 构建与运行

```bash
# 编译并跳过测试(日常开发用)
mvn clean package -DskipTests

# 运行所有测试
mvn test

# 启动服务(需要本地MySQL和Redis)
mvn spring-boot:run -Dspring-boot.run.profiles=local

代码规范

  • Controller层只做参数校验和响应封装,禁止写业务逻辑
  • Service层禁止直接用@Autowired,统一用构造器注入
  • 所有接口响应用统一的 Result<T> 包装,不要直接返回业务对象
  • 错误码统一在 ErrorCode 枚举里定义,不要在代码里写魔法数字

重要背景(请务必读)

  • 订单金额字段全部用 BigDecimal 存储,绝对不能用 double 或 float
  • OrderStatus 枚举值和数据库里的整数映射关系见 OrderStatus.java 注释
  • 支付回调接口(/api/payment/callback)有幂等逻辑,修改前先看懂再动
  • 测试环境的RocketMQ地址和生产不一样,配置在 application-local.yml 里

测试要求

  • 新增Service方法必须有对应的单元测试
  • 涉及数据库操作的测试用 @Transactional + @Rollback,不要污染测试数据
  • Controller测试用 MockMvc,不要用真实HTTP

不要做的事

  • 不要修改 BaseEntity 基类,它被所有实体继承
  • 不要在代码里写日志密码或密钥,用配置文件
  • 不要直接操作 order 表,所有写操作必须经过 OrderService
code

---

## 7.6 微服务项目的CLAUDE.md:多模块场景

当项目是微服务架构,多个服务在同一个仓库时(monorepo),CLAUDE.md的层级结构很重要。

### 7.6.1 目录结构和对应的CLAUDE.md

ecommerce-platform/
├── CLAUDE.md # 全局共享:通用规范、服务间关系
├── order-service/
│ ├── CLAUDE.md # 订单服务专属:订单状态机、金额规范
│ └── src/
├── user-service/
│ ├── CLAUDE.md # 用户服务专属:认证逻辑、隐私规范
│ └── src/
├── payment-service/
│ ├── CLAUDE.md # 支付服务专属:幂等规范、对账逻辑
│ └── src/
└── gateway/
├── CLAUDE.md # 网关专属:路由规则、限流配置
└── src/

code

### 7.6.2 根目录CLAUDE.md写什么

根目录的CLAUDE.md只写跨服务都需要知道的内容:

```markdown
# 电商平台(ecommerce-platform)全局说明

## 项目结构

这是一个微服务项目,包含以下服务:
- order-service:订单全生命周期
- user-service:用户和认证
- payment-service:支付和对账
- gateway:API网关

各服务有自己的 CLAUDE.md,进入对应目录查看详细规范。

## 跨服务通用规范

### API规范
- 所有服务间调用走内部域名(不走网关)
- 服务间鉴权用 JWT(在 common-auth 模块里)
- 响应格式统一用 Result<T>(在 common-core 模块里)

### 数据库规范
- 每个服务独立数据库,禁止跨服务直接查对方的数据库
- 服务间数据同步走消息队列,不走同步接口(异步化原则)

### 日志规范
- 所有日志用 SLF4J,不直接用 System.out.println
- 错误日志必须包含 traceId(MDC注入)
- 不要在日志里打印密码、手机号等敏感字段

## 公共模块

- `common-core`:统一响应、异常处理、常量
- `common-auth`:JWT工具、权限注解
- `common-redis`:Redis工具封装
- `common-mq`:MQ消息定义

**修改公共模块前必须评估影响范围**,所有服务都依赖它。

7.6.3 子服务CLAUDE.md写什么

子服务的CLAUDE.md专注于本服务的特殊知识:

markdown
# 支付服务(payment-service)说明

## 这个服务的核心职责

处理所有支付相关操作:创建支付单、接收第三方回调、对账、退款。

## 最重要的规范:幂等性

**支付相关的所有操作必须幂等**。原因:网络重试、用户重复点击、第三方回调重复推送都是正常现象。

幂等实现:
- 支付单有唯一的 `payment_no`(业务幂等键)
- 所有写操作先查幂等键是否存在
- `payment_callback` 接口用Redis分布式锁 + 状态机控制,已处理的回调直接返回成功

## 第三方渠道的特殊性

- 微信支付:回调可能延迟30分钟,不要以为没收到就是失败
- 支付宝:沙箱环境和生产的密钥不同,注意配置文件
- 银行卡直连:有严格的报文格式要求,修改报文组装逻辑前先看文档

## 不要做的事

- 不要修改 `PaymentStatus` 枚举值对应的整数(和数据库直接映射)
- 不要在回调接口里做耗时操作(微信要求3秒内响应)
- 退款逻辑涉及资金,任何修改前必须CR

7.7 用#前缀实时更新记忆

在对话过程中,你可以用#前缀向Claude说话,它会把这条信息记录下来而不是作为普通对话处理:

code
# 我们刚讨论决定,分页查询统一用游标分页而不是offset分页

# 前缀会将内容写入 CLAUDE.local.md(个人本地记忆,不提交git)。如需更新团队共享的规范,请手动编辑 CLAUDE.md。这对于记录"正在进行中的决策"很有用,不用手动去编辑文件。


7.8 CLAUDE.local.md详解

CLAUDE.local.md是你的个人本地记忆文件,和CLAUDE.md的区别:

对比项 CLAUDE.md CLAUDE.local.md
提交到Git 否(加入.gitignore)
团队可见 所有人 只有你
内容类型 团队共享规范 个人偏好、临时决策
更新方式 手动编辑 手动或 # 前缀

适合写进CLAUDE.local.md的内容

markdown
# 个人开发偏好

## 我的工作环境
- IDE:IDEA 2024
- 终端:iTerm2
- 本地数据库密码:(这里可以写,因为不会提交git)

## 当前正在做的任务

正在重构订单模块的缓存逻辑,预计本周完成。
进度:Service层已完成,Mapper层还没改。
待讨论:Redis的key设计还没确定。

## 个人偏好

- 给我的代码示例都用Java 17语法(record、text block等)
- 错误信息用中文,代码注释用英文
- 生成测试时优先用JUnit 5 + Mockito

## 暂定的决策(还没写入CLAUDE.md)

- 决定用Caffeine本地缓存替代Redis,原因是减少运维复杂度
  待确认:和团队对齐后写入CLAUDE.md

CLAUDE.local.md的维护建议:把它当做一个"工作日志",记录当前任务的状态、临时决策、个人配置。不需要永久保留,定期清理过时的内容。


7.9 CLAUDE.md的反模式

有些东西看起来适合写进CLAUDE.md,但实际上会让它变得臃肿、低效。

7.9.1 不应该写进去的东西

不应该写进去:完整的代码规范文档

markdown
# 错误示范:把所有规范都堆进去
## 命名规范
- 类名用大驼峰
- 方法名用小驼峰
- 变量名用小驼峰
- 常量用全大写
- 包名用全小写
- 接口名以I开头
...(继续列了30条)

这些规范Claude本来就知道(Java编程规范),写进去只是浪费Token。CLAUDE.md里只写那些"不说Claude会猜错的"内容。

不应该写进去:Claude能从代码里自己推断的东西

markdown
# 错误示范
这是一个Spring Boot项目,使用MyBatis做持久层,MySQL是数据库。
Controller层返回JSON格式的响应...

Claude看到你的代码就知道了,不需要在CLAUDE.md里重复。

不应该写进去:过期的信息

markdown
# 错误示范:已经废弃的说明还留着
## 旧版API(已废弃,2023年10月下线)
- /api/v1/order:旧版订单接口,不要再用

过期信息比没有信息更危险——Claude可能认真遵守了一条早就不适用的规范。

不应该写进去:应该用自动化工具保证的规范

markdown
# 错误示范:用CLAUDE.md替代linter
- 所有方法必须有JavaDoc注释
- 代码行长度不超过120字符
- import不能有通配符(import java.util.*)

这些规范应该用Checkstyle或SonarQube来强制检查,不应该依赖Claude记住。Claude的任务是帮你思考业务逻辑,不是充当linter。

7.9.2 反模式的本质

CLAUDE.md过于冗长会带来两个问题:

  1. 消耗大量Token(每次会话都要读入)
  2. 重要信息被淹没在大量普通信息里,Claude实际执行时关注度下降

一个经验法则:如果CLAUDE.md超过了500行,就需要审视了——要么是写了太多Claude本来就知道的东西,要么是需要拆分到子目录的CLAUDE.md里。


7.10 CLAUDE.md的维护策略

7.10.1 建立"更新触发点"

不要等到CLAUDE.md完全过时才更新。在以下情况下,把更新CLAUDE.md作为任务的一部分:

  • 做了重要的架构决策:完成了缓存方案的讨论,把结论写进去
  • 发现了一个新的坑:踩到了一个Claude会犯的错,把规避方法写进去
  • 修改了关键接口:接口契约变了,更新相关说明
  • 增加了新的约束:比如新增了"金额处理必须四舍五入"的规范

7.10.2 季度性清理

每个季度做一次CLAUDE.md的"清理":

  1. 检查"重要背景"里的信息是否还准确
  2. 删除已经废弃的功能说明
  3. 把已经用自动化工具覆盖的规范从CLAUDE.md里移出
  4. 更新命令(比如构建命令里的版本号)

7.10.3 用Claude来帮你维护CLAUDE.md

一个有意思的用法:让Claude帮你检查CLAUDE.md的质量:

code
帮我审查我们的CLAUDE.md:
1. 有哪些内容已经可以从代码里直接推断出来,可以删掉?
2. 有哪些重要的背景知识是从代码里看不出来的,需要补充?
3. 有没有过时的信息需要更新?

7.11 团队协作中的CLAUDE.md

7.11.1 CLAUDE.md是团队的共同财产

CLAUDE.md应该提交到Git,像对待代码一样对待它。这意味着:

  • Code Review:修改CLAUDE.md也需要PR和CR
  • Changelog:重要的修改在commit message里说明原因
  • 冲突解决:多人同时修改时需要合并,和代码一样处理

7.11.2 建立团队共识

引入CLAUDE.md的时候,团队需要达成几个共识:

谁来维护:不是一个人的活。每个人在发现"Claude犯了某个可预防的错误"时,都有责任更新CLAUDE.md。

更新的质量标准:写进CLAUDE.md的内容要满足"Claude不说会犯错"这个标准,不是什么都往里堆。

避免规范冲突:不同人写的规范之间可能矛盾。设立一个人(比如技术负责人)来做最终的一致性审查。

7.11.3 新人入职场景

CLAUDE.md对新人入职也有价值。一个新人加入项目,在第一天让Claude Code读CLAUDE.md,然后问:

code
我刚加入这个项目,还不熟悉代码库。
基于项目说明书,给我讲讲最需要注意的5件事,
特别是那些容易犯错的地方。

Claude会帮他整理出关键的背景知识,比任何新人文档都更精准——因为CLAUDE.md里写的就是"容易犯错的地方"。


7.12 CLAUDE.md的测试:如何验证规则被遵守

写了一堆规范,怎么知道Claude真的在遵守?

7.12.1 用反向验证

写完某条规则后,立即用一个会触发它的场景测试:

markdown
# 你在CLAUDE.md里写了:
不要用 double 存金额,必须用 BigDecimal

然后在会话里测试:

code
帮我写一个计算订单折扣的方法,
输入:原价(元)、折扣率(0.0到1.0),
输出:折后价(元)

看Claude生成的代码里,金额字段用的是BigDecimal还是double。如果用了double,说明你的规范写得不够清晰或者权重不够,需要调整表达方式。

7.12.2 问Claude是否理解了规则

在会话开始时,直接问:

code
你已经读了我们的CLAUDE.md。
请告诉我,你认为这个项目里最关键的3条规范是什么,
以及违反它们会有什么后果。

Claude的回答能反映它对CLAUDE.md的理解程度。如果它说出来的不是你认为最重要的,可能需要在CLAUDE.md里加重点标注。

7.12.3 持续观察和反馈

日常使用中,每当发现Claude做了CLAUDE.md里明确禁止的事,记录下来:

  • 规则写得不够清晰?重新表述
  • 规则太多,Claude没注意到这条?把重要的放在更显眼的位置
  • Claude理解了规则但判断该场景不适用?补充更明确的约束条件

7.13 最佳实践:保持精简

CLAUDE.md不是什么都往里堆的地方。几个原则:

不要把CLAUDE.md当代码规范文档用。规范太多,Claude会忘记执行;而且规范执行应该靠linter和checkstyle来保证,不是靠Claude记住。

只写Claude容易犯错的地方。那些"在代码里一眼就能看出来"的东西不用写,Claude自己能推断。只写那些"没有背景知识会搞错"的东西。

定期清理过期信息。项目迭代了,CLAUDE.md里写的信息可能已经不准确了,过期信息比没有信息更有害。

一个检验标准:对着CLAUDE.md里的每一条,问自己"如果没有这条,Claude会在什么场景下犯什么错?"如果答不上来,这条可能就不需要。


本页目录