03 · 怎么记住你的习惯
上下文是一次性的,关机就清空。Claude Code 怎么跨会话记住你的项目、习惯、偏好?答案是双轨记忆——你写的 CLAUDE.md 持久指令 + 它自己写的 Auto Memory 工作笔记。
上一篇我们聊了上下文——一张很大但会清空的桌子。翔宇当时的第一个念头是:那每次启动 Claude Code,它岂不是什么都不记得?翻文档发现 Anthropic 给的方案比想象中精妙——两套记忆并行,一套你写、一套它写,把每天都是第一天这个问题彻底解决了。——翔宇
这一篇用 13 分钟换什么:上一篇 02 拆了上下文窗口——会话级、会清空。这一篇拆跨会话的记忆系统:你写给 Claude 的项目指令(CLAUDE.md)+ Claude 自己积累的工作笔记(Auto Memory)。理解了双轨设计,你才能判断什么信息该写哪、写多少、放哪一层。
1. 一个新员工的麻烦
假设你雇了一个超级聪明的助手。什么都会,反应飞快,解决问题一流。
但他每天早上来上班,不记得昨天发生过什么。
你得重新告诉他:项目用的是 Next.js,数据库是 PostgreSQL,代码风格遵循这套规范,构建命令是 pnpm build,部署走 Vercel,CI 在 GitHub Actions 里……
第一天你觉得还行。第二天开始烦了。第三天你想辞退他。
这就是上一篇结尾提到的问题:上下文窗口是一次性的,会话结束就清空。如果 Claude Code 只有上下文,每次启动它对你的项目一无所知——你得反复解释技术栈、构建命令、代码规范、架构决策……这些解释本身还要占上下文空间,挤掉了本来可以用来做正事的位置。
换个设定:同样这个助手,但桌上放着一本你写好的手册——《新员工必读》。每天来上班先翻一遍,五分钟后进入状态。你再也不需要重复解释任何事。
这本手册就是 Claude Code 的 CLAUDE.md。
2. 一份手册,先解决最痛的问题
CLAUDE.md 是一个普通的 Markdown 文件,任何文本编辑器都能打开。
每次 Claude Code 启动,它做的第一件事就是读这个文件。读完之后,文件内容变成这次会话的背景信息——Claude 回答你的每个问题时,都知道手册里写的东西。
那应该写什么?想象你给一个聪明但对你的项目一无所知的新同事写一份备忘录。你不会写公司全部历史,不会贴 500 行源代码,不会把所有制度从头抄一遍。你只会写他上班第一天最需要知道的那些事。
具体三类:
- 这是什么(WHAT):项目一句话介绍、技术栈、核心目录结构
- 为什么这样设计(WHY):关键架构决策(如选 Next.js 因为需要 SSR)—— 这类信息 Claude 从代码里看不出来,必须你告诉它
- 怎么操作(HOW):构建命令、测试命令、部署流程
200 行预算:官方建议 CLAUDE.md 控制在 200 行以内。文件越长,消耗的上下文越多,Claude 对指令的遵循度也会下降。内容多时用 @import 引用外部文件,或拆到 .claude/rules/ 子目录(按文件路径 glob 加载)。
3. 一份手册不够:4 层 scope
如果记忆只有一个 CLAUDE.md,你很快会碰到一个具体的麻烦:个人偏好和项目规范混在一起。
你喜欢中文回复——这是个人偏好,跟项目无关。 项目用 TypeScript——这是项目规范,跟你个人无关。
在多个项目之间切换时,个人偏好每个项目都要写一遍?团队多个人时,每人偏好都要写进项目 CLAUDE.md?
显然得分层。Anthropic 的方案是 4 层 scope,按位置自动判断属于哪一层:
每一层各管各的,按官方加载顺序拼起来:
sequenceDiagram
participant CWD as 你的工作目录
participant Claude as Claude Code 启动
participant Ctx as 上下文窗口
Claude->>CWD: 从项目根往上一路走
CWD-->>Claude: 找到所有 CLAUDE.md / CLAUDE.local.md
Claude->>Ctx: ① Managed policy(系统级)注入
Claude->>Ctx: ② Project(项目根 ./CLAUDE.md)注入
Claude->>Ctx: ③ User(~/.claude/CLAUDE.md)注入
Claude->>Ctx: ④ Local(./CLAUDE.local.md)注入
Note over Ctx: 离工作目录越近的越晚注入<br/>越容易影响最终行为
Claude->>Ctx: 也加载 MEMORY.md 前 200 行
Note over Ctx: Auto Memory 索引(详见 §5)
加载机制底层:Claude Code 从工作目录往上逐层查找 CLAUDE.md,全部拼接注入上下文(不是覆盖)。同目录下 CLAUDE.local.md 接在 CLAUDE.md 之后。子目录的 CLAUDE.md 只在 Claude 实际读取那个目录下的文件时按需加载。详见官方加载顺序文档。
日常使用中,你只需要关注两个文件:
~/.claude/CLAUDE.md—— 你的个人偏好(跨项目)项目根/CLAUDE.md—— 项目规范(团队共享,进 git)
为什么是"全部拼接"而不是"覆盖":覆盖会让最深一层的 CLAUDE.md 干掉所有上层规则——团队规范被个人偏好覆盖、个人偏好被本地实验覆盖,工程上不可控。拼接的代价是所有层加起来不能太长——如果 4 层都写满 200 行,启动注入 800 行,主对话桌子被规则文件占掉一大半。这就是为什么"克制"是 CLAUDE.md 的核心写作原则。
新手最常见的写法误区:把项目结构(目录树 / 文件列表)、依赖列表(package.json 内容)、Git 历史 / Commit 说明都抄进 CLAUDE.md。这些信息代码里有,每次会话再注入一遍 = 浪费 token。Claude 需要时直接读就行——它在你电脑上(01 篇 拆过)。
到这里手册系统已经很完整了。但还有一类信息,手册装不下。
4. AI 还得自己记笔记
CLAUDE.md 解决了一个问题:你把规则写下来,Claude 每次启动都看得见。
但工作中还有一些东西不太适合写进正式手册。
比如你纠正了 Claude 一次:测试不要 mock 数据库,用真实数据库。这条信息很有价值——下次写测试时应该记住。但它不是项目规范,不太适合写进 CLAUDE.md(团队 review 时也奇怪)。
再比如 Claude 在帮你调试时发现,某类错误的根因总是缓存没清。这是经验教训,对未来有用,但你不会主动写进手册。
这就是 Auto Memory 的角色。
通俗讲:CLAUDE.md 是你写的员工手册,Auto Memory 是员工自己带的工作笔记本。手册写公司规章,笔记本记工作中积累的经验教训。你不需要告诉它什么时候该记——它自己判断。
Auto Memory 是 Claude Code 自己维护的项目笔记系统(v2.1.59+ 默认开启)。你什么都不用做——Claude 在对话中自动识别哪些信息值得记住,分类存到持久文件里。下次启动新会话时,这些笔记自动可用。
存放位置:
<项目标识> 由 Claude Code 根据 git 仓库自动推导——同一个仓库的不同 worktree、子目录共享同一份 Auto Memory。Auto Memory 机器本地(不跨机同步)。
200 行 / 25KB 加载上限:启动时只加载 MEMORY.md 的前 200 行或 25KB(取较小)。超过部分不进入会话起点,但 Claude 在工作中可以按需读取 topic 文件(debugging.md 等)。这是为了避免笔记把工作台从一开始就铺满。
5. 怎么判断什么放哪?
现在两套系统都清楚了。判断标准很简单——这条信息是规则还是经验?还是Claude 直接看代码就能知道?
📜 规则 → CLAUDE.md
特征:必须遵守的、每次都需要的、应该共享给团队的。
典型内容:
- 技术栈声明(用 TypeScript / Next.js / PostgreSQL)
- 构建测试命令(
pnpm build/pnpm test) - 代码规范(缩进 / 命名 / 文件组织)
- 架构约定(API 在
src/api/handlers/下) - 业务领域规则(订单状态机 / 权限边界)
写进哪一层:
- 团队共享 →
项目根/CLAUDE.md(提交 git) - 个人跨项目偏好 →
~/.claude/CLAUDE.md - 个人项目偏好 →
./CLAUDE.local.md(加.gitignore)
什么时候开始写:
- Claude 第二次犯同一个错误
- 代码 review 指出 Claude 本应知道的项目规则
- 你反复在对话里解释同一个流程
- 新团队成员需要同样的上下文才能上手
💡 经验 → Auto Memory
特征:有用但非强制的、在工作中自然积累的、个人化或机器本地的。
典型内容:
- 你的纠正反馈(不要 mock 数据库 / 用 pnpm 不要 npm)
- 调试中发现的规律(这类报错根因总是缓存没清)
- 项目临时状态(这周冻结主分支 / X 服务停机维护)
- 某个文件 / 函数的非显然约定(看起来像 X 但实际是 Y)
- 偶发但重要的环境差异(CI 跟本地行为不同)
怎么写:
- 你不用主动写——Claude 自己判断写什么
- 想主动添加:直接告诉 Claude 比如以后都用 pnpm 不要 npm,它会自动写进 Auto Memory
- 想编辑:用
/memory命令打开
怎么查:
/memory列出所有当前会话加载的指令文件- 直接打开
~/.claude/projects/<项目>/memory/看 markdown
🔍 代码里有 → 不存
特征:Claude 随时能从项目代码 / 文件 / Git 历史读到的事实。
典型内容:
- 文件结构 / 目录组织(
ls就能看) - 函数签名 / 类定义(
grep就能看) - 历史变更 / 谁改了什么(
git log就能看) - package.json 的依赖列表(直接
cat就行) - README 已经写过的内容
为什么不存:
- 重复存 = 浪费上下文 token + 容易跟代码不同步
- Claude 需要时直接读就行——它在你电脑上(01 篇拆过)
- 信息源唯一才不会自相矛盾
反模式:把 README 内容复制进 CLAUDE.md / 把目录结构 ASCII 树写进 CLAUDE.md / 把测试用例列表写进 CLAUDE.md。
速记:每次都需要 → CLAUDE.md。工作中发现的 → Auto Memory。代码里有的 → 不存。
3 个判断练习 —— 下面三句话分别该放哪里?读完答案再看你判断对了几个:
场景 A:项目用 Next.js 14 + TypeScript + Prisma,所有 API 必须返回
{ data, error }格式。场景 B:你昨天发现 Claude 总是把测试 mock 数据库——你纠正后说"以后所有测试都连真实测试库"。
场景 C:项目源码结构(
src/app//src/components//src/api/handlers/...)。
📌 看答案
- A → 项目根
CLAUDE.md:是项目级长期规范,每个团队成员都需要,进 git 共享。 - B → Auto Memory(自动记忆):是工作中积累的纠正反馈,不需要正式写进项目规范,Claude 自己会记到
~/.claude/projects/<项目>/memory/。 - C → 不存:源码结构
ls就能看到,写进 CLAUDE.md = 浪费 token + 跟代码不同步(重构后 CLAUDE.md 容易忘改)。
判断诀窍——问自己:
- 这条信息每次会话都要进上下文吗?是 → CLAUDE.md。
- 这条信息是工作中临时发现的纠正?是 → Auto Memory(让 Claude 自己记)。
- 这条信息代码里 /
ls/git log能直接读到?是 → 不存。
6. 完整的画面
把前面所有内容串起来,Claude Code 启动时的信息架构是这样的:
| 时机 | 自动加载 | 来源 |
|---|---|---|
| 会话开始 | 系统提示(内置) | Claude Code 自己 |
| 会话开始 | CLAUDE.md(4 层全量拼接) | 你写的 |
| 会话开始 | MEMORY.md 前 200 行 / 25KB | Claude 自己写的 |
| 工作进行中 | 你和 Claude 的对话、读取的文件、命令输出 | 实时累积进上下文窗口 |
| 工作进行中 | Claude 自动写 Auto Memory(识别值得记的信息) | Claude 决策 |
| 工作进行中 | 子目录 CLAUDE.md / .claude/rules/*.md 按 glob 命中 | 按需加载 |
| 会话结束 | 上下文清空 | —— |
| 下次启动 | CLAUDE.md + MEMORY.md 还在 | 跨会话保留 |
底层逻辑:两套记忆系统的设计对应了两种信息天然属性——每次对话都需要知道的(CLAUDE.md)和在工作中自然积累的(Auto Memory)。把所有信息都塞进 CLAUDE.md 等于文件膨胀 + 团队 review 噪音;让 AI 自己积累而不留人写规则的口子,团队会失去显式约定。两套必须并存。
7. 排障:Claude 不听 CLAUDE.md 怎么办
CLAUDE.md 是上下文不是强制配置。Claude 会读它、尝试遵守,但不保证严格服从——尤其是模糊或冲突的指令。
排障 1 · 用 /memory 检查到底加载了哪些文件
/memory 命令列出当前会话所有已加载的 CLAUDE.md / CLAUDE.local.md / .claude/rules/*.md。
如果你的指令文件没出现在列表里 → Claude 根本没看到。
常见原因:
- 文件不在工作目录的祖先链上
- 子目录 CLAUDE.md(只在 Claude 读子目录文件时按需加载)
- 用了
--add-dir但没设CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1
排障 2 · 让指令更具体
格式化代码 ❌ → 用 2 空格缩进 ✅
测试改动 ❌ → 提交前跑 pnpm test ✅
保持文件组织 ❌ → API 处理器在 src/api/handlers/ ✅
模糊的话 Claude 会自由发挥,具体到能验证的程度才能稳定遵循。
排障 3 · 文件超过 200 行
文件越长,消耗上下文越多,对指令的遵循度反而下降。
解法:
- 路径范围规则 → 拆到
.claude/rules/加paths: [...]frontmatter,只在 Claude 处理匹配文件时加载 - 拆分多文件 → 用
@path/to/sub.mdimport(注意:import 的内容仍然占上下文 token,只是组织上分开) - 剔除可推断的内容 → 文件结构 / 函数签名等代码里有的,删掉
排障 4 · 多个 CLAUDE.md 互相冲突
monorepo / 大型项目里,祖先目录的 CLAUDE.md 可能跟当前项目的指令矛盾。Claude 会任意挑一个,行为不稳定。
解法:
- 用
/memory看所有加载的文件 - 找到冲突指令,统一表述
- 不需要的祖先文件用
claudeMdExcludes设置排除
排障 5 · /compact 后指令好像没了
项目根 CLAUDE.md 会 在 /compact 后被重新注入。
子目录 CLAUDE.md 不会自动重新注入,下次 Claude 读子目录文件时才会重新加载。
如果 /compact 后指令丢了 → 大概率是你只在对话里口头给过的指令,没写进文件。写进 CLAUDE.md 才能跨 compact 持久。
8. 检验你真懂了吗
费曼说,检验你是不是真的理解一件事,试试能不能解释给朋友听。
| # | 试着用自己的话回答 | 对应章节 |
|---|---|---|
| 1 | 有人说 Claude Code 记忆力很好什么都能记住——你能解释为什么这说法不准确?它有几种记忆,各自的特点? | §1 + §6 |
| 2 | CLAUDE.md 为什么建议控制在 200 行以内?背后的原理是什么?超过会怎样? | §2 + 排障 3 |
| 3 | 动手题 ⭐:打开你当前项目的 CLAUDE.md(如果没有,新建一个)。删掉所有"ls / git log / cat package.json 能查到的内容"——目录结构、依赖列表、Git 历史描述等。剩下的就是真正"每次会话都要进上下文"的项目规范。如果剩不到 50 行,证明你以前在 CLAUDE.md 里塞了太多 Claude 自己能查的事实。 | §5 |
过关标准:能用一句话说清——Claude Code 的跨会话记忆是双轨的:你写的 CLAUDE.md(4 层 scope,规则)+ 它写的 Auto Memory(项目本地,经验);代码里有的事实不重复存。
📖 本篇术语速查表
| 英文 / 缩写 | 中文 | 一句话解释 |
|---|---|---|
| CLAUDE.md | 项目记忆文件 | 你写的持久指令,每次启动自动读,Markdown 格式 |
~/.claude/CLAUDE.md | 用户级记忆 | 跨所有项目的个人偏好 |
./CLAUDE.local.md | 本地级记忆 | 当前项目的个人偏好(必须加 .gitignore) |
| Managed policy | 系统级策略 | IT/DevOps 部署的全公司强制指令 |
.claude/rules/ | 规则目录 | 大项目下按主题拆分的指令文件,支持 paths: glob 过滤 |
@path/to/file | import 语法 | CLAUDE.md 引用其它文件,递归最多 5 层 |
| Auto Memory | 自动记忆 | Claude 自己维护的项目本地笔记系统(v2.1.59+ 默认开启) |
| MEMORY.md | 自动记忆主文件 | Auto Memory 索引,启动加载前 200 行 / 25KB |
/memory | 记忆查看命令 | 列出当前会话已加载的所有指令文件 |
claudeMdExcludes | 排除设置 | settings 里指定不加载某些 CLAUDE.md(monorepo 场景) |
CLAUDE_CODE_DISABLE_AUTO_MEMORY | 环境变量 | 设为 1 关闭 Auto Memory |
官方资料
接下来去哪
➡️ 04 · 怎么和 AI 说话
有了记忆,还得会说话。提示词不是模板游戏,是信息密度游戏——目标 / 上下文 / 边界 / 验收 4 件套。
06 · 把重复的话写成文件(可跳读)
规则之外还有工作流。Skills 是把多步流程沉淀成可复用单元——记忆系统的进化形态。
02 · 一次能看多少代码(上一篇)
复习一下:上下文是会话级的工作台。本篇的双轨记忆就是为了解决每次对话都需要知道的那部分。
不用按顺序全读。挑你最好奇的那条线走就行。