前言
如果你只能为 Claude Code 写一个配置文件,那一定是 CLAUDE.md。
CLAUDE.md 是 Claude Code 的**「员工手册」**。它告诉 Claude "做什么"——项目怎么构建、代码风格是什么、有哪些坑要避开。而 settings.json 告诉 Claude "怎么做"——权限、模型、工具配置。两者搭配,才是完整的 Claude Code 配置体系。
很多人用 Claude Code 觉得"不够聪明"、"总是犯同样的错",大多数时候不是模型的问题,而是没有给够上下文。CLAUDE.md 就是解决这个问题的核心手段。
这篇文章把 CLAUDE.md 讲透——从文件层级到写作原则,从高价值内容到反模式,再到完整的实战示例。
一、CLAUDE.md 是什么
1.1 一句话定义
CLAUDE.md 是一个纯文本文件,放在项目中(或用户目录下),Claude Code 启动时自动读取,作为整个会话的背景指令。你写在里面的内容,Claude 会在每次对话中都"记住"。
把它想象成你给一个新同事写的入职文档:项目怎么跑、代码怎么写、有什么规矩。区别是这个"同事"每次上班都会从头读一遍这份文档。
1.2 和其他配置文件的区别
Claude Code 有四种配置文件,各司其职:
| 文件 | 内容类型 | 作用 | 类比 |
|---|---|---|---|
CLAUDE.md | 自然语言 | 项目知识、编码规范、工作流指令 | 员工手册 |
settings.json | JSON | 权限、工具、模型、环境变量 | IT 安全策略 |
.claude/commands/ | Markdown 模板 | 可复用的 Prompt 模板 | SOP 操作手册 |
.claudeignore | Glob 模式 | 排除文件/目录,不让 Claude 读取 | .gitignore |
一个常见的误区是把所有东西都塞进 CLAUDE.md。记住分工:
- "Claude 应该知道什么" → CLAUDE.md
- "Claude 被允许做什么" → settings.json
- "Claude 不该看什么文件" → .claudeignore
- "常用操作怎么一键触发" → commands
1.3 为什么 CLAUDE.md 是最重要的配置文件
settings.json 控制的是"能不能",CLAUDE.md 控制的是"好不好"。
没有 settings.json,Claude Code 照样能工作(只是每次都要确认权限)。但没有 CLAUDE.md,Claude 就像一个什么都不知道的新人——它不知道你的项目用什么构建工具、测试怎么跑、代码风格有什么特殊要求。它只能靠猜,而猜错的概率很高。
CLAUDE.md 是你获得好结果最重要的杠杆。
二、文件层级与加载顺序
2.1 五个层级
CLAUDE.md 有五个层级,Claude Code 启动时会按顺序加载并合并:
① Enterprise(最高优先级,不可覆盖)
~/.claude/enterprise/CLAUDE.md
② 用户级(跨项目的个人偏好)
~/.claude/CLAUDE.md
③ 项目根目录(团队共享,提交到 Git)
./CLAUDE.md
④ 子目录级(特定模块的上下文)
./src/CLAUDE.md
./packages/api/CLAUDE.md
⑤ 项目用户级(个人项目笔记,不提交)
~/.claude/projects/<project-hash>/CLAUDE.md
2.2 层级详解
| 层级 | 路径 | 谁写 | 是否提交 Git | 典型内容 |
|---|---|---|---|---|
| Enterprise | ~/.claude/enterprise/CLAUDE.md | IT 管理员 | N/A | 公司级编码规范、安全要求 |
| 用户级 | ~/.claude/CLAUDE.md | 个人 | N/A | 个人偏好(语言、风格) |
| 项目根目录 | ./CLAUDE.md | 团队 | 是 | 构建命令、架构、约定 |
| 子目录级 | ./src/CLAUDE.md | 团队 | 是 | 模块特定的上下文 |
| 项目用户级 | ~/.claude/projects/<hash>/CLAUDE.md | 个人 | N/A | 个人笔记、临时提醒 |
2.3 加载与合并行为
所有层级的 CLAUDE.md 内容会拼接在一起,作为 Claude 的系统上下文。不是覆盖,是拼接——所有层级的内容 Claude 都能看到。
最终上下文 = Enterprise
+ 用户级
+ 项目根目录
+ 当前工作目录的子目录级(如果有)
+ 项目用户级
关键细节:
- 子目录级是动态的:Claude 只会加载当前工作目录路径上的子目录 CLAUDE.md。如果你在
packages/api/下工作,Claude 会加载packages/api/CLAUDE.md,但不会加载packages/web/CLAUDE.md。 - Enterprise 不可覆盖:其他层级无法"取消"Enterprise 层的指令。这是给企业 IT 管理员用的强制策略。
- 内容冲突时:如果两个层级的指令矛盾,Claude 会倾向于遵循更具体的(子目录 > 项目根目录 > 用户级)。但最好避免冲突。
2.4 每个层级的使用场景
Enterprise(~/.claude/enterprise/CLAUDE.md):
# 公司编码规范
- 所有代码必须通过 ESLint 检查后才能提交
- 不要使用 any 类型
- 所有 API 端点必须有错误处理
- 日志使用公司统一的 logger 库,不要用 console.log
- 敏感数据(API Key、密码)绝不能硬编码这个文件由 IT 管理员部署到每台开发机器上,开发者无法修改。
用户级(~/.claude/CLAUDE.md):
# 个人偏好
- 回复使用中文
- 代码注释使用英文
- 优先使用函数式编程风格
- commit message 使用 Conventional Commits 格式跨项目生效。适合放个人习惯和偏好。
项目根目录(./CLAUDE.md):
这是最重要的层级,下一节详细讲。
子目录级(./packages/api/CLAUDE.md):
# API 包约定
- 所有路由处理函数放在 routes/ 目录
- 使用 zod 做请求参数校验
- 错误响应统一使用 AppError 类
- ���据库查询使用 repository 模式
- 测试文件和源文件放在同一目录:user.service.ts → user.service.test.ts适合 Monorepo 中不同包有不同约定的场景。
项目用户级(~/.claude/projects/<hash>/CLAUDE.md):
# 个人笔记
- 当前正在重构 auth 模块,注意不要改动 legacy/ 目录
- payments 模块的测试需要 mock Stripe API
- 本地开发用 port 3001(3000 被其他项目占了)这个文件由 /memory 命��自动创建和管理,不提交到 Git。适合放个人的临时笔记和提醒。
三、该写什么:高价值内容指南
项目根目录的 CLAUDE.md 是最核心的文件。这一节讲清楚:什么内容值得写,怎么写效果最好。
3.1 构建 / 测试 / Lint 命令(最高价值)
这是 CLAUDE.md 中价值最高的内容。Claude 需要这些命令来验证自己的工作——写完代码后跑测试、跑 lint,确认没有破坏任何东西。
# 常用命令
- 构建:`npm run build`
- 开发服务器:`npm run dev`(端口 3000)
- 全量测试:`npm test`
- 单文件测试:`npm test -- path/to/file.test.ts`
- Lint:`npm run lint`
- 类型检查:`npx tsc --noEmit`
- 格式化:`npx prettier --write .`为什么这是最高价值?
没有这些命令,Claude 只能写代码然后"希望"它是对的。有了这些命令,Claude 会在写完代码后主动运行测试和 lint,发现问题立即修复。这是从"写代码"到"交付可工作的代码"的关键跨越。
进阶写法——区分不同场景:
# 命令
## 测试
- 全量测试:`npm test`
- 单元测试:`npm run test:unit`
- 集成测试:`npm run test:integration`(需要先启动数据库:`docker compose up -d db`)
- 单文件测试:`npx vitest run path/to/file.test.ts`
- 测试覆盖率:`npm run test:coverage`
## 构建
- 开发构建:`npm run build:dev`
- 生产构建:`npm run build`(会执行类型检查)
## 代码质量
- Lint:`npm run lint`
- Lint 自动修复:`npm run lint:fix`
- 类型检查:`npx tsc --noEmit`
- 格式化检查:`npx prettier --check .`3.2 代码风格和约定
只写非显而易见的、和默认不同的约定。Claude 已经知道通用的编码规范,你不需要教它"函数名用 camelCase"(除非你的项目偏偏不用)。
好的写法:
# 代码风格
- 使用具名导出(named export),不用默认导出(default export)
- React 组件用 arrow function,不用 function declaration
- 状态管理统一用 Zustand,不要引入 Redux
- CSS 使用 Tailwind,不写自定义 CSS 文件
- 错误处理用 Result 模式(neverthrow 库),不用 try-catch
- 文件命名:组件用 PascalCase(UserProfile.tsx),工具函数用 kebab-case(format-date.ts)不好的写法:
# 代码风格
- 使用 TypeScript(← 项目已经是 TS,Claude 能看到 tsconfig.json)
- 缩进用 2 空格(← .prettierrc 里已经配了)
- 使用 ESLint(← package.json 里已经有了)
- 变量命名用 camelCase(← 这是 JS/TS 的默认约定)3.3 架构概览
保持简短。Claude 能读代码,不需要你把整个架构文档复制过来。只需要给它一个"地图",让它知道去哪里找什么。
# 项目架构
Monorepo(pnpm workspace):
- `packages/api/` — Express 后端,REST API
- `packages/web/` — Next.js 前端
- `packages/shared/` — 共享类型和工具函数
- `packages/db/` — Prisma schema 和数据库迁移
API 路由结构:
- `routes/` — 路由定义(thin controller)
- `services/` — 业务逻辑
- `repositories/` — 数据库访问
- `middleware/` — Express 中间件
数据流:Route → Service → Repository → Prisma3.4 重要警告和陷阱
这类信息价值极高——它们是 Claude 不可能从代码中推断出来的"隐性知识"。
# 重要警告
- `users` 表的 `email` 字段有唯一约束,但 `profiles` 表没有——不要假设 profile.email 是唯一的
- `legacy/` 目录下的代码不要修改,它会在 Q3 被移除
- 环境变量 `DATABASE_URL` 在本地和 CI 中格式不同(本地用 localhost,CI 用 Docker 网络名)
- `payment.service.ts` 中的金额计算必须用 Decimal.js,不要用浮点数
- 修改 `schema.prisma` 后必须运行 `npx prisma generate`,否则类型不会更新3.5 Git 和工作流约定
# Git 约定
- 分支命名:`feat/xxx`、`fix/xxx`、`refactor/xxx`
- Commit message 格式:`type(scope): description`
- 例:`feat(auth): add OAuth2 login`
- 例:`fix(api): handle null response from payment gateway`
- 提交前必须通过:lint + 类型检查 + 相关测试
- 不要直接 push 到 main,走 PR 流程
- PR 标题和 commit message 格式一致3.6 测试约定
# 测试约定
- 测试文件放在 `__tests__/` 目录,命名为 `xxx.test.ts`
- 使用 Vitest + React Testing Library
- Mock 外部服务,不 mock 内部模块
- 测试描述用中文:`describe('用户登录')` / `it('应该返回 JWT token')`
- 每个 PR 必须包含对应的测试
- 集成测试使用 testcontainers 启动真实数据库3.7 技术栈摘要
当项目技术栈不是"一眼能看出来"的时候,写一个简短的摘要很有帮助:
# 技术栈
- Runtime: Node.js 20 + TypeScript 5.4
- 前端: Next.js 16 (App Router) + Tailwind CSS v4
- 后端: Express 5 + tRPC
- 数据库: PostgreSQL 16 + Prisma ORM
- 缓存: Redis 7(用于 session 和 rate limiting)
- 测试: Vitest + Playwright(E2E)
- CI/CD: GitHub Actions
- 部署: Docker + AWS ECS四、写作原则
知道该写什么之后,还要知道怎么写。CLAUDE.md 的写法直接影响 Claude 的理解效果。
4.1 简洁直接,用祈使语气
CLAUDE.md 是给 Claude 的指令,不是给人读的文档。用祈使语气,像给同事发 Slack 消息一样。
| 不好的写法 | 好的写法 |
|---|---|
| 在我们的项目中,我们通常倾向于使用具名导出而不是默认导出,因为这样有利于重构和自动导入。 | 使用具名导出,不用默认导出。 |
| 当你需要运行测试的时候,你可以使用以下命令... | 测试命令:npm test |
| 我们的团队约定是在提交代码之前先运行 lint 检查,以确保代码质量。 | 提交前运行 npm run lint。 |
4.2 优先高信号信息
把最重要的信息放在最前面。Claude 对文件开头的内容权重更高。
推荐的内容顺序:
1. 构建/测试/lint 命令(Claude 最常用)
2. 重要警告和陷阱(避免犯错)
3. 代码风格约定(保持一致性)
4. 架构概览(导航地图)
5. Git/工作流约定(协作规范)
6. 其他补充信息4.3 不要重复代码里已有的信息
Claude 能读 package.json、tsconfig.json、.eslintrc、.prettierrc 等配置文件。不需要在 CLAUDE.md 里重复这些信息。
不需要写的:
- "项目使用 TypeScript"(tsconfig.json 已经说明了)
- "缩进用 2 空格"(.prettierrc 里配了)
- "使用 ESLint"(.eslintrc 存在就说明了)
- "依赖包括 React、Next.js..."(package.json 里有)
需要写的:
- 配置文件里看不出来的约定
- 团队的隐性知识
- 工具链的非标准用法
4.4 增量更新,用 /memory 命令
不要试图一次写出完美的 CLAUDE.md。在日常使用中,当你发现 Claude 犯了某个错误或不知道某个约定时,用 /memory 命令把它记下来。
你:/memory 修改 prisma schema 后要运行 npx prisma generate
Claude:已保存到项目记忆。
这条信息会被保存到项目用户级的 CLAUDE.md(~/.claude/projects/<hash>/CLAUDE.md)。积累一段时间后,你可以把高频出现的条目整理到项目根目录的 CLAUDE.md 中,提交给团队共享。
4.5 提交到版本控制
项目根目录的 CLAUDE.md 应该提交到 Git。它是团队共享的项目知识,和 README.md、.eslintrc 一样是项目的一部分。
git add CLAUDE.md
git commit -m "docs: add CLAUDE.md for Claude Code"好处:
- 新成员 clone 项目后立即获得完整上下文
- CLAUDE.md 的变更可以在 PR 中 review
- 版本历史可追溯
4.6 Monorepo 用子目录 CLAUDE.md
在 Monorepo 中,不要把所有包的约定都塞进根目录的 CLAUDE.md。利用子目录层级:
my-monorepo/
├── CLAUDE.md # 全局约定(构建命令、Git 规范)
├── packages/
│ ├── api/
│ │ └── CLAUDE.md # API 特定约定
│ ├── web/
│ │ └── CLAUDE.md # 前端特定约定
│ └── shared/
│ └── CLAUDE.md # 共享库约定
Claude 会根据当前工作目录自动加载对应的子目录 CLAUDE.md,不会把无关的上下文混进来。
4.7 控制篇幅
CLAUDE.md 的内容会占用上下文窗口。过长的文件会:
- 浪费 token(花更多钱)
- 稀释重要信息(Claude 可能忽略关键指令)
- 增加冲突概率(内容越多越容易自相矛盾)
建议控制在 500 行以内。 如果超过了,考虑:
- 把模块特定的内容拆到子目录 CLAUDE.md
- 删除 Claude 能从代码中推断的信息
- 用"详见 docs/xxx.md"引用外部文档,而不是复制内容
五、反模式:不该做什么
知道该写什么很重要,知道不该写什么同样重要。以下是常见的 CLAUDE.md 反模式。
5.1 不要写小说
# ❌ 反模式:2000 行的 CLAUDE.md
## 项目背景
这个项目始于 2023 年,当时我们的团队只有 3 个人。最初我们选择了 React 作为前端框架,
因为团队成员对 React 比较熟悉。后来随着项目规模扩大,我们引入了 Next.js 来解决 SSR
的需求。在 2024 年初,我们进行了一次大规模重构,将状态管理从 Redux 迁移到了 Zustand...
(后面还有 1500 行)Claude 不需要知道你的项目历史。它需要的是当前的、可操作的信息。2000 行的文件浪费大量 token,而且 Claude 很可能会忽略其中的关键信息。
修正: 只保留当前有效的指令,删除历史叙述。
5.2 不要写显而易见的
# ❌ 反模式:重复已有信息
- 本项目使用 TypeScript
- 包管理器是 pnpm
- 使用 React 18
- 使用 Next.js 16
- 使用 Tailwind CSSClaude 能读 package.json 和 tsconfig.json。这五行信息它自己就能推断出来,写了等于没写,还浪费 token。
修正: 只写 Claude 推断不出来的信息,比如"用 pnpm,不要用 npm 或 yarn"(如果这是一个强制约定的话)。
5.3 不要自相矛盾
# ❌ 反模式:矛盾的指令
## 测试
- 测试文件放在 `__tests__/` 目录
## 代码规范
- 测试文件和源文件放在同一目录Claude 遇到矛盾指令时会困惑,可能随机选择一个遵循。定期审查 CLAUDE.md,确保没有冲突。
修正: 统一约定,删除矛盾的条目。
5.4 不要包含密钥或凭证
# ❌ 反模式:硬编码密钥
## 环境配置
- API Key: sk-xxxxxxxxxxxx
- Database URL: postgresql://admin:password123@prod-db.example.com/mydbCLAUDE.md 通常会提交到 Git。即使不提交,密钥也不应该出现在任何纯文本文件中。
修正: 用占位符或环境变量名代替。
# ✅ 正确写法
## 环境配置
- API Key 从环境变量 `API_KEY` 读取
- 数据库连接字符串在 `.env.local` 中配置(参考 `.env.example`)5.5 不要微管理代码格式
# ❌ 反模式:格式微管理
- 花括号放在同一行
- 逗号后面加空格
- 字符串用单引号
- 行尾不加分号
- 对象最后一个属性加尾逗号
- import 语句按字母排序这些事情应该交给 Prettier、ESLint 等工具。在 CLAUDE.md 里写格式规则是低效的——Claude 可能遵循也可能不遵循,而且你已经有工具来强制执行了。
修正: 配置好 Prettier/ESLint,在 CLAUDE.md 里只写"提交前运行 npm run lint:fix"。如果你配了 Hooks,连这句都不用写——Hook 会自动格式化。
5.6 不要当文档用
# ❌ 反模式:把 CLAUDE.md 当 README
## 安装步骤
1. 克隆仓库
2. 安装依赖:npm install
3. 复制环境变量:cp .env.example .env.local
4. 启动开发服务器:npm run dev
5. 打开浏览器访问 http://localhost:3000
## API 文档
### GET /api/users
返回用户列表...CLAUDE.md 是给 Claude 的指令,不是给人读的文档。安装步骤放 README.md,API 文档放 Swagger/OpenAPI。
修正: 只保留 Claude 需要的命令(npm run dev、npm test),删除面向人类的教程内容。
5.7 不要放动态或频繁变化的信息
# ❌ 反模式:动态信息
- 当前 Sprint 目标:完成用户模块重构
- 待修复 Bug:#123, #456, #789
- 下次发布日期:2026-03-25这些信息很快就会过时。过时的信息比没有信息更糟糕——它会误导 Claude。
修正: 动态信息放在 Issue Tracker 或项目管理工具中。如果需要 Claude 知道当前任务,在对话中直接告诉它。
六、CLAUDE.md 与 Memory 系统
6.1 /memory 命令
Claude Code 有一个内置的记忆系统,通过 /memory 命令使用:
你:/memory 这个项目的测试需要先启动 Docker
Claude:已保存到项目记忆。
/memory 命令会把信息保存到项目用户级 CLAUDE.md:
~/.claude/projects/<project-hash>/CLAUDE.md
这个文件:
- 按项目隔离(不同项目有不同的 hash)
- 不提交到 Git(是你的个人笔记)
- 每次会话自动加载
6.2 自动记忆建议
除了手动 /memory,Claude 有时会主动建议保存某些信息。比如当你纠正了 Claude 的一个错误时,它可能会说:
Claude:明白了,这个项目用 Vitest 而不是 Jest。要我把这个保存到记忆中吗?
你:好的
Claude:已保存。下次我会记住使用 Vitest。
这个机制让 CLAUDE.md 可以渐进式完善——你不需要一开始就写出完美的文件,在日常使用中逐步积累就好。
6.3 会话上下文 vs 持久记忆
理解三种"Claude 知道的信息"的区别:
| 类型 | 来源 | 生命周期 | 优先级 |
|---|---|---|---|
| 会话上下文 | 当前对话中你说的话 | 会话结束即消失 | 最高 |
| CLAUDE.md | 各层级的 CLAUDE.md 文件 | 持久存在 | 中 |
| 代码上下文 | Claude 读取的代码文件 | 按需加载 | 最低 |
优先级规则: 如果你在对话中说"用 Jest 测试",但 CLAUDE.md 里写的是"用 Vitest 测试",Claude 会遵循你在对话中的指令。聊天指令 > CLAUDE.md > 代码推断。
6.4 什么时候用哪种方式
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 团队统一的编码规范 | 项目根目录 CLAUDE.md | 提交到 Git,团队共享 |
| 个人编码偏好 | 用户级 CLAUDE.md | 跨项目生效 |
| 项目中你个人的笔记 | /memory 命令 | 不影响团队 |
| 临时的一次性指令 | 直接在对话中说 | 不需要持久化 |
| 模块特定的约定 | 子目录 CLAUDE.md | 按需加载,不污染全局 |
| 公司强制规范 | Enterprise CLAUDE.md | 不可覆盖 |
6.5 从 Memory 到 CLAUDE.md 的工作流
推荐的渐进式工作流:
1. 日常使用中,用 /memory 记录发现的问题和约定
2. 定期(比如每周)review ~/.claude/projects/<hash>/CLAUDE.md
3. 把高频出现的、团队通用的条目移到项目根目录 CLAUDE.md
4. 提交 PR,让团队 review
5. 清理项目用户级中已经移到根目录的条目
这样 CLAUDE.md 就是一个活的文档,随着项目演进不断完善。
七、实战示例:Next.js 全栈项目
7.1 项目背景
假设你在一个 Next.js 全栈项目中工作:
- 技术栈:Next.js 16 (App Router) + Prisma + tRPC + Tailwind CSS v4
- Monorepo 结构(pnpm workspace)
- 团队 4 人,使用 GitHub 协作
- 前后端在同一个仓库
7.2 项目根目录 CLAUDE.md(团队共享)
./CLAUDE.md(提交到 Git,约 60 行):
# 项目指令
## 命令
- 安装依赖:`pnpm install`
- 开发服务器:`pnpm dev`(端口 3000)
- 全量测试:`pnpm test`
- 单文件测试:`pnpm test -- --run path/to/file.test.ts`
- Lint:`pnpm lint`
- 类型检查:`pnpm typecheck`
- 数据库迁移:`pnpm db:migrate`
- 数据库 seed:`pnpm db:seed`
- 生成 Prisma Client:`pnpm db:generate`
## 架构
Monorepo(pnpm workspace):
- `apps/web/` — Next.js 16 前端(App Router)
- `apps/api/` — tRPC 路由和业务逻辑
- `packages/db/` — Prisma schema、迁移、seed
- `packages/ui/` — 共享 UI 组件(Tailwind CSS v4)
- `packages/shared/` — 共享类型和工具函数
## 代码风格
- 使用具名导出,不用默认导出(Next.js page/layout 除外)
- React 组件用 arrow function
- 服务端组件优先,只在需要交互时用 'use client'
- 状态管理用 Zustand(不用 Context 做全局状态)
- 表单用 react-hook-form + zod 校验
- 日期处理用 date-fns,不用 moment
## 重要警告
- 修改 `packages/db/prisma/schema.prisma` 后必须运行 `pnpm db:generate`
- `apps/web/app/` 下的 page.tsx 和 layout.tsx 必须用默认导出
- tRPC router 定义在 `apps/api/src/routers/`,不要在 web 端定义
- 环境变量分两种:`NEXT_PUBLIC_*`(客户端可见)和普通变量(仅服务端)
- Tailwind v4 不用 tailwind.config.js,配置在 CSS 文件中
## Git 约定
- 分支:`feat/xxx`、`fix/xxx`、`refactor/xxx`
- Commit:`type(scope): description`(英文)
- scope 用包名:`feat(web): add login page`
- 提交前确保 `pnpm lint` 和 `pnpm typecheck` 通过
## 测试
- 使用 Vitest + React Testing Library
- 测试文件:`xxx.test.ts(x)`,放在 `__tests__/` 目录
- Mock 外部 API,不 mock 内部模块
- 数据库相关测试用 `@testcontainers/postgresql`7.3 子目录 CLAUDE.md(API 特定约定)
./apps/api/CLAUDE.md:
# API 约定
## 路由结构
- `src/routers/` — tRPC router 定义
- `src/services/` — 业务逻辑(一个 service 对应一个领域)
- `src/repositories/` — 数据库查询(封装 Prisma 调用)
## 数据流
Router(输入校验)→ Service(业务逻辑)→ Repository(数据库)
## 规范
- 每个 router 文件导出一个 `xxxRouter`
- 输入校验用 zod schema,定义在 router 文件中
- Service 方法不直接调用 Prisma,通过 Repository
- 错误处理用 `TRPCError`,不要 throw 普通 Error
- 所有数据库查询必须有 `select` 或 `include`,不要 `select: undefined`(防止返回敏感字段)
## 新增 API 的步骤
1. 在 `src/routers/` 创建或修改 router
2. 在 `src/services/` 实现业务逻辑
3. 在 `src/repositories/` 实现数据库查询
4. 在 `src/routers/_app.ts` 注册 router
5. 运行 `pnpm test -- --run apps/api/` 确认测试通过7.4 用户级 CLAUDE.md(个人偏好)
~/.claude/CLAUDE.md:
# 个人偏好
- 回复使用中文
- 代码注释使用英文
- commit message 使用英文
- 优先使用函数式风格,避免 class
- 解释技术决策时给出简短理由7.5 项目用户级 Memory(个人笔记)
~/.claude/projects/<hash>/CLAUDE.md(由 /memory 命令创建)��
# 项目笔记
- 本地 PostgreSQL 跑在 Docker 里:`docker compose up -d db`
- payments 模块正在重构,暂时不要改 `src/services/payment.legacy.ts`
- 跑 E2E 测试前需要 seed 数据库:`pnpm db:seed`
- 张三负责 auth 模块,有问题找他7.6 合并后的效果
当你在 apps/api/ 目录下工作时,Claude 看到的完整上下文:
[用户级] 回复中文、代码注释英文、函数式风格...
[项目根目录] pnpm install、Monorepo 架构、代码风格、Git 约定...
[子目录级] tRPC 路由结构、数据流、API 规范...
[项目用户级] 本地 Docker、payments 重构中...
当你切换到 apps/web/ 目录工作时,子目录级的内容会自动切换为 apps/web/CLAUDE.md(如果存在的话),API 的约定不会干扰前端的工作。
这就是多层 CLAUDE.md 的威力:全局约定统一,局部上下文精准,个人偏好不影响团队。
八、进阶模式
8.1 条件指令
你可以在 CLAUDE.md 中写条件性的指令,让 Claude 在特定场景下遵循特定规则:
# 条件指令
写测试时:
- 总是先写测试描述(describe/it),再写实现
- 每个测试只验证一个行为
- 使用 Arrange-Act-Assert 模式
写 API 路由时:
- 总是添加输入校验(zod schema)
- 总是处理错误情况
- 总是返回统一的响应格式
做代码审查时:
- 关注安全问题(SQL 注入、XSS、敏感数据泄露)
- 检查错误处理是否完整
- 检查是否有性能问题(N+1 查询、不必要的重渲染)
重构时:
- 不要改变公共 API 的签名
- 每次只重构一个模块
- 重构后运行完整测试套件Claude 会根据当前任务的上下文自动匹配相关的条件指令。
8.2 引用外部文档
当某个主题的信息太多,不适合全部放在 CLAUDE.md 中时,用引用的方式:
# 架构
整体架构概览见本文件。详细的架构决策记录(ADR)在 `docs/adr/` 目录。
数据库 schema 设计见 `packages/db/prisma/schema.prisma`。
API 接口文档见 `docs/api.md`。
部署流程见 `docs/deployment.md`。Claude 在需要时会主动去读这些文件。你不需要把内容复制到 CLAUDE.md 中——只需要告诉 Claude 去哪里找。
8.3 团队入职加速
CLAUDE.md 的一个隐藏价值是加速新成员入职。
新成员 clone 项目后,CLAUDE.md 立即提供:
- 怎么构建和运行项目
- 代码风格和约定
- 架构概览
- 常见陷阱
这比口头传授或翻阅 Wiki 高效得多。而且 Claude Code 可以基于这些信息回答新成员的问题:
新成员:这个项目怎么跑测试?
Claude:(读取 CLAUDE.md)运行 `pnpm test`。单文件测试用 `pnpm test -- --run path/to/file.test.ts`。
注意:数据库相关的测试需要先启动 Docker:`docker compose up -d db`。
8.4 CI/CD 集成
Claude Code 支持 headless 模式(非交互式),可以在 CI/CD 流水线中使用。在这种模式下,Claude 同样会读取 CLAUDE.md。
# .github/workflows/claude-review.yml
name: Claude Code Review
on: [pull_request]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Claude Review
run: |
claude --headless "Review the changes in this PR. \
Check for code style violations, potential bugs, \
and missing tests." \
--settings .claude/ci-settings.jsonCLAUDE.md 中的约定会指导 Claude 的 review 标准。比如你写了"错误处理用 Result 模式",Claude 在 review 时就会检查是否有人用了 try-catch。
8.5 Monorepo 策略
大型 Monorepo 的 CLAUDE.md 策略:
monorepo/
├── CLAUDE.md # 全局:workspace 命令、Git 约定、CI 流程
├── apps/
│ ├── web/
│ │ └── CLAUDE.md # 前端:组件规范、路由约定、状态管理
│ ├── mobile/
│ │ └── CLAUDE.md # 移动端:平台差异、导航结构
│ └── admin/
│ └── CLAUDE.md # 管理后台:权限模型、表格组件用法
├── packages/
│ ├── api/
│ │ └── CLAUDE.md # API:路由结构、认证、错误处理
│ ├── db/
│ │ └── CLAUDE.md # 数据库:迁移流程、命名约定
│ └── ui/
│ └── CLAUDE.md # UI 库:组件 API 设计原则、样式约定
根目录 CLAUDE.md 的原则:
- 只放全局通用的信息
- 不超过 100 行
- 引导 Claude 去子目录找具体约定
子目录 CLAUDE.md 的原则:
- 只放该模块特有的信息
- 不重复根目录已有的内容
- 包含该模块的构建/测试命令(如果和全局不同)
8.6 版本控制最佳实践
把 CLAUDE.md 当作代码一样管理:
# 在 PR 中 review CLAUDE.md 的变更
## 好的 PR 示例
标题:docs(claude): add API error handling convention
变更:在 apps/api/CLAUDE.md 中添加错误处理约定
## Review 检查清单
- [ ] 新增的指令是否和现有指令冲突?
- [ ] 是否有可以从代码推断的冗余信息?
- [ ] 篇幅是否合理?
- [ ] 是否包含敏感信息?推荐的 Git 工作流:
- 在日常使用中通过
/memory积累改进点 - 定期整理,提交 CLAUDE.md 的更新 PR
- 团队 review——CLAUDE.md 的变更和代码变更一样重要
- 合并后,所有人的 Claude Code 立即生效
九、常见问题
Q1:CLAUDE.md 和 README.md 有什么区别?
README.md 是给人读的——项目介绍、安装步骤、使用说明。CLAUDE.md 是给 Claude 读的——编码指令、构建命令、项目约定。
两者可能有少量重叠(比如构建命令),但目的完全不同。不要把 CLAUDE.md 当 README 写,也不要用 README 代替 CLAUDE.md。
Q2:CLAUDE.md 支持什么格式?
纯 Markdown。支持标题、列表、代码块、表格等标准 Markdown 语法。Claude 对 Markdown 的理解很好,合理使用格式可以提高可读性。
不支持的:
- 图片(Claude 不会渲染 Markdown 中的图片链接)
- HTML 标签(会被当作纯文本)
- 动态内容(不支持变量替换或模板语法)
Q3:CLAUDE.md 有大小限制吗?
没有硬性限制,但有实际限制——它会占用上下文窗口。建议:
| 层级 | 建议行数 | 原因 |
|---|---|---|
| 项目根目录 | 50-150 行 | 核心信息,每次都加载 |
| 子目录级 | 20-50 行 | 模块特定,按需加载 |
| 用户级 | 10-30 行 | 个人偏好,简短即可 |
| 项目用户级 | 10-30 行 | 临时笔记,定期清理 |
| 所有层级合计 | < 500 行 | 控制总 token 消耗 |
如果你的项目根目录 CLAUDE.md 超过 200 行,认真考虑拆分到子目录或删除冗余内容。
Q4:多人协作时 CLAUDE.md 冲突怎么办?
和代码冲突一样处理——Git merge 时解决。因为 CLAUDE.md 通常是追加式修改(添加新条目),冲突概率不高。
减少冲突的技巧:
- 每个条目独占一行
- 用清晰的分节(## 标题)
- 避免频繁修改已有条目
- 大的变更走 PR review
Q5:Claude 真的会遵循 CLAUDE.md 里的所有指令吗?
大部分情况下会。但有几个注意点:
- 指令越具体,遵循率越高。"用 Vitest 测试"比"写好测试"有效得多。
- 指令越靠前,权重越高。把最重要的放在文件开头。
- 矛盾的指令会降低遵循率。Claude 遇到矛盾时可能随机选择。
- 对话中的指令优先级更高。如果你在对话中说了和 CLAUDE.md 矛盾的话,Claude 会遵循对话。
- 过长的文件会稀释重要指令。500 行以内效果最好。
Q6:可以在 CLAUDE.md 中引用其他文件吗?
不能直接 #include 或 import。但你可以写"详见 docs/xxx.md",Claude 在需要时会主动去读取那个文件。
# 架构详情见 docs/architecture.md
# 数据库 schema 见 packages/db/prisma/schema.prisma
# API 错误码定义见 packages/shared/src/error-codes.ts这是一种"懒加载"模式——CLAUDE.md 提供索引,Claude 按需读取详细内容。
Q7:项目用户级的 CLAUDE.md 路径中的 hash 是怎么算的?
hash 基于项目的绝对路径生成。你不需要手动管理这个路径——/memory 命令会自动处理。如果你想查看或编辑它,可以在 Claude Code 中问"我的项目记忆文件在哪里"。
Q8:从零开始,CLAUDE.md 应该先写什么?
如果你刚开始使用 Claude Code,按这个优先级写:
# 第一步:只写命令(5 分钟搞定)
- 构建:`npm run build`
- 测试:`npm test`
- Lint:`npm run lint`
# 第二步:加上关键警告(遇到问题时补充)
- 修改 schema 后要运行 generate
- 不要改 legacy/ 目录
# 第三步:逐步完善(日常使用中积累)
- 用 /memory 记录 Claude 犯的错
- 定期整理到 CLAUDE.md不要试图一次写出完美的 CLAUDE.md。先写 5 行,比不写强 10 倍。
总结
CLAUDE.md 的核心就三件事:
- 写对的内容——构建命令、关键警告、非显而易见的约定。这些是 Claude 无法从代码中推断的高价值信息。
- 用对的方式写——简洁、直接、祈使语气。不写小说,不重复已有信息,控制在 500 行以内。
- 用对的层级——团队约定放项目根目录(提交 Git),个人偏好放用户级,临时笔记用
/memory,模块细节放子目录。
记住:CLAUDE.md 是你获得好结果最重要的杠杆。先写 5 行命令,然后在日常使用中逐步完善。
推荐阅读
- Claude Code 进阶指南 — 从零开始的完整入门
- Claude Code settings.json 完全指南 — CLAUDE.md 的搭档,管"怎么做"
- 上下文管理指南 — 管好上下文,让 CLAUDE.md 更高效
- Claude Code Hooks 指南 — 用 Hooks 自动化代码格式化等重复工作
- 高效 Prompt 指南 — 配置好 CLAUDE.md 后,写好 Prompt 是下一步
- 自定义 Slash Commands 指南 — 把常用操作变成一键命令
- MCP Server 深度指南 — 用 MCP 扩展 Claude Code 的能力