
Claude Code SDK #17:Memory 与 CLAUDE.md 全解——两套机制 × 四层作用域 × 路径级按需加载,让 Claude 跨 session 记住一切
每次新 session Claude 都从零记忆出发,CLAUDE.md 和 Auto Memory 是解决这个问题的两套互补机制。本篇完整拆解四层作用域(Managed/User/Project/Local)与加载顺序、`.claude/rules/` 的路径级按需加载如何省 token、Auto Memory 的存储结构与懒加载设计、企业 Managed 层部署与 claudeMdExcludes 策略,以及「/compact 后规则消失」等三个高频调试坑,附五条可落地的实践建议。
每次启动新 session,Claude 的上下文都从零开始。你可能已经无数次打出同样的话:「用 2-space 缩进」「测试命令是
npm run test:unit」「别直接往 main 分支推」。这不是你的问题,是机制问题——而 Claude Code 提供了专门解决这个问题的两套系统:CLAUDE.md 文件和 Auto Memory。本篇完整拆解这套记忆体系的加载逻辑、作用域层级、路径级按需规则、企业部署,以及「/compact 后指令消失」等高频调试坑,附五条可落地的实践建议。
两套机制,互补而非替代
理解这套体系的第一步,是搞清楚 CLAUDE.md 和 Auto Memory 是两种不同性质的机制,不要混用1。
| CLAUDE.md | Auto Memory | |
|---|---|---|
| 由谁写 | 开发者手动写 | Claude 自动记录 |
| 内容类型 | 项目规范、工作流程、架构约定 | 构建命令、调试经验、Claude 观察到的偏好 |
| 作用域 | 项目 / 用户 / 组织级 | 单仓库,跨 worktree 共享 |
| 加载方式 | 每次 session 全量注入上下文 | 每次 session 加载前 200 行或 25KB |
| 最适合 | 你想主动控制的规则与约定 | 让 Claude 从使用中学习、减少重复纠正 |
两套机制并行工作,都在每次 session 启动时加载。但有一点要记住:无论哪套机制,内容进入的是上下文窗口,不是强制执行层。想要无条件拦截某个工具调用,应该用 Hooks 的 PreToolUse 而不是在 CLAUDE.md 里写「禁止执行 rm -rf」。

CLAUDE.md 的四层作用域
CLAUDE.md 文件可以放在四个不同位置,每个位置对应不同的作用范围1。
| 层级 | 路径 | 作用范围 | 典型用途 |
|---|---|---|---|
| Managed 层 | macOS: /Library/Application Support/ClaudeCode/CLAUDE.md / Linux: /etc/claude-code/CLAUDE.md | 机器上所有用户、所有项目 | 公司编码规范、合规要求(IT 通过 MDM/Ansible 分发) |
| User 层 | ~/.claude/CLAUDE.md | 当前用户的所有项目 | 个人代码风格偏好、常用工具快捷方式 |
| Project 层 | ./CLAUDE.md 或 ./.claude/CLAUDE.md | 当前项目(通过版本控制与团队共享) | 项目架构、测试命令、命名约定 |
| Local 层 | ./CLAUDE.local.md(加入 .gitignore) | 仅当前用户、当前项目 | 本地 sandbox URL、个人测试数据 |
加载顺序:从文件系统根目录向工作目录方向逐层加载,范围越广的文件越先被读入上下文。也就是说,
./CLAUDE.md 在 ~/.claude/CLAUDE.md 之后进入上下文,项目级指令优先级更高。如果在
foo/bar/ 目录下启动 Claude,它会加载:foo/CLAUDE.md → foo/bar/CLAUDE.md → 各层对应的 CLAUDE.local.md,全部拼接进上下文(不是覆盖)。子目录懒加载:CLAUDE.md 只有在 Claude 实际读取对应子目录中的文件时,才会加载该子目录下的 CLAUDE.md。这是一个重要的 token 节省机制。
用 .claude/rules/ 做路径级按需加载
当项目变大,把所有规则堆进一个 CLAUDE.md 会遇到两个问题:文件超过 200 行后遵循度下降;大量与当前任务无关的规则占据 token。
your-project/
├── .claude/
│ ├── CLAUDE.md # 全局主指令
│ └── rules/
│ ├── code-style.md # 始终加载(无 paths 声明)
│ ├── testing.md # 始终加载
│ └── api-design.md # 只有操作 API 文件时才加载声明路径绑定只需要在
.md 文件头部加 YAML frontmatter:---
paths:
- "src/api/**/*.ts"
- "src/api/**/*.tsx"
---
# API 开发规范
- 所有 API endpoint 必须包含输入验证
- 使用标准错误响应格式(见 src/lib/errors.ts)
- 必须包含 OpenAPI 注释当 Claude 读取
src/api/users.ts 时,这份规则才会进入上下文;操作 src/components/Button.tsx 时不会加载。对于个人偏好,
~/.claude/rules/ 下的文件在所有项目中生效——优先级低于项目级 rules,但高于 managed 层之外的全局默认。
Auto Memory:Claude 自己做笔记
Auto Memory 是 Claude Code v2.1.59 引入的机制,默认开启1。
每个项目的自动记忆存储在:
~/.claude/projects/<project-hash>/memory/
├── MEMORY.md # 入口索引(每次 session 加载前 200 行或 25KB)
├── debugging.md # Claude 整理出的调试经验
├── api-conventions.md # Claude 观察到的 API 约定
└── ... # 其他主题文件(按需创建)MEMORY.md 是一份索引,记录「去哪里找什么」。细节内容放在主题文件里,不在 session 启动时加载,而是 Claude 认为需要时通过文件工具按需读取。这套设计背后的逻辑:每次 session 全量注入所有记忆的 token 成本太高;只注入索引,细节懒加载,兼顾了完整性和 token 效率。
同一 git 仓库的所有 worktree 共享一份 Auto Memory(路径由 git repo 根目录计算得出)。跨机器不同步——Auto Memory 是机器本地的。
关闭 Auto Memory:
{
"autoMemoryEnabled": false
}或设置环境变量
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1。
企业部署场景
Managed CLAUDE.md 部署在固定路径(macOS 为
/Library/Application Support/ClaudeCode/CLAUDE.md),由 IT 通过 MDM/Ansible 推送,覆盖该机器上所有用户的 Claude 会话,且无法被 claudeMdExcludes 排除1。还可以直接把 CLAUDE.md 内容内联进
managed-settings.json:{
"claudeMd": "提交前始终运行 `make lint`。\n禁止直接推送到 main 分支。"
}Managed 层 vs Settings 层的分工:
| 要控制的事情 | 配置位置 |
|---|---|
| 限制特定工具、命令、文件路径 | managed-settings.json → permissions.deny |
| 强制沙箱隔离 | managed-settings.json → sandbox.enabled |
| 代码风格、合规提示、行为指令 | Managed CLAUDE.md |
关键区别:settings 里的权限规则是客户端强制执行的;CLAUDE.md 是上下文约束,Claude 会尽力遵循,但不能像 deny 规则一样保证拦截。
大型 Monorepo 中排除其他团队的 CLAUDE.md:
{
"claudeMdExcludes": [
"**/monorepo/CLAUDE.md",
"/home/user/monorepo/other-team/.claude/rules/**"
]
}加入
.claude/settings.local.json 使排除只在本机生效。三个高频调试坑
坑一:Claude 不遵循 CLAUDE.md 里的规则
原因通常是:文件没被加载、规则太模糊、不同文件中存在冲突指令。
先运行
/memory 命令,查看当前 session 实际加载了哪些文件。如果你的 CLAUDE.md 不在列表里,说明路径不对或不在加载层级内。规则模糊度也很关键:「好好格式化代码」对 Claude 没有足够约束力;「使用 2-space 缩进,函数间留一个空行」才是可操作的指令。
如果规则必须在特定生命周期时间点执行(比如每次提交前运行 linter),应该写成 Hook 而不是 CLAUDE.md 指令。
坑二:/compact 后 Claude 忘记了项目规则
/compact 后,工作目录的 CLAUDE.md 会重新从磁盘读取并注入——这部分不会丢失。但子目录下的 CLAUDE.md 不会自动重新注入,要等 Claude 下次读取对应目录的文件时才重新加载。如果某条重要规则只在对话里给出、没有写进 CLAUDE.md 文件,compact 后它就丢失了。
解决方案:规则写文件,不写对话1。
坑三:CLAUDE.md 越写越大,遵循度下降
超过 200 行的单个 CLAUDE.md 文件会消耗大量上下文,且 Claude 对后部分的遵循度明显下降(上下文中越靠后的内容越容易被忽略)。
用
@path/to/file 语法把内容拆分成多个文件并不能缓解这个问题,因为被 @ 导入的文件仍然在 session 启动时全量注入。真正的解法是用 .claude/rules/ 加 paths frontmatter,让规则只在需要时加载。五条实践建议
1. 用
/init 生成起步文件,再手动精炼
/init 命令让 Claude 自动分析当前代码库,生成包含构建命令、测试方法和项目约定的初始 CLAUDE.md。设置 CLAUDE_CODE_NEW_INIT=1 启用多阶段交互式流程,能进一步定制要生成的 Skills 和 Hooks。初始文件生成后,删掉 Claude 能从代码里自己推断的内容,只保留它靠静态分析无法得知的规则。2. 「触发第二次犯同样错误时才写进 CLAUDE.md」
第一次纠正可以当作上下文给出;如果同一个错误在下次 session 再次出现,这就是该写进 CLAUDE.md 的信号。这个原则防止 CLAUDE.md 过早膨胀。
3. 按「是否所有上下文下都需要」决定放全局还是 rules/
「所有 API 文件使用标准错误格式」→ 放进
rules/api-design.md 加 paths: ["src/api/**/*.ts"]。「所有文件都用 2-space 缩进」→ 放进主 CLAUDE.md。规则的触发范围越窄,越应该放进 rules/ 的路径级文件。4. 偶尔审计 Auto Memory 的内容
运行
/memory → 打开 auto memory 目录查看 Claude 记录了什么。Auto Memory 里的内容有时比你自己写的 CLAUDE.md 更准确地反映了「Claude 在这个项目里实际学到了什么」。发现过时或错误的记录直接编辑对应的 .md 文件即可;Auto Memory 是普通 Markdown,不需要特殊工具管理。5. CLAUDE.md 和 Settings 各司其职,不要混用
CLAUDE.md 只放行为指导,技术约束放 settings。「不要 import xxx 包」写 CLAUDE.md;「禁止执行 rm -rf /」写
permissions.deny。Settings 里的限制是客户端强制执行的,Claude 自己无法绕过;CLAUDE.md 里的限制是上下文约束,Claude 通常遵循但在极少数情况下可能忽略。本篇是 Claude Code SDK 系列的第 17 篇。下期主题:Skills 全解——如何把可复用的工作流程打包成按需加载的技能,而不是堆进 CLAUDE.md 变成 session 启动时的 token 负担。
围绕这条内容继续补充观点或上下文。