Appearance
Claude Code 的 CLAUDE.md 遵循两种不同的加载机制:从当前目录向上找到的所有祖先 CLAUDE.md 在启动时立即加载;子目录的 CLAUDE.md 则只在 Claude 操作该目录的文件时才懒加载。正确理解这两种机制是组织 monorepo 项目指令的基础。
Claude Code Memory 深度解析:CLAUDE.md 在单体仓库中的加载机制
什么是 CLAUDE.md
CLAUDE.md 是 Claude Code 的持久上下文文件,用来告诉 Claude 项目规范、代码风格、测试命令、常见陷阱等。它是对 Claude 输出质量影响最大的单一配置文件,相当于每次对话开始前 Claude 必读的"工作手册"。
CLAUDE.md 可以放在多个位置,每个位置有不同的作用范围:
~/.claude/CLAUDE.md:全局个人配置,适用于所有项目<项目根目录>/CLAUDE.md:项目级共享配置,提交到 git 供团队使用<项目根目录>/CLAUDE.local.md:项目级个人配置,加入 .gitignore<子目录>/CLAUDE.md:模块级配置,仅在操作该模块文件时加载
两种加载机制
理解这两种机制是 monorepo 中合理组织 CLAUDE.md 的关键。
向上加载(Ancestor Loading)——启动时立即加载
Claude Code 启动时,从当前工作目录向上遍历整个目录树直到根目录,加载沿途找到的所有 CLAUDE.md 文件。这些文件立即注入上下文,无需等待任何操作。
/mymonorepo/ ← CLAUDE.md 启动时加载 ✓
├── CLAUDE.md
└── frontend/ ← 从这里启动 claude
└── CLAUDE.md ← CLAUDE.md 启动时加载 ✓从 /mymonorepo/frontend/ 启动时,frontend/CLAUDE.md 和 /mymonorepo/CLAUDE.md 都会立即加载。
向下懒加载(Descendant Loading)——操作时按需加载
子目录的 CLAUDE.md 不会在启动时加载,只有当 Claude 读取或编辑该子目录内的文件时才会触发加载。
/mymonorepo/ ← 从这里启动 claude
├── CLAUDE.md ← 启动时加载 ✓
├── frontend/
│ └── CLAUDE.md ← 操作 frontend/ 文件时加载
├── backend/
│ └── CLAUDE.md ← 操作 backend/ 文件时加载
└── api/
└── CLAUDE.md ← 操作 api/ 文件时加载兄弟目录互不影响:在 frontend/ 工作时,永远不会自动加载 backend/CLAUDE.md 或 api/CLAUDE.md。
完整的加载场景示例
场景 1:从根目录启动
bash
cd /mymonorepo
claude| 文件 | 是否加载 | 原因 |
|---|---|---|
/mymonorepo/CLAUDE.md | ✅ 启动时 | 当前目录 |
frontend/CLAUDE.md | 延迟 | 等到操作 frontend/ 文件 |
backend/CLAUDE.md | 延迟 | 等到操作 backend/ 文件 |
场景 2:从子目录启动
bash
cd /mymonorepo/frontend
claude| 文件 | 是否加载 | 原因 |
|---|---|---|
/mymonorepo/CLAUDE.md | ✅ 启动时 | 祖先目录 |
frontend/CLAUDE.md | ✅ 启动时 | 当前目录 |
backend/CLAUDE.md | ❌ 不加载 | 兄弟目录,永不加载 |
api/CLAUDE.md | ❌ 不加载 | 兄弟目录,永不加载 |
为什么这个设计合理
- 祖先向下传递:根目录的规范会被所有子项目自动继承,无需重复
- 子目录按需加载:不操作某个模块就不加载它的规则,避免无关上下文污染
- 兄弟隔离:前端开发者不会被后端规范干扰
如何组织 Monorepo 的 CLAUDE.md
根目录 CLAUDE.md——放全局规范
markdown
# mymonorepo
## 技术栈
- 包管理:pnpm workspaces
- 测试:vitest
- 提交格式:Conventional Commits
## 常用命令
- `pnpm test`:运行全量测试
- `pnpm build`:构建所有包
## 注意事项
- 不要直接修改 dist/ 目录
- PR 必须通过 CI 才能合并子目录 CLAUDE.md——放模块专属规范
markdown
# frontend 模块
## 框架规范
- 使用 React 18 + TypeScript
- 状态管理:Zustand(不用 Redux)
- 组件文件:每个组件一个目录,含 index.tsx + tests/
## 禁止事项
- 不直接调用后端 API,通过 api/ 包的封装个人配置 CLAUDE.local.md
添加到 .gitignore,用于个人偏好:
markdown
# 我的偏好
- 代码注释用英文
- 变量命名偏好 camelCase
- 我在用 M4 MacBook,可以并行运行构建任务.claude/rules/ 的按路径激活
除了 CLAUDE.md,还可以在 .claude/rules/ 目录放置规则文件,通过 paths frontmatter 实现只在操作特定文件时激活:
markdown
---
# .claude/rules/typescript-rules.md
paths: "**/*.ts,**/*.tsx"
---
# TypeScript 规则
- 始终定义函数的返回类型
- 避免使用 any,优先用 unknown只有当 Claude 操作 .ts 或 .tsx 文件时,这条规则才会加入上下文。这是更精细的懒加载控制。
写好 CLAUDE.md 的核心原则
根据 Boris Cherny 和 Humanlayer 的经验:
- 控制在 200 行以内:太长会稀释重要规则的权重,Claude 可能忽略后面的内容
- 关注"不显而易见"的规则:Claude 本身已经懂编程规范,只写项目特有的约束和陷阱
- 让团队共同维护:每次 Claude 做错的事,立即加入 CLAUDE.md,下次就会记住
- 用
<important>标签标记关键规则:对于"绝对不能违反"的规则,用标签包裹以提高权重
markdown
<important if="modifying-auth">
修改认证相关代码时,必须同时更新 auth-tests/ 目录下的集成测试。
</important>- 任何开发者运行
claude说"运行测试"都应该成功:如果不行,说明 CLAUDE.md 缺少了构建/测试命令
FAQ
Q: CLAUDE.md 和 .claude/rules/ 有什么区别? A: 功能相同,但 .claude/rules/ 更适合大型项目:支持多文件拆分,支持 paths 字段按文件路径懒加载,便于团队分工维护不同模块的规则。CLAUDE.md 更简单,适合小型项目。
Q: 为什么子目录的 CLAUDE.md 没有在启动时加载? A: 设计上的选择:如果所有 CLAUDE.md 都在启动时加载,大型 monorepo(可能有几十个子模块)会在启动时就把大量无关上下文注入,不仅浪费 tokens,还会干扰 Claude 的判断。懒加载确保只有你真正在操作的模块规则才会进入上下文。
Q: Claude 真的会忽略 CLAUDE.md 里的规则吗? A: 会,概率在 20% 左右(来自社区数据)。缓解方法:把最重要的规则放在文件开头,使用 <important> 标签,保持文件简洁(< 200 行),以及在规则里解释为什么(有原因的规则更不容易被忽略)。