记忆与 CLAUDE.md
不想每次开会话都重复交代"这个项目用 pnpm 不用 npm"、"提交信息写中文"、 "改完必须跑 make check"。把这些写一次,之后自动带上。
三种机制,别混:
| 机制 | 谁写 | 什么时候进上下文 | 适合放什么 |
|---|---|---|---|
| CLAUDE.md | 你手写 | 每次会话,全量 | 项目约定、规范、铁律 |
| 记忆(save_memory) | 模型自动存(不弹确认),可 /memory delete <key> 删 | 索引每次带,正文按需读 | 你的偏好、纠正、决策 |
| 团队记忆 | 模型写入本地团队目录,配了共享目录才同步给其他成员 | 索引每次带 | 团队级规范与架构决策 |
先用 CLAUDE.md。写一个文件就生效,性价比最高。
快速上手
让它自己看一遍代码库,生成初版:
/init生成的 CLAUDE.md 在项目根。改成你要的,比如:
# 项目约定
## 包管理
用 pnpm,不要用 npm 或 yarn。
## 提交
提交信息用中文,格式 `type: 描述`。不要加 emoji。
## 改完必须做
跑 `pnpm test` 和 `pnpm lint`,两个都过了才算完成。下次开会话它就带上了。想确认到底加载了哪些文件:
/memory list详细说明
CLAUDE.md 的层级与优先级
不止项目根一个文件。完整合并链,后者覆盖/累积在前者之上:
企业 managed → managed/rules/ → 全局 → 用户规则目录 → 父目录链逐层(远 → 近)「父目录链」是从启动目录一直往上到文件系统根的每一层目录(不停在 git 仓库根, monorepo 外层工作区的规则在仓库里同样生效)。每一层内部按这个顺序读:
该层 CLAUDE.md → 该层 .sid-code/rules/、.claude/rules/ → 该层 CLAUDE.local.md层与层之间离启动目录越近越靠后、优先级越高。所以外层目录的 CLAUDE.local.md 不会盖过 内层仓库的 CLAUDE.md 和 rules。
| 层 | 位置 | 用途 |
|---|---|---|
| managed | <managed 根>/CLAUDE.md,外加 <managed 根>/rules/*.md(managed 根见下表) | 组织策略基座,个人改不掉 |
| 全局(user) | ~/.claude/CLAUDE.md,回退 ~/.sid-code/CLAUDE.md | 你的个人习惯,跨所有项目 |
| 用户规则目录 | ~/.claude/rules/ 与 ~/.sid-code/rules/,两个目录都会加载 | 拆成多个文件的个人规则 |
| 项目(project / subdir) | 父目录链上每一层的 CLAUDE.md,最深一层标 project,外层标 subdir | 团队共享,检入代码库;越深优先级越高 |
| 项目规则目录 | 父目录链上每一层的 .sid-code/rules/*.md 与 .claude/rules/*.md,两个都读,.sid-code/rules 在前 | 项目规则拆分 |
| local | 父目录链上每一层的 CLAUDE.local.md(或 .claude/CLAUDE.local.md) | 你个人的项目内偏好,不检入 |
| AGENTS.md 兜底 | 父目录链上每一层的 AGENTS.md | 只在父目录链上没有任何项目级 CLAUDE 系文件(含 CLAUDE.local.md)时才读——全局 ~/.claude/CLAUDE.md 的存在不影响兜底判定,给只写了 AGENTS.md 的仓库一个加载点 |
managed 根按平台固定(企业管理员照这个放文件):
| 平台 | managed 根 |
|---|---|
| macOS | /Library/Application Support/SidCode |
| Linux 及其他 Unix | /etc/sid-code |
| Windows | %PROGRAMDATA%\SidCode(未设置时为 C:\ProgramData\SidCode) |
父目录链上每一层的文件名候选是固定 5 个,按顺序取第一个存在的:
CLAUDE.md > .claude.md > claude.md > .claude/CLAUDE.md > .claude/instructions.md「同层只取一个」只管这 5 个文件名;rules/ 目录下是全部 *.md 都加载。
子目录这一层实际很好用:在 src/ui/ 放一个 CLAUDE.md 写"这个目录下的组件必须 用函数式写法",只在动那个目录时生效,不污染全局。
子目录(cwd 之下)的 CLAUDE.md 启动时不加载,等 agent 读 / 改 / 搜到那个目录里的 文件时才注入(JIT,与 Claude Code 一致)。启动时只读上表那条 cwd → 文件系统根的父链。 所以在家目录这类「底下有一堆项目」的地方启动,不会把每个项目的规则都塞进上下文。
CLAUDE.local.md vs CLAUDE.md
同一个项目里两个人偏好不同的时候:
CLAUDE.md—— 团队规范,检入 git,所有人一样CLAUDE.local.md—— 你自己的,加进.gitignore,在它所在那一层里优先级最高
比如团队用 CLAUDE.md 规定"注释写英文",你个人在 CLAUDE.local.md 里加 "跟我对话用中文"——两件事不冲突,各生效。
CLAUDE.md 里能 import 别的文件
支持 @路径 引用,把大文件拆开:
@docs/coding-style.md
@docs/review-checklist.md项目根之外的引用(含 ~/)需要批准。这是个安全边界:一个恶意仓库的 CLAUDE.md 不能靠 @~/.ssh/id_rsa 把你的私钥读进上下文。未批准的外部 import 会被跳过并提示。
写 CLAUDE.md 的实际建议
它进系统提示词,每次请求都要发一遍,所以长度是有成本的。
- 写"必须/不要",别写"最好/建议"。模糊的要求等于没要求。
- 写它猜不到的。"用 TypeScript"这种从
tsconfig.json就能看出来,不用写。 该写的是"这个项目里any是禁的,宁可写unknown再 narrow"。 - 别堆到几百行。没人遵守的规则是每次请求都在为它付费。写完一段时间回头看看 哪几条它从来没违反过——那些其实不用写。
- 改动要慎重。CLAUDE.md 在 prompt 前缀里,改一次缓存全失效, 见成本与用量。
想看它现在占多少上下文,/context 里有独立的"记忆/CLAUDE.md"一项。
输出风格:教它怎么说话
CLAUDE.md 管「做什么、不做什么」,输出风格管「怎么说」——回复长短、用不用 markdown、 语气正式还是口语。放一个 .md 文件到 .sid-code/output-styles/(项目级)或 ~/.sid-code/output-styles/(用户级),内容会作为系统提示词注入。项目级从启动目录 逐级往上扫到 git 仓库根,同名时离启动目录近的优先。
一个风格文件长这样:
---
name: concise
description: 简洁风格,每次回复不超过 3 句话
---
你是一个极简风格的助手。
- 每次回复不超过 3 句话
- 不要使用 markdown 标题
- 用短句选中它:
{
"outputStyle": "concise"
}outputStyle 匹配的是文件 frontmatter 里的 name 字段(没写 name 就用文件名)。 项目级覆盖用户级——同名时项目里的那份生效,和 CLAUDE.md 的层级方向一致。
几个行为要知道:
- 注入位置是系统提示词,和 CLAUDE.md 同层。所以它每次请求都发一遍,写得越长越贵—— 风格文件该写"约束"而不是"背景知识"
- 会话重建时刷新——改了
settings.outputStyle或风格文件后,下一轮 LLM 调用就用新的, 不用重开会话 - 风格文件可以只有正文没有 frontmatter——这时
name取文件名,description为空, 一样能用,只是/菜单里展示得朴素些
适合放什么:固定回复格式(commit message 模板、API 响应风格)、语气约束(中文优先、 不用 emoji)、结构要求(先结论后展开、列表代替散文)。不适合放业务逻辑——那是 CLAUDE.md 的活。
记忆:模型自己攒的东西
CLAUDE.md 是你手写的,记忆是模型用 save_memory 存的,跨会话可用。四类封闭分类:
| 类型 | 存什么 |
|---|---|
user | 用户画像(角色、目标、知识水平、长期偏好) |
feedback | 行为反馈(你的纠正与确认,含 Why 和怎么应用) |
project | 项目上下文(进行中的工作、决策、截止日期,无法从代码推导的) |
reference | 外部引用(URL、dashboard、工单的指针) |
触发方式最自然的就是直接说:
以后都用 pnpm,记住它不该存什么(这些约束写在系统提示词里):
- 能从代码 / git / 文件内容直接推导的事实
- 临时会话状态、当前任务进展
- 进度 / PR 状态这类快照,以及调试过程与修复配方(即使你说了"记住",也只留其中非显而易见的那一点)
- API Key、token、密码等凭证明文
- 已经在 CLAUDE.md 里的规则
save_memory 的 type 是必填参数,由模型显式给出四类之一,不再按关键词猜。 保存成功后工具会回一组写入质量提示(不拒绝,模型可用同一个 key 覆盖修正): 相对日期(含"周四"这类星期)、feedback / project 缺 Why: 或 How to apply: 标签、 reference 正文没有 URL、内容像进度快照。四个范围(project / global / team / agent)同一套判据。
想看本机记忆库的质量读数:
bun run scripts/memory-quality-report.ts # 存量(磁盘)+ 增量(memory_write 埋点)存储在 ~/.sid-code/projects/<项目键>/memory/ 下。项目键用主仓根目录派生(git rev-parse --git-common-dir), 所以同一个仓库的多个 worktree 共享同一份记忆——在 worktree 里攒的记忆回主仓照样在。
管理命令:
/memory 无参:打开交互式记忆面板(最常用)
/memory list (别名 ls) 列出记忆
/memory search <关键词> 搜
/memory get <key> 看某条正文
/memory set <key> <value> [--global] 手动写一条(默认项目级,--global 写全局)
/memory delete <key> (别名 del/rm) 删(同时删项目级和全局同名 key)
/memory show 看当前注入系统提示词的记忆内容(不接参数)
/memory auto on|off|status [-p] 自动记忆开关;无参是查状态,-p 持久化到 settings.json
/memory external allow|deny|status CLAUDE.md 里项目外 @import 的批准开关
/memory reload 重新加载并刷新系统提示词注入方式是"索引 + 按需读":每次会话只带一份 MEMORY.md 索引(名字 + 一行描述), 模型判断需要某条时才 Read 正文。所以记忆攒多了不会线性推高每次请求的成本。
自动记忆可以关:
SID_CODE_AUTO_MEMORY=false sid-code或者写 settings 的 autoMemory。优先级是 env > settings > 默认开启。
记忆是快照,不是实时状态
系统提示词里对模型有一条明确约束:记忆是"写入时的时间点观察"。 引用记忆里关于代码行为或 file:line 的断言之前,要先对照当前代码验证。
这条很重要。三周前存的"认证逻辑在 src/auth.ts:42"现在大概率已经不对了。
团队记忆
共享目录模型:模型先写进你本机的团队记忆目录,后台 watcher 按内容校验和与共享目录做增量双向同步, 不需要额外后端。团队 MEMORY.md 索引也注入每个会话——否则团队知识永远进不了上下文。
前提是启用 teamMemory 并配了合法的共享目录 teamMemory.dir(绝对路径)。 没配共享目录时团队记忆只存在本机,不跨成员同步。
团队记忆只由主会话写入(模型显式传 scope=team)。后台记忆提取代理无人监督, 只能写当前项目的私有记忆——团队记忆会同步给所有人,误判的代价需要人在场兜住。
SID_CODE_TEAM_MEMORY='{"enabled":true,"dir":"/shared/team-memory"}' sid-code注意 SID_CODE_TEAM_MEMORY 接受的是 JSON 对象字符串(不是一个布尔开关)。 写 =false 会被 JSON.parse 静默忽略、回退到 settings.json 的值。 关闭应写 '{"enabled":false}',或直接改 settings.json 的 teamMemory 段。 团队场景的完整做法见团队默认配置分发。
常见问题
CLAUDE.md 写了但它不遵守。 先确认加载了:/memory list 或看 /context 里"记忆/CLAUDE.md"是否非零。 加载了还不遵守,通常是写法问题——把"建议用 X"改成"必须用 X,不要用 Y"。
@ import 的文件没被读进来。 如果引用的路径在项目根之外(含 ~/),需要批准才生效;之前拒绝过可以用 /memory external allow 改主意。这是防止恶意仓库读你本机文件的 设计,不是 bug。
改了 CLAUDE.md 要重启吗。 规则在会话启动时加载。改完想立刻生效,/memory reload。
多个 CLAUDE.md 冲突了听谁的。 按上面那条合并链,越靠后越优先。CLAUDE.local.md 最大。
我在 worktree 里让它记的东西,回主仓没了。 不该发生——记忆按主仓根目录分桶,多 worktree 共享。真遇到这情况先确认那个 worktree 是不是同一个仓库的(两边各跑一次 git rev-parse --path-format=absolute --git-common-dir, 结果应相同)。注意 --show-toplevel 在 worktree 里返回的是 worktree 自己,用它对比会误判。
记忆里存了敏感信息怎么办。save_memory 落盘前没有人工审核环节,现有的隐私边界是三条:写入时做 secret 检测 (一套独立的常见凭证规则,比轨迹脱敏的覆盖面窄), 疑似凭证的内容直接拒收;系统提示词明令不存凭证;事后可以 /memory delete <key> 删。 如果你在对话里贴过明文 key,检测没认出来的形态仍可能被摘进 project 类记忆——发现了直接删。
能不能完全不用记忆,只用 CLAUDE.md。 可以,autoMemory: false。很多人就这么用,CLAUDE.md 已经覆盖大部分需求。
相关
- 上下文与压缩 —— CLAUDE.md 占多少、怎么看
- 成本与用量 —— 为什么频繁改 CLAUDE.md 会变贵
- Skill —— 比 CLAUDE.md 更重的复用单位:把一套流程打包
- 团队默认配置分发 —— 团队记忆与配置怎么发
- settings.json 字段 ——
autoMemory/teamMemory字段
写了 CLAUDE.md 却没被遵守? 多半不是模型不听话,而是那条规则当时根本不在上下文里。 JIT 上下文讲清了规则在什么时刻、按什么条件进入上下文,附实测基线。