Skip to content

第 04 章 CLAUDE.md 与上下文入门

版本基准:2026-07-08 / v2.1.202+

1. 结论先行

CLAUDE.md 是 Claude Code 的持久上下文文件——你把项目的「技术栈、代码规范、常用命令、架构约束、安全红线」一次性写进去,之后每一次对话都会自动加载。它的价值不是配置本身,而是工程纪律的第一块基石:让 Agent 不用你每次重复说明就能在同一套规则下工作。

本章解决三个问题:CLAUDE.md 怎么分层加载、怎么写好一份、怎么与 Claude Code 的另一套记忆系统(Auto Memory)协作。

2. 为什么需要持久上下文

每次对话重复说明的代价

Claude 是无状态的——每一次新对话、每一次 /clear 之后,模型对你项目的认知归零。如果没有持久上下文,你必须每次重复告诉它:

  • 「我们用的是 NestJS 10 + TypeORM + PostgreSQL 16」
  • 「数据库操作放 Repository,Controller 只做参数校验」
  • 「测试用 Jest,单测跑 npm test -- --testPathPattern=auth
  • 「不要用 .then(),用 async/await」

这些信息每多重复一次,就消耗一次 token、增加一轮误解的概率。更严重的是,Agent 在不被告知约束时会按通用习惯行事——它可能写出 .then() 链、把 SQL 拼接进 Controller、用原生 Error——而这些恰恰是你最不希望的。

CLAUDE.md 预加载的收益

写一份 CLAUDE.md 之后:

  • 首次启动即知情:Claude 进入项目目录就知道技术栈、目录结构、验证命令,省去 5–10 分钟的探索。
  • 规则统一:所有对话在同一套代码规范下生成,不再出现「这次让用 async/await、下次又冒出 .then()」的摇摆。
  • /clear 后不丢规则:清空上下文只清对话历史,不清 CLAUDE.md。规则跨会话持久。
  • 多人协作对齐:把 CLAUDE.md 提交到 Git,团队成员的 Claude 都加载同一份规则,相当于「机器可读的编码规范」。

工程上的核心价值:把约束写下来,比每次口头强调更可靠。这与人类团队里「写进 CONTRIBUTING.md」的逻辑一致——口头规则会随人员变动失效,文档规则不会。

3. 两套记忆系统

Claude Code 有两套记忆系统,职责不同,必须分清。

维度CLAUDE.md(手写指令)Auto Memory(自动记录)
存储位置项目根 ./CLAUDE.md~/.claude/CLAUDE.md 等四级层级~/.claude/projects/<project>/memory/
内容性质你主动写下的规则、约束、命令Claude 在对话中学习到的事实、决策、用户偏好
加载方式每次启动全量加载到上下文MEMORY.md 为索引,首 200 行或 25KB 加载
维护方式人工编辑,提交到 GitClaude 自动写入,用户可 /memory 查看/切换
适合内容稳定的项目规则、代码规范、架构易变的项目状态、用户习惯、踩坑记录、决策原因
生命周期项目级,长期跨会话累积,可手动清理

什么时候用哪个

写进 CLAUDE.md:当信息是「规则」——你希望 Claude 每次都遵守的硬约束。例如:

  • 「数据库操作必须用参数化查询,禁止字符串拼接」
  • 「改 src/ 后必须跑 python src/rag.py "测试问题" 验证」
  • 「API 响应格式统一为 { code, data, message }

交给 Auto Memory:当信息是「事实」或「偏好」——Claude 在工作中观察到的、不需要你每次重复的。例如:

  • 「用户偏好用 cursor-based pagination 而非 offset」
  • 「上次重构决策记录在 docs/adr/002.md
  • 「测试数据库连接串在 .env.test,不要改」

简单判断法:能写成团队规范的进 CLAUDE.md,只在某次对话中成立的临时状态留给 Auto Memory

注意:Auto Memory 不应记录代码规范(代码规范写在 CLAUDE.md 里更稳定)。它的价值是记录那些「代码推导不出来、但对话中反复有用」的非显而易见信息。

4. CLAUDE.md 分层加载

Claude Code 按四级层级加载 CLAUDE.md,从广到细,后者补充(而非简单覆盖)前者。

四级层级与加载顺序

1. Managed policy   /Library/Application Support/ClaudeCode/CLAUDE.md
                   (企业/组织级,最高优先级,通常由 IT 部署)

2. User             ~/.claude/CLAUDE.md
                   (用户全局,所有项目共享,个人偏好与通用纪律)

3. Project          ./CLAUDE.md  或  ./.claude/CLAUDE.md
                   (项目级,提交到 Git,团队共享)

4. Local            ./CLAUDE.local.md
                   (本地级,gitignore,个人临时覆盖)

四份文件全部都会加载,不是「后者覆盖前者」。它们在上下文里按层级拼接,Claude 同时看到所有层级的内容。当规则冲突时,更细粒度(更靠近 Local)的指令优先;但默认情况下四级应该互补,不冲突。

各级该放什么

层级放什么典型示例
Managed policy组织强制规则、合规要求、安全红线「禁止把生产数据写入测试环境」「所有 PR 必须有 SAST 扫描通过」
User跨项目通用的个人偏好、沟通风格、思维原则「结论先行」「代码用英文、对话用中文」「禁止谄媚废话」
Project项目级技术栈、代码规范、架构、命令、目录「NestJS 10 + TypeORM + PostgreSQL」「测试命令 npm test
Local本机临时覆盖、个人实验、未定稿「今天先用 Node 18 测试,正式用 20」「我本机的 db host 是 localhost:5433」

核心原则:越靠下的层级越个人化、越易变;越靠上的层级越稳定、越共享。User 级写你这个人是谁、怎么沟通;Project 级写这个项目怎么干活;Local 级写你本机的临时差异。

进入子目录时的加载

当你在项目根目录下进入子目录工作(例如 cd src/modules/auth),Claude 会额外加载该子目录的 CLAUDE.md(如果存在)。子目录级规则只在该目录下生效,适合给特定模块加专属约束。例如:

src/modules/payment/CLAUDE.md    ← 支付模块的专属规则(PCI 合规、加密要求)
src/modules/auth/CLAUDE.md       ← 认证模块的专属规则(JWT 过期、刷新策略)

5. 高级语法

5.1 @import 引用其他文件

CLAUDE.md 支持用 @path/to/file 引用其他文件,被引用文件的内容会一并加载到上下文。

markdown
# CLAUDE.md

@docs/architecture.md
@docs/coding-standards.md
@docs/api-conventions.md

适合把长规则拆成多个文件,按主题组织。例如把「API 设计规范」「Git 工作流」「数据库迁移规则」分别维护,在 CLAUDE.md 里统一 import。

递归深度限制:@import 支持嵌套,最深 4 层递归。即 A 引用 B、B 引用 C、C 引用 D 是允许的;再深一层会被截断。设计时避免过深的引用链——四层嵌套通常意味着规则组织得太碎,应该合并。

5.2 .claude/rules/ 条件规则

对于只在特定路径下生效的规则,用 .claude/rules/ 目录下的规则文件,通过 frontmatter 的 paths 字段做 glob 匹配。

.claude/
  rules/
    frontend.rules.md      ← 只对前端文件生效
    backend.rules.md       ← 只对后端文件生效
    test.rules.md          ← 只对测试文件生效

frontend.rules.md 示例:

markdown
---
paths:
  - "web/src/**"
  - "*.tsx"
  - "*.ts"
---

# 前端规则

- 使用函数组件 + Hooks,禁止 class 组件
- 样式用 Tailwind CSS,不写自定义 CSS
- API 调用统一走 web/src/api/,不在组件里直接 fetch
- 状态管理用 Zustand,不用 Redux

backend.rules.md 示例:

markdown
---
paths:
  - "server/**/*.go"
---

# 后端规则

- 遵循 Effective Go
- 错误用 fmt.Errorf + %w 包装,禁止吞错误
- 数据库操作放 repository 层
- 所有 SQL 用参数化查询

条件规则的好处:前端规则不污染后端上下文。全栈项目里前端和后端规则经常冲突(例如前端用 camelCase、后端用 snake_case),全量加载会让 Claude 困惑;按路径加载让规则只在相关文件上生效。

5.3 AGENTS.md 兼容

Claude Code 兼容开源的 AGENTS.md 规范。两种使用方式:

方式一:@AGENTS.md 导入

如果项目已有 AGENTS.md(其他工具也在用),在 CLAUDE.md 里引用即可:

markdown
# CLAUDE.md

@AGENTS.md

方式二:符号链接

bash
ln -s AGENTS.md CLAUDE.md

CLAUDE.md 直接指向 AGENTS.md,两者完全同步。适合团队同时用 Claude Code 和其他支持 AGENTS.md 的工具(如 Cursor、Codex),只维护一份规则文件。

6. 该写什么 / 不该写什么

该写

  1. 项目概述:一两句话说明这是什么项目、给谁用。
  2. 技术栈:版本要写具体,因为不同版本 API 差异大(NestJS 8 和 10 的写法不同)。
  3. 常用命令:开发、测试、构建、迁移、lint——给完整可复制的命令。
  4. 代码规范:命名、错误处理、分层职责、禁止的写法。
  5. 架构约束:模块边界、通信方式、认证要求、分页策略。
  6. 目录结构:每个关键目录的职责,避免 Claude 把文件放错位置。
  7. 安全注意:密钥处理、SQL 注入防护、用户输入校验。

不该写

  1. 代码片段:CLAUDE.md 不是代码仓库。具体实现放代码文件里,规则只写「应该怎么做」。
  2. 可从代码推导的文件路径:写「config.py 是唯一配置入口」有用;写「src/utils/format.ts 里有 formatDate 函数」没用——Claude 自己能搜到,而且这种信息会过时。
  3. 临时状态:「今天在修 bug #123」「正在重构 auth 模块」——这种是 Auto Memory 的职责,写进 CLAUDE.md 会在 bug 修完后变成过时信息。
  4. 完整文档:API 文档、设计文档不该塞进 CLAUDE.md,用 @import 引用即可。
  5. 密钥、Token、连接串:绝对禁止。CLAUDE.md 通常提交到 Git,密钥进了 Git 历史就无法清除。

建议长度:每个文件 < 200 行

CLAUDE.md 每次启动全量加载到上下文,过长会持续占用 token 预算。建议:

  • 单个 CLAUDE.md 控制在 200 行以内。
  • 超过就拆分:长规则拆到 docs/ 下用 @import 引用;模块专属规则拆到 .claude/rules/
  • 一份好的 CLAUDE.md 读起来像「新人入职第一天的 README」——精炼、可执行、不啰嗦。

7. /init 自动生成 + /memory 查看

/init:一键生成初始 CLAUDE.md

进入一个新项目,先跑:

/init

Claude 会分析项目结构(package.jsongo.mod、目录树、配置文件、已有文档),自动生成一份初始 CLAUDE.md,包含:

  • 检测到的技术栈
  • 推断的常用命令
  • 目录结构概述
  • 基础代码规范建议

这份初始文件是草稿,不是终稿。生成后你应该手动修正:

  • 删掉 Claude 猜错的部分
  • 补充项目特有的架构约束
  • 加入安全红线和验证闭环要求
  • 调整为团队习惯的命名和分层

/init 适合冷启动。已有 CLAUDE.md 的项目不用再跑——它不会智能合并,而是覆盖。

/memory:查看所有加载文件

/memory

执行后会列出当前会话加载的所有上下文文件:

  • 四级 CLAUDE.md 的实际路径(哪些存在、哪些缺失)
  • @import 引用的所有文件
  • .claude/rules/ 下生效的条件规则
  • Auto Memory 的状态(开/关、当前项目记录条数)

/memory 还可以切换 Auto Memory 开关。当你发现 Claude 把不该记的东西写进 Auto Memory,或者 Auto Memory 内容过时干扰判断时,可以临时关闭。

调试上下文问题的第一步永远是 /memory。如果 Claude 行为异常(不遵守规则、规则冲突、加载了奇怪的内容),先看 /memory 确认实际加载了什么,再决定是改 CLAUDE.md 还是清理 Auto Memory。

8. 完整 CLAUDE.md 示例

以下是一个 SaaS 数据分析平台项目的完整 CLAUDE.md,涵盖该写的所有要素。可直接复制修改使用。

markdown
# CLAUDE.md

## 1. 项目概述
B2B SaaS 数据分析平台,支持自定义看板、实时数据流和多人协作。
面向企业数据团队,多租户架构,按 workspace 隔离。

## 2. 技术栈
- Frontend: React 18 + TypeScript 5 + Tailwind CSS + Zustand
- Backend: Go 1.22 + Gin + GORM
- Database: PostgreSQL 16(业务库) + ClickHouse(分析查询)
- Queue: Kafka 3.5
- Cache: Redis 7
- Testing: Vitest(前端) + Go testing(后端)
- Deploy: Docker Compose + Kubernetes

## 3. 常用命令
```bash
# 前端
cd web && npm run dev              # 开发服务器
cd web && npm test                 # 全量前端测试
cd web && npm test -- auth         # 单模块测试
cd web && npm run build            # 构建

# 后端
cd server && go run ./cmd/api      # 开发服务器
cd server && go test ./...         # 全量后端测试
cd server && go test ./internal/auth/...  # 单包测试

# 全局
make test                          # 跑前后端所有测试
make migrate                       # 数据库迁移
make lint                          # 全量 lint
docker compose up -d               # 本地起依赖(PG/ClickHouse/Redis/Kafka)
```

## 4. 代码规范
- TypeScript: strict mode,禁止 any,禁止 @ts-ignore
- Go: 遵循 Effective Go,错误用 fmt.Errorf + %w 包装,禁止 _ = err
- React: 函数组件 + Hooks,禁止 class 组件;状态用 Zustand,不用 Redux
- API 响应格式统一: `{ code: number, data: T, message: string }`
- 变量命名: 代码用 camelCase,数据库字段用 snake_case
- 错误处理: 不吞错误,不裸 panic,业务错误用自定义 AppError

## 5. 架构约束
- 模块间通过接口通信,不直接 import 其他模块的 Service 实现
- 所有 API 端点需要认证(除 /auth/login 和 /auth/register)
- 分页统一用 cursor-based,不用 offset
- Controller 层只做参数校验和响应格式化,业务逻辑在 Service 层
- 数据库操作只在 Repository 层,禁止在 Controller/Service 里写 SQL
- 跨 workspace 的查询必须带 workspace_id 过滤

## 6. 目录结构
```
web/src/
  pages/           页面组件
  hooks/           自定义 Hooks
  api/             API 调用层(统一入口,组件不直接 fetch)
  stores/          Zustand stores
  components/      通用组件

server/
  cmd/api/         程序入口
  internal/
    handler/       HTTP 处理器
    service/       业务逻辑
    repository/    数据库操作
    model/         数据模型
    middleware/    中间件(auth、logging、ratelimit)
  migrations/      数据库迁移脚本
```

## 7. 验证闭环
- 改 server/ 代码后:`cd server && go test ./...` 必须通过
- 改 web/ 代码后:`cd web && npm test && npm run build` 必须通过
- 改数据库 schema 后:`make migrate` 必须成功,且向后兼容
- 禁止「只改不验」,禁止用 @ts-ignore 或 _ = err 绕过报错

## 8. 安全注意
- API Key、数据库连接串、JWT secret 只从环境变量读,禁止硬编码
- 所有 SQL 必须参数化,禁止字符串拼接
- 用户输入在 handler 层校验(用 validator)
- 日志禁止打印用户密码、token、PII 数据
- 跨 workspace 操作必须校验权限
- .env 文件不提交 Git,仅保留 .env.example

这份 CLAUDE.md 约 80 行,覆盖了所有该写的要素。它能让 Claude 在进入项目时立即知道:用什么技术、怎么跑命令、怎么写代码、哪些事不能做、改完怎么验证。

9. 失败边界

CLAUDE.md 不是越多越好。三种典型失败模式:

9.1 过长,持续占用上下文

CLAUDE.md 每次启动全量加载,长文件持续吃 token。一份 500 行的 CLAUDE.md 可能占用数千 token,每轮对话都付出成本。

症状:对话后期 Claude 开始「忘记」你刚才说的话——因为上下文被 CLAUDE.md 占满,留给对话历史的窗口变小。

对策:

  • 单文件 < 200 行。
  • 长规则拆到 docs/@import 引用。
  • 模块专属规则拆到 .claude/rules/,按路径加载。
  • 定期用 /memory 检查实际加载了多少。

9.2 过时信息误导

CLAUDE.md 写了「用 NestJS 8」,但项目已经升级到 10——Claude 会按 8 的写法生成代码,导致编译错误或用了废弃 API。

症状:Claude 生成的代码引用了不存在的 API、用了已废弃的写法、放错了文件位置。

对策:

  • 规则变更顺序:先改 CLAUDE.md,再改代码实践。升级依赖时第一时间同步 CLAUDE.md。
  • 把会变的具体版本号写清楚(「NestJS 10」比「NestJS」好),升级时强制 review CLAUDE.md。
  • 删掉所有「可从代码推导」的内容——版本号升级时代码会变,但 CLAUDE.md 不会自动更新,这种信息是过时的温床。
  • 把易变的临时状态交给 Auto Memory,不写进 CLAUDE.md。

9.3 把密钥写进去

这是最严重的失败。CLAUDE.md 通常提交到 Git,密钥一旦进入 Git 历史,即使后续删除也永久留存,需要 force push 清理——而 force push 本身就是高风险操作。

症状:Git 历史里出现 ANTHROPIC_API_KEY=sk-...、数据库连接串带密码、JWT secret 明文。

对策:

  • CLAUDE.md 里只写规则(「密钥从环境变量读」),不写值
  • .env.example 给模板,真实值放 .env(gitignore)。
  • .gitignore 必须包含 .envCLAUDE.local.md*.local.json
  • 如果已经泄露,立即轮换密钥——清理 Git 历史无法撤销已发生的泄露。

小结

CLAUDE.md 的本质是把「每次都要重复说的规则」沉淀成文件。它不是配置,是工程纪律——你写得多认真,Claude 就有多稳定。掌握三个要点即可:

  1. 分层:四级层级各司其职,User 管个人偏好,Project 管项目规则,Local 管临时覆盖。
  2. 精炼:单文件 < 200 行,长规则拆 @import,模块规则拆 .claude/rules/
  3. 闭环:规则变更先改 CLAUDE.md 再改代码;改完代码必须跑 CLAUDE.md 里写的验证命令。

下一章将进入 Hooks 与自动化——如何让 Claude Code 在特定事件触发时自动执行命令,把「验证闭环」从口头规则变成强制执行的系统。


下一章:权限模型入门 | 返回目录