CLAUDE.md 还是 rules?先把项目事实与编码规范分开
团队开始维护 Claude Code 指令时,通常会先创建一个 CLAUDE.md。随着项目推进,遇到一个问题就补一条,文件很快从几十行增长到几百行。
这时往往会陷入两难:写得太简单,AI 不知道具体怎么执行;写得太详细,又会占用大量上下文,让真正重要的信息失去焦点。
解决这个问题的关键,不是继续争论“应该写多少行”,而是先把不同性质的内容分开。
CLAUDE.md 的定位:常驻、高频、高信号
CLAUDE.md 会作为项目指令进入 Claude 的上下文。它适合保存几乎每次会话都可能需要的信息,例如:
- 技术栈和主要框架
- 包管理器、构建工具和版本要求
- 启动、测试、格式化、检查命令
- 关键目录及其职责
- 重要架构边界
- 全项目通用的命名或安全要求
- 很难从代码中推断出的特殊约定
一个精简的示例:
# 订单服务
## 技术栈
- Java 17、Spring Boot 3.x
- PostgreSQL、Redis
- Maven、Flyway
## 常用命令
- 启动:`mvn spring-boot:run`
- 测试:`mvn test`
- 完整检查:`mvn verify`
- 代码风格:`mvn checkstyle:check`
## 架构边界
- Controller 只处理协议适配与参数校验
- 业务逻辑放在 Service
- 数据访问通过 Repository 或 Mapper
## 项目红线
- 数据库变更必须提供 Flyway migration
- 不提交 application-local.yml 和真实密钥
- 支付、权限和资金计算相关改动必须请求人工评审
官方建议每个 CLAUDE.md 以 200 行以内为目标。这不是硬性长度限制,超过后仍然会加载;问题在于长文件会消耗更多上下文,并可能降低指令遵守的稳定性。
因此,与其追求严格的行数数字,不如追求三个标准:
- 是否每个会话都需要?
- 是否足够具体?
- 是否比它占用的上下文更有价值?
rules 的定位:模块化、可维护、可限定范围
对于较大的项目,可以把规则拆到 .claude/rules/:
my-project/
├── CLAUDE.md
└── .claude/
└── rules/
├── coding-style.md
├── api-design.md
├── database.md
├── security.md
└── testing.md
每个文件只负责一个主题:
coding-style.md:命名、日志、错误处理和注释。api-design.md:入参、响应、错误码和分页。database.md:查询、写入、索引、事务和 migration。security.md:鉴权、敏感数据、密钥和日志脱敏。testing.md:测试类型、目录、命名和运行命令。
这种拆分带来几个明显好处。
第一,职责清楚。维护 API 规范时不需要在数百行文件中寻找对应段落。
第二,Git 冲突更少。不同负责人可以维护不同规则文件。
第三,可以使用路径规则,只在 Claude 阅读相关代码时加载对应内容。
第四,规则变更可以通过 PR 独立评审,提交记录也能解释规范为什么变化。
一条模糊规则为什么没有用?
下面两条规则看起来合理:
- 不要使用 console.log,统一使用 logger
- 修改接口时要补测试
但对 AI 来说仍然有很多未知信息:
- logger 从哪里导入?
- 使用
logger.error()还是logger.log()? - 日志字段是拼接字符串还是结构化对象?
- 哪些上下文必须记录?
- 哪些敏感信息不能记录?
- 要补单元测试还是集成测试?
- 测试文件放在哪个目录?
- 用例如何命名?
- 应该运行哪条验证命令?
所以,团队规则应该尽量写到“可执行”,而不是只表达愿望。
可执行规则的七个组成部分
一条高质量规则可以包含:
- 适用范围:影响哪些目录、语言或组件。
- 强度:必须、禁止、建议还是例外情况。
- 正确动作:具体使用哪个库、接口或目录。
- 禁止动作:明确哪些写法不能出现。
- 正反示例:让 AI 看到项目期望的形状。
- 验证方法:给出 lint、测试或脚本命令。
- 原因或例外:解释不明显的决策,避免 AI 自行“优化”。
团队也可以给规则标注强度,例如:
- P0 / 必须:违反会造成安全、数据、兼容性或明显质量风险。
- P1 / 强烈建议:通常应该遵守,但允许在说明理由后采用例外方案。
- 建议:用于提高一致性,不应阻塞合理实现。
优先级不宜滥用。如果所有规则都是 P0,最终等于没有优先级。真正能够确定性验证的 P0 要求,还应该同步进入权限、Hook 或 CI。
例如日志规则可以这样写:
# 日志规范
## 必须
- 使用项目 `infra/logger` 导出的 logger
- 错误日志调用 `logger.error(message, context)`
- context 必须包含 requestId 和相关业务实体 ID
- 原始异常放在 `error` 字段,不要只记录 error.message
## 禁止
- 禁止使用 console.log、console.error
- 禁止记录密码、Token、Cookie 和完整个人敏感信息
- 禁止通过字符串拼接模拟结构化字段
## 示例
不要这样:
```ts
console.log("Load user failed: " + userId, error);
应该这样:
logger.error("Failed to load user", {
requestId,
userId,
error
});
验证
运行 pnpm lint。
这样的规则不仅告诉 AI“不能做什么”,还告诉它应该怎样完成任务。
## 不要把 rules 写成编程教材
“写得详细”不等于把每个概念都解释一遍。AI 本身已经知道 Java、TypeScript、Spring 和 React 的通用知识。
规则应该重点记录项目特有内容,例如:
- 团队选择了哪一种可行方案。
- 当前代码库有哪些容易踩坑的地方。
- 哪些通用最佳实践在本项目中不适用。
- Code Review 中反复出现过什么问题。
- 应该模仿哪个现有模块或测试文件。
下面这种内容通常价值不高:
```markdown
- 变量名应该有意义
- 代码应该清晰易懂
- 写代码时注意性能
- 尽量遵循最佳实践
它们很难验证,也没有提供项目特有信息。
多步骤流程应该放进 Skills
如果一段规则逐渐变成“第一步做什么、第二步检查什么、第三步提交什么”,它已经不再是普通约定,而是工作流。
例如:
- 创建并验证数据库迁移
- 执行生产发布
- 排查线上性能问题
- 完成安全审查
- 按团队模板生成新模块
这类内容更适合放在 .claude/skills/<name>/SKILL.md。Skill 的正文按需加载,不需要在每个会话里常驻。
可以用一句话区分:
rules 描述“写这种代码时应遵守什么”;Skills 描述“这项任务具体如何完成”。
一个实用的内容分流判断
遇到新规范时,可以依次问:
- 每个会话都需要知道吗?需要则考虑
CLAUDE.md。 - 只影响某类文件吗?是则考虑路径规则。
- 它是一套多步骤流程吗?是则考虑 Skill。
- 能被程序确定性检查吗?能则优先交给 lint、测试或 CI。
- 必须阻止某个工具行为吗?是则使用权限或 Hook。
- 需要业务判断吗?保留人工 Review。
小结
CLAUDE.md 与 .claude/rules/ 并不是互相替代的两个选项。
CLAUDE.md保持精简,保存需要常驻的项目上下文。- rules 按主题拆分,保存具体、可执行的编码规范。
- 路径规则减少无关内容。
- Skills 承载较长的任务流程。
- 自动化工具负责确定性检查。
下一篇将深入 rules 的加载方式:无条件规则、路径规则、用户级规则、符号链接,以及 monorepo 中如何划分团队边界。