源码级深度解析

Claude Code
Memory System

从产品经理视角,结合官方文档与源码实现,全面拆解 Claude Code 的记忆架构、加载策略、存储机制与最佳实践。

分析版本 Claude Code CLI (Mar 2025 snapshot)
分析日期 2026 年 4 月 10 日
源码文件 20+ 核心文件
SCROLL

为什么需要记忆系统?

Claude Code 的每一次会话都从全新的上下文窗口开始——没有任何历史记忆。记忆系统的核心使命是:跨会话传递知识,让 AI 在不同对话间保持对项目、用户和团队的理解。

2
互补记忆系统
5
层级优先级
200
行 / MEMORY.md 上限
25K
字节 / 自动记忆上限
💡
关键洞察:CLAUDE.md 的内容作为 用户消息(user message)传递,而非系统提示(system prompt)的一部分。Claude 会阅读并尽力遵循,但不是硬性强制——指令越具体、越简洁,遵循度越高。

CLAUDE.md + 自动记忆

两套互补的记忆机制在每次对话开始时加载。人类编写指令,AI 积累学习——二者协同工作。

维度 CLAUDE.md 文件 自动记忆 (Auto Memory)
编写者 用户 / 团队 Claude 自主编写
内容类型 指令和规则 学习到的模式和偏好
作用范围 项目、用户或组织 每个工作树 (worktree)
加载方式 完整加载(不论长度) 前 200 行或 25KB
典型内容 编码标准、工作流、架构 构建命令、调试经验、偏好
持久化位置 项目目录 / 用户目录 ~/.claude/projects/<project>/memory/
源码入口 utils/claudemd.ts memdir/memdir.ts
📌
源码验证:constants/prompts.ts:495 中,通过 systemPromptSection('memory', () => loadMemoryPrompt()) 将记忆注入系统提示。上下文构建在 context.ts:155-189getUserContext() 函数中完成。

五层优先级架构

CLAUDE.md 的加载遵循严格的层级顺序。更具体的位置覆盖更广泛的位置。源码中的 getMemoryFiles() 函数定义了完整的发现和优先级逻辑。

P1
托管策略 (Managed)
macOS: /Library/Application Support/ClaudeCode/CLAUDE.md
组织全员
P2
用户指令 (User)
~/.claude/CLAUDE.md + ~/.claude/rules/*.md
个人全局
P3
项目指令 (Project)
./CLAUDE.md 或 ./.claude/CLAUDE.md + .claude/rules/*.md
团队共享
P4
本地指令 (Local)
./CLAUDE.local.md(gitignore,私有)
个人项目
P5
自动记忆 (AutoMem)
~/.claude/projects/<project>/memory/MEMORY.md
工作树级别
⚠️
关键源码逻辑:utils/claudemd.ts:790-1074getMemoryFiles() 中,加载顺序为:Managed → User → Project(含向上遍历父目录)→ Local → AutoMem → TeamMem。此外发现还有 团队记忆(TeamMem)存储于 <autoMemPath>/team/MEMORY.md,由 Feature Flag tengu_herring_clock 控制。

记忆如何进入上下文?

记忆的加载并非简单的"全部读取"——它涉及发现、解析、截断、注入等多个精密步骤。

会话启动 entry → init
发现文件 getMemoryFiles()
解析 @import max depth: 5
去除注释 <!-- strip -->
截断控制 200行 / 25KB
注入上下文 systemPrompt

启动时加载(Eager Load)

以下内容在会话开始时即完整加载:

  • 当前工作目录及其所有祖先目录中的 CLAUDE.md
  • .claude/CLAUDE.md.claude/rules/*.md(无 paths: frontmatter 的文件)
  • 用户全局 ~/.claude/CLAUDE.md
  • 托管策略 CLAUDE.md
  • MEMORY.md 入口文件(前 200 行 / 25KB)

按需加载(Lazy Load)

以下内容仅在需要时才加载:

  • 子目录中的 CLAUDE.md(当 Claude 读取该目录的文件时触发)
  • 带有 paths: frontmatter 的 .claude/rules/*.md(当读取匹配文件时触发)
  • 自动记忆中的主题文件(如 debugging.mdpatterns.md),由相关性选择引擎决定
  • --add-dir 附加目录中的文件(需设置 CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1

@import 递归解析

CLAUDE.md 支持 @path/to/file 语法导入外部文件。

utils/claudemd.ts:448-490 // @import 解析逻辑 // 支持: @relative, @./relative, @~/home, @/absolute // 最大递归深度: 5 层 (line 537) // 通过 processedPaths Set 防止循环引用 // 仅从文本节点提取(代码块中的 @ 不处理) const MAX_IMPORT_DEPTH = 5; function resolveImports(content, filePath, processedPaths, depth) { if (depth > MAX_IMPORT_DEPTH) return content; // 提取 @path 引用,解析为绝对路径,递归展开 }

HTML 注释剥离

在注入上下文前,块级 HTML 注释会被自动移除——可用于给人类维护者留备注而不消耗 token。

utils/claudemd.ts:280-334 // 块级 HTML 注释剥离 // <!-- maintainer notes --> → 被移除 // 代码块内的注释 → 保留 // Read 工具直接打开时 → 注释可见

MEMORY.md 截断机制

自动记忆的入口文件有严格的大小限制:

memdir/memdir.ts:35-38, 57 const MEMORY_LINE_CAP = 200; // 最多 200 行 const MEMORY_BYTE_CAP = 25000; // 最多 25KB function truncateEntrypointContent(content) { // 取二者先达到的限制 // 超出部分附加截断警告 }
📏
注意区别:此限制仅适用于 MEMORY.md。CLAUDE.md 文件无论长度都会完整加载(但官方建议控制在 200 行以下以获得最佳遵循度)。

Claude 如何自主学习?

自动记忆是 Claude Code 最具"产品力"的功能之一——AI 在工作中主动积累知识,无需用户手动操作。

1

触发判断

Claude 在会话中发现值得记住的信息(用户纠正、非显而易见的偏好、项目模式等),基于"对未来对话是否有用"判断是否保存。

2

写入主题文件

使用 FileWriteTool 将记忆写入独立的 .md 文件(如 feedback_testing.md),包含 YAML frontmatter(name, description, type)。

3

更新索引

在 MEMORY.md 中添加一行索引指针:- [Title](file.md) — 一行描述,控制在 150 字符以内。

4

下次会话加载

MEMORY.md 索引在新会话启动时自动加载(前 200 行)。主题文件按需通过相关性引擎召回。

5

目录结构

~/.claude/projects/<sanitized-git-root>/memory/,同一 Git 仓库的所有 worktree 共享记忆。

memdir/paths.ts:223-235 — 路径解析逻辑 // 自动记忆路径解析优先级: // 1. CLAUDE_COWORK_MEMORY_PATH_OVERRIDE (环境变量) // 2. settings.json → autoMemoryDirectory (用户设置) // 3. 默认: ~/.claude/projects/<sanitized-git-root>/memory/ // // 重要安全策略: // autoMemoryDirectory 不从 projectSettings(.claude/settings.json) 读取 // 防止共享项目将记忆写入重定向到敏感位置 // 路径按项目根目录做 memoize 缓存
🔒
安全设计:源码中 memdir/teamMemPaths.ts:109-150 实现了符号链接攻击防护——在创建团队记忆目录前检测 symlink 是否指向不安全路径。autoMemoryDirectory 设置也刻意不从项目级 settings.json 读取(memdir/paths.ts),防止恶意项目重定向记忆存储。

结构化的记忆分类体系

自动记忆不是无序的笔记堆——它遵循严格的四类分类法,每种类型有明确的触发场景、存储格式和使用方式。

源码定义: memdir/memoryTypes.ts 行为指令: memdir/memdir.ts:199-316
USER

用户画像

用户的角色、目标、职责和知识水平。帮助 Claude 在未来对话中量身定制行为——对资深工程师和初学者的协作方式完全不同。

触发: 用户提到"我是数据科学家"
保存: 用户是数据科学家,当前关注可观测性/日志
PROJECT

项目动态

从代码或 Git 历史中无法推导的项目信息:谁在做什么、为什么、截止何时。注意将相对日期转换为绝对日期("周四" → "2026-03-05")。

触发: "周四之后冻结所有非关键合并"
保存: 2026-03-05 起合并冻结 + 原因: 移动端发版
REFERENCE

外部指针

指向外部系统中信息位置的指针。让 Claude 知道去哪里找最新信息(而非缓存过时的内容)。

触发: "管道 bug 都在 Linear 的 INGEST 项目里"
保存: 管道 bug → Linear "INGEST" 项目

记忆文件格式规范

每个记忆文件遵循统一的 YAML frontmatter + Markdown 正文格式:

记忆文件格式(utils/claudemd.ts:253-278 解析逻辑) --- name: 测试策略偏好 description: 集成测试必须使用真实数据库而非 mock type: feedback --- 集成测试必须连接真实数据库,不使用 mock。 **Why:** 上季度 mock 测试通过但生产迁移失败。 **How to apply:** 所有涉及数据库交互的测试文件中使用测试数据库实例。

什么不应该存入记忆?

  • 代码模式、架构、文件路径——可通过读取当前代码状态获得
  • Git 历史、最近变更——git log / git blame 是权威来源
  • 调试方案或修复配方——修复已在代码中,commit message 有上下文
  • CLAUDE.md 中已记录的内容——避免重复
  • 临时任务细节——使用 Plan 或 Todo 而非记忆

智能召回而非暴力加载

并非所有记忆文件都在每次会话中加载。系统使用 AI 驱动的相关性选择来决定哪些主题文件最有价值。

召回流程

  • 扫描 memdir 中所有 .md 文件(最多 200 个,按修改时间倒序)
    memdir/memoryScan.ts:35
  • 提取每个文件前 30 行的 frontmatter(name, description, type)
  • 构建记忆清单(manifest)传给 Claude Sonnet 模型
  • Sonnet 选出最多 5 个最相关的文件
    memdir/findRelevantMemories.ts:39-77
  • 排除已在上下文中的文件,最大化覆盖

设计考量

  • 轻量级模型:使用 Sonnet 而非 Opus 做选择,平衡质量与速度
  • 去重:已加载的文件不会被再次选择 (line 44)
  • 工具文档过滤:最近使用的工具文档被排除 (lines 92-95)
  • 渐进式:可多次调用以在对话中逐步召回更多记忆
memdir/findRelevantMemories.ts — 核心逻辑 async function findRelevantMemories(context) { // 1. 扫描所有记忆文件 (max 200, sorted newest-first) const files = await scanMemoryFiles(memDir); // 2. 排除已在上下文中的文件 const candidates = files.filter(f => !alreadySurfaced.has(f)); // 3. 构建清单文本 const manifest = formatMemoryManifest(candidates); // 4. 调用 Sonnet 做相关性排序,选出 top 5 const selected = await selectRelevantMemories(manifest, context); return selected; // 最多 5 个文件 }

.claude/rules/ 按需加载

对于大型项目,可将指令拆分为多个规则文件,支持按文件路径模式条件触发——仅在处理匹配文件时才加载到上下文中。

.claude/rules/api-design.md 示例 --- paths: - "src/api/**/*.ts" --- # API 开发规则 - 所有 API 端点必须包含输入验证 - 使用标准错误响应格式 - 包含 OpenAPI 文档注释
模式 匹配范围
**/*.ts 任意目录中的 TypeScript 文件
src/**/* src/ 下的所有文件
src/components/*.tsx 特定目录中的 React 组件
src/**/*.{ts,tsx} 大括号扩展匹配多扩展名
🔗
源码实现:utils/claudemd.ts:1354-1397,条件规则使用 ignore 库(类似 .gitignore 语法)对相对路径做匹配。规则触发时机是 Claude 读取匹配文件时(而非每次工具调用时)。规则文件也支持符号链接——可在多项目间共享。

Settings 与 Feature Flags

记忆系统的行为可通过 settings.json 和环境变量精细控制。源码中还存在多个 Feature Flag 控制实验性功能。

配置项 类型 作用 源码位置
autoMemoryEnabled boolean 开启/关闭自动记忆(默认 true) settings/types.ts:938
autoMemoryDirectory string 自定义记忆存储路径(支持 ~/ 展开) settings/types.ts:944
autoDreamEnabled boolean 启用后台记忆整合("dream"模式) settings/types.ts:950
claudeMdExcludes string[] 排除特定 CLAUDE.md 文件(glob 语法) settings/types.ts:1053
CLAUDE_CODE_DISABLE_AUTO_MEMORY env var 环境变量级关闭自动记忆 memdir/paths.ts:31-37

源码中发现的 Feature Flags

以下是在源码中找到的与记忆系统相关的实验性标志,揭示了产品演进方向:

🔮

tengu_herring_clock

控制团队记忆功能。启用后在自动记忆目录下创建 team/ 子目录,允许多人协作的记忆共享。

🦋

tengu_moth_copse

控制 MEMORY.md 注入方式切换——从直接注入转为附件预取(attachment prefetch),可能是上下文优化策略。

🧠

EXTRACT_MEMORIES

启用后台记忆提取代理,可能在会话结束后自动分析对话并提取值得记住的信息。

🌙

KAIROS

控制每日日志模式(Daily Log),为 Assistant 模式提供追加式的日志记忆。

性能优化:源码中 getMemoryFiles 使用 memoize 缓存(单次会话仅调用一次,除非显式清理)。系统提示的记忆部分也会被缓存,直到 /clear/compact 时才刷新。在 constants/prompts.ts:573,记忆内容位于动态边界处用于 prefix caching。

产品经理的行动指南

综合官方文档与源码实现,以下是使用 Claude Code 记忆系统的最佳实践。

📐

CLAUDE.md 控制在 200 行以内

虽然文件会完整加载,但过长的文件消耗上下文且降低遵循度。详细内容拆分到 @import 引用或 .claude/rules/ 文件中。用 HTML 注释 <!-- --> 给维护者留备注而不消耗 token。

🎯

指令要具体到可验证

✅ "使用 2 空格缩进"  ✅ "提交前运行 npm test"  ✅ "API 处理程序位于 src/api/handlers/"
❌ "正确格式化代码"  ❌ "测试你的更改"  ❌ "保持文件有组织"

🏗️

善用分层架构

托管策略放安全合规(全组织)→ 用户级放个人偏好 → 项目级放团队规范 → 本地放个人项目配置 → 自动记忆让 AI 自主积累。每层各司其职,避免重复。

📁

大项目用 .claude/rules/ 条件加载

使用 paths: frontmatter 让规则仅在处理匹配文件时加载。在 monorepo 中用 claudeMdExcludes 排除其他团队的 CLAUDE.md。条件规则 = 更少的上下文噪音 + 更精准的指令。

🔄

定期审计自动记忆

使用 /memory 命令浏览 Claude 保存的内容。记忆文件是纯 Markdown,可随时编辑或删除。注意清理过时的项目动态(project 类型),它们衰减最快。

🧩

记忆 vs Plan vs Todo 选择策略

记忆:跨会话有用的信息(偏好、模式、外部指针)。Plan:当前任务的实现方案(需要用户确认)。Todo:当前会话的离散工作步骤。不要把临时任务信息存入记忆。

用 /init 快速启动

运行 /init 自动生成初始 CLAUDE.md。设置 CLAUDE_CODE_NEW_INIT=1 启用交互式多阶段流程,使用 subagent 探索代码库并生成可审查的提案。从生成结果开始迭代,添加 AI 不会自己发现的指令。

🛡️

理解安全边界

CLAUDE.md 是行为指导(非强制)——真正的安全控制用 settings.json 的 permissions.denyautoMemoryDirectory 刻意不从项目 settings 读取,防止恶意重定向。团队记忆有 symlink 攻击防护。托管策略 CLAUDE.md 无法被 claudeMdExcludes 排除。