Aklman · Library

— 04 / 第四章

记忆 · 从零写一份 CLAUDE.md.

同一件事你跟它说了十遍。这一章从零写一份真的 CLAUDE.md,并且用一组前后对照证明它确实改变了行为 —— 不是「感觉好点了」,是同一句提示、同一个仓库,做出来的东西不一样。顺带把四层记忆的位置与优先级、@import、rules 目录的路径限定,和一条容易踩的时间差讲清:它在会话开始读进内存,你中途改了不生效。

MD海报

用这个包管理器,不是那个。测试要跑 npm test 不是 npx jest。migrations 目录别碰。—— 这些话你跟它说过十遍,因为模型不跨会话记事。这一章从零写一份真的 CLAUDE.md,然后用一组前后对照证明它确实改变了行为:同一句提示、同一个仓库,做出来的东西不一样。不是「感觉好点了」,是看得见的差别。

— I

第一步:先拍一张「没有记忆」的底片.

对照要成立,得先有前片。挑一个你的项目有特殊做法的小任务 —— 加一个组件、加一条接口、加一个测试 —— 用一句最普通的提示交给它,然后什么都别纠正,把结果原样记下来。
提示词底片提示 · 故意不给任何约定
在这个仓库里加一个 <最小的、你们有特殊做法的东西>,照你觉得合适的方式做。
做完告诉我三件事:
1. 你把文件放在了哪里、为什么选这个位置;
2. 你跑了什么命令来验证,输出是什么;
3. 你对这个项目的约定做了哪些假设。
在这个仓库里加一个 带单元测试的日期格式化工具函数,照你觉得合适的方式做。
做完告诉我三件事:
1. 你把文件放在了哪里、为什么选这个位置;
2. 你跑了什么命令来验证,输出是什么;
3. 你对这个项目的约定做了哪些假设。
第 3 问是这一步的重点。它列出的每一条「假设」,都是一条它本来该知道、但没人告诉过它的事实 —— 那张假设清单,就是你 CLAUDE.md 的第一版目录。

— II

第二步:写那份文件,一行一个否决问题.

起点不用手写:跑一次 /init,它会分析代码库,把探出来的构建命令、测试方式、项目惯例生成一份初稿;已经有 CLAUDE.md 的话,它提改进而不是覆盖。然后你做减法。 CLAUDE.md 的敌人不是太短,是太长:它整份进入每次会话的上下文,臃肿的文件会让真正要紧的规则被淹没 —— 官方直说,写得太满,Claude 反而开始忽略你的指令。2注 2Claude Code Docs · Best practices —— 写 CLAUDE.md 的取舍表:收录它猜不到的构建命令、和默认不同的风格规则、测试跑法、仓库礼仪、项目特有的架构决定与坑;排除读代码就能推断的、语言通识、频繁变动的信息、逐文件的代码库描述。每一行问一句「删掉它会不会导致出错」,不会就删;臃肿的 CLAUDE.md 会让真正的规则被忽略。截至 2026-08-05。纪律是对每一行问同一个问题:删掉这行,它会不会因此犯错?不会,就删。2注 2Claude Code Docs · Best practices —— 写 CLAUDE.md 的取舍表:收录它猜不到的构建命令、和默认不同的风格规则、测试跑法、仓库礼仪、项目特有的架构决定与坑;排除读代码就能推断的、语言通识、频繁变动的信息、逐文件的代码库描述。每一行问一句「删掉它会不会导致出错」,不会就删;臃肿的 CLAUDE.md 会让真正的规则被忽略。截至 2026-08-05。
值得一行不值得
它猜不到的构建 / 测试命令读代码就能推断的结构
和默认不同的风格规则语言的通行惯例
禁区目录、仓库礼仪、环境怪癖经常变动的信息
踩过的坑和非直觉行为逐文件的代码库导览
CLAUDE.md
# 这个仓库的规矩
 
## 命令
- 测试:`npm test`(不是 npx jest —— 我们的 jest 配置只在这个脚本里生效)
- 单文件测试:`npm test -- <路径>`
- 构建前必须先 `npm run codegen`,否则类型对不上
 
## 约定
- 组件放 `src/components/<名字>/`,一个目录含组件、测试、样式三个文件
- 日期一律用 `src/lib/date.ts` 里的工具,不要直接 new Date()
- 新增依赖前先问我 —— 这个项目对包体积有硬预算
 
## 禁区
- 不要改 `src/db/migrations/`,那是线上迁移历史
- 不要碰 `.env*`
- 不要在提交信息里加 co-author 尾注
 
## 坑
- `src/legacy/` 下的代码没有测试覆盖,改那里要手动验证并说明怎么验的

一份真实形状的项目记忆:每一行都通过了「删掉会不会出错」

什么时候写?触发律是第二次:同一个错误出现第二遍,就是写一行的时候。3注 3Claude Code Docs · Extend Claude Code —— 各扩展机制的触发时机:同一个约定或命令错第二次,写进 CLAUDE.md;反复粘贴的多步流程,做成 skill;必须每次发生的,写 hook。指令写在 CLAUDE.md 或 skill 里「是请求,不是保证」。截至 2026-08-05。什么时候搬走?一段记忆长成了多步流程,它就不该住在这里 —— 那是 skill 的形状(第 5 章)。

— III

第三步:重跑同一句,看差别.

关键的一步,也是最容易被跳过的一步:/clear 开一个新会话(记住 —— 中途改文件不生效,下一节讲),把第 I 步一字不改的那句提示再发一次。

没有 CLAUDE.md

文件落在 src/utils/(它的通用直觉),直接用了 new Date(),顺手 npx jest 跑测试 —— 报了个配置错,它又装了一个依赖去绕。交回来的东西能跑,但三条项目约定全踩了,而它列出的「假设」正好就是这三条。

有 CLAUDE.md

文件落在 src/components/ 的目录约定里,日期走 src/lib/date.ts,验证用的是 npm test 并贴了输出;想加依赖时它停下来问你。没有一次纠正,因为不需要纠正 —— 这就是那份文件替你说的十遍话。
这组对照的意义不只是「它变听话了」。它把一件抽象的事变具体:一份写得好的 CLAUDE.md,对产出质量的改善常常大于换一个更强的模型 —— 因为多数「模型不够聪明」的错,其实是「没人告诉它」的错。也正因如此,这份文件值得像代码一样进版本库、被 review。

— IV

放哪一层,以及两个时间差.

四层记忆按从宽到窄的顺序加载,项目层出现在用户层之后。1注 1Claude Code Docs · How Claude remembers your project —— 四层 CLAUDE.md 按加载顺序从宽到窄:managed policy(macOS /Library/Application Support/ClaudeCode/CLAUDE.md、Linux 与 WSL /etc/claude-code/CLAUDE.md、Windows C:\Program Files\ClaudeCode\CLAUDE.md)、用户 ~/.claude/CLAUDE.md、项目 ./CLAUDE.md 或 ./.claude/CLAUDE.md、本地 ./CLAUDE.local.md;项目层出现在用户层之后。查找方式是从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md;当前目录之下的子目录 CLAUDE.md 不在启动时加载,而是 Claude 读到那些子目录里的文件时才带进来。@path 导入相对路径按「含该导入的文件」解析而非工作目录,最多递归四层;导入解析会跳过 markdown 行内代码与围栏代码块,想提路径又不想导入就用反引号包住。项目文件里的导入有信任对话框保护(防别人往共享仓库里塞),用户层导入是你自己写的,不弹。Claude Code 读 CLAUDE.md 而不是 AGENTS.md,官方给的桥接写法是在 CLAUDE.md 里写 @AGENTS.md 或做符号链接。两套记忆都在每次会话开始加载,并且「Claude treats them as context, not enforced configuration」—— 要不论模型怎么决定都拦住某个动作,用 PreToolUse hook。auto memory 每次会话加载 MEMORY.md 的前 200 行或 25KB。截至 2026-08-05。
层级位置放什么
组织managed policy(各系统固定路径)全公司的编码与合规规范
用户~/.claude/CLAUDE.md你个人的偏好,跟你走所有项目
项目./CLAUDE.md 或 ./.claude/CLAUDE.md团队共享:命令、架构、惯例,进版本库
项目 · 个人./CLAUDE.local.md你的沙盒地址、测试数据,进 .gitignore
查找方式值得知道:它从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md —— 所以在 monorepo 的子包里开工,上层仓库的规矩照样带得到。反方向则是懒加载:当前目录之下的子目录 CLAUDE.md 不在启动时加载,等 Claude 真读到那些子目录里的文件才带进来。1注 1Claude Code Docs · How Claude remembers your project —— 四层 CLAUDE.md 按加载顺序从宽到窄:managed policy(macOS /Library/Application Support/ClaudeCode/CLAUDE.md、Linux 与 WSL /etc/claude-code/CLAUDE.md、Windows C:\Program Files\ClaudeCode\CLAUDE.md)、用户 ~/.claude/CLAUDE.md、项目 ./CLAUDE.md 或 ./.claude/CLAUDE.md、本地 ./CLAUDE.local.md;项目层出现在用户层之后。查找方式是从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md;当前目录之下的子目录 CLAUDE.md 不在启动时加载,而是 Claude 读到那些子目录里的文件时才带进来。@path 导入相对路径按「含该导入的文件」解析而非工作目录,最多递归四层;导入解析会跳过 markdown 行内代码与围栏代码块,想提路径又不想导入就用反引号包住。项目文件里的导入有信任对话框保护(防别人往共享仓库里塞),用户层导入是你自己写的,不弹。Claude Code 读 CLAUDE.md 而不是 AGENTS.md,官方给的桥接写法是在 CLAUDE.md 里写 @AGENTS.md 或做符号链接。两套记忆都在每次会话开始加载,并且「Claude treats them as context, not enforced configuration」—— 要不论模型怎么决定都拦住某个动作,用 PreToolUse hook。auto memory 每次会话加载 MEMORY.md 的前 200 行或 25KB。截至 2026-08-05。这条设计很值钱:子包各自的规矩不用挤占你的开场上下文。 文件长了有两个泄压阀。@path 把别的文件拼进来,最多递归四层,相对路径按「含这条导入的文件」解析而不是工作目录 —— 这一条踩错过很多人。1注 1Claude Code Docs · How Claude remembers your project —— 四层 CLAUDE.md 按加载顺序从宽到窄:managed policy(macOS /Library/Application Support/ClaudeCode/CLAUDE.md、Linux 与 WSL /etc/claude-code/CLAUDE.md、Windows C:\Program Files\ClaudeCode\CLAUDE.md)、用户 ~/.claude/CLAUDE.md、项目 ./CLAUDE.md 或 ./.claude/CLAUDE.md、本地 ./CLAUDE.local.md;项目层出现在用户层之后。查找方式是从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md;当前目录之下的子目录 CLAUDE.md 不在启动时加载,而是 Claude 读到那些子目录里的文件时才带进来。@path 导入相对路径按「含该导入的文件」解析而非工作目录,最多递归四层;导入解析会跳过 markdown 行内代码与围栏代码块,想提路径又不想导入就用反引号包住。项目文件里的导入有信任对话框保护(防别人往共享仓库里塞),用户层导入是你自己写的,不弹。Claude Code 读 CLAUDE.md 而不是 AGENTS.md,官方给的桥接写法是在 CLAUDE.md 里写 @AGENTS.md 或做符号链接。两套记忆都在每次会话开始加载,并且「Claude treats them as context, not enforced configuration」—— 要不论模型怎么决定都拦住某个动作,用 PreToolUse hook。auto memory 每次会话加载 MEMORY.md 的前 200 行或 25KB。截至 2026-08-05。另一个是 .claude/rules/,按主题拆文件,还能用 paths 限定只在 Claude 碰到匹配文件时加载。1注 1Claude Code Docs · How Claude remembers your project —— 四层 CLAUDE.md 按加载顺序从宽到窄:managed policy(macOS /Library/Application Support/ClaudeCode/CLAUDE.md、Linux 与 WSL /etc/claude-code/CLAUDE.md、Windows C:\Program Files\ClaudeCode\CLAUDE.md)、用户 ~/.claude/CLAUDE.md、项目 ./CLAUDE.md 或 ./.claude/CLAUDE.md、本地 ./CLAUDE.local.md;项目层出现在用户层之后。查找方式是从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md;当前目录之下的子目录 CLAUDE.md 不在启动时加载,而是 Claude 读到那些子目录里的文件时才带进来。@path 导入相对路径按「含该导入的文件」解析而非工作目录,最多递归四层;导入解析会跳过 markdown 行内代码与围栏代码块,想提路径又不想导入就用反引号包住。项目文件里的导入有信任对话框保护(防别人往共享仓库里塞),用户层导入是你自己写的,不弹。Claude Code 读 CLAUDE.md 而不是 AGENTS.md,官方给的桥接写法是在 CLAUDE.md 里写 @AGENTS.md 或做符号链接。两套记忆都在每次会话开始加载,并且「Claude treats them as context, not enforced configuration」—— 要不论模型怎么决定都拦住某个动作,用 PreToolUse hook。auto memory 每次会话加载 MEMORY.md 的前 200 行或 25KB。截至 2026-08-05。 两个时间差别踩。其一:CLAUDE.md 在会话开始读入内存,中途改了不生效 —— 新内容要等下次 /clear、/compact 或重启才加载。4注 4Claude Code Docs · How Claude Code uses prompt caching —— 项目根与用户级 CLAUDE.md 在会话开始读入内存,中途编辑不废缓存、但也不生效,下次 /clear、/compact 或重启才加载新内容。截至 2026-08-05。改完发现它还按旧规矩走,不是它叛逆,是你还没翻页。其二:除了你写的记忆,它也在自己记 —— auto memory 把「下次会用上」的东西写进项目记忆目录,每次会话加载 MEMORY.md 的前 200 行或 25KB。1注 1Claude Code Docs · How Claude remembers your project —— 四层 CLAUDE.md 按加载顺序从宽到窄:managed policy(macOS /Library/Application Support/ClaudeCode/CLAUDE.md、Linux 与 WSL /etc/claude-code/CLAUDE.md、Windows C:\Program Files\ClaudeCode\CLAUDE.md)、用户 ~/.claude/CLAUDE.md、项目 ./CLAUDE.md 或 ./.claude/CLAUDE.md、本地 ./CLAUDE.local.md;项目层出现在用户层之后。查找方式是从当前工作目录向上逐级走,沿途每一层都查 CLAUDE.md 与 CLAUDE.local.md;当前目录之下的子目录 CLAUDE.md 不在启动时加载,而是 Claude 读到那些子目录里的文件时才带进来。@path 导入相对路径按「含该导入的文件」解析而非工作目录,最多递归四层;导入解析会跳过 markdown 行内代码与围栏代码块,想提路径又不想导入就用反引号包住。项目文件里的导入有信任对话框保护(防别人往共享仓库里塞),用户层导入是你自己写的,不弹。Claude Code 读 CLAUDE.md 而不是 AGENTS.md,官方给的桥接写法是在 CLAUDE.md 里写 @AGENTS.md 或做符号链接。两套记忆都在每次会话开始加载,并且「Claude treats them as context, not enforced configuration」—— 要不论模型怎么决定都拦住某个动作,用 PreToolUse hook。auto memory 每次会话加载 MEMORY.md 的前 200 行或 25KB。截至 2026-08-05。/memory 能看到两套记忆的全部文件:定期翻一翻,删掉过时的 —— 记忆也会腐烂,烂记忆比没记忆更误事。 本章验收 · 这份文件立起来了吗:

同一句话说第三遍之前, 把它变成一行记忆.

Before you say it a third time, make it one line of memory.

Aklman Library

— 讨论

讨论.

评论区初始化中…