diff --git a/README.en.md b/README.en.md index a37390f3..d2e608e7 100644 --- a/README.en.md +++ b/README.en.md @@ -18,6 +18,7 @@ A **locally runnable version** repaired from the leaked Claude Code source, with - [Environment Variables](#environment-variables) - [Fallback Mode](#fallback-mode) - [Computer Use Desktop Control](#computer-use-desktop-control) +- [Memory System](#memory-system) - [FAQ](#faq) - [Fixes Compared with the Original Leaked Source](#fixes-compared-with-the-original-leaked-source) - [Project Structure](#project-structure) @@ -32,6 +33,7 @@ A **locally runnable version** repaired from the leaked Claude Code source, with - MCP server, plugin, and Skills support - Custom API endpoint and model support ([Third-Party Models Guide](docs/third-party-models.en.md)) - **Computer Use desktop control** (screenshots, mouse, keyboard, app management) — [Guide](docs/computer-use.en.md) +- **Memory System** (cross-session persistent memory with auto-extraction and smart retrieval) — [Usage Guide](docs/memory/01-usage-guide.md) | [Implementation](docs/memory/02-implementation.md) - Fallback Recovery CLI mode > **Computer Use Note**: This project includes a **modified version of Computer Use**. The official implementation relies on Anthropic's private native modules. We replaced the entire underlying operation layer with a Python bridge (`pyautogui` + `mss` + `pyobjc`), enabling anyone to use Computer Use on macOS. See the [Computer Use Guide](docs/computer-use.en.md) for details. @@ -235,6 +237,29 @@ For supported platforms, technical architecture, and approaches we tried, see: * --- +## Memory System + +Claude Code includes a **file-based persistent memory system** that accumulates understanding of users and projects across sessions. Core principle: only remember what cannot be inferred from the code. + +**Four memory types**: + +| Type | Purpose | Example | +|------|---------|---------| +| **User** | Role, skills, preferences | "Deep Go expertise, new to React" | +| **Feedback** | Corrections or confirmations of Claude's approach | "Don't mock the database in tests" | +| **Project** | Project context not derivable from code | "Merge freeze starts Thursday" | +| **Reference** | Pointers to external systems | "Pipeline bugs tracked in Linear INGEST" | + +**Core capabilities**: + +- **Auto-extraction**: After each conversation, a background forked agent automatically analyzes and saves noteworthy information +- **Smart retrieval**: When the user asks a question, a Sonnet model selects the most relevant memories (up to 5) to inject into context +- **Freshness management**: Memories older than 1 day carry staleness warnings and are verified before citation + +Documentation: **[Usage Guide](docs/memory/01-usage-guide.md)** | **[Implementation Details](docs/memory/02-implementation.md)** + +--- + ## Fixes Compared with the Original Leaked Source The leaked source could not run directly. This repository mainly fixes the following issues: diff --git a/README.md b/README.md index b4998cd8..adcf375f 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ - [环境变量说明](#环境变量说明) - [降级模式](#降级模式) - [Computer Use 桌面控制](#computer-use-桌面控制) +- [记忆系统](#记忆系统) - [常见问题](#常见问题) - [相对于原始泄露源码的修复](#相对于原始泄露源码的修复) - [项目结构](#项目结构) @@ -32,6 +33,7 @@ - 支持 MCP 服务器、插件、Skills - 支持自定义 API 端点和模型([第三方模型使用指南](docs/third-party-models.md)) - **Computer Use 桌面控制**(截屏、鼠标、键盘、应用管理)— [使用指南](docs/computer-use.md) +- **记忆系统**(跨会话持久化记忆,自动提取 + 智能检索)— [使用指南](docs/memory/01-usage-guide.md) | [实现原理](docs/memory/02-implementation.md) - 降级 Recovery CLI 模式 > **Computer Use 说明**:本项目包含**魔改版的 Computer Use** 功能。官方实现依赖 Anthropic 私有原生模块,我们替换了整个底层操作层,使用 Python bridge(`pyautogui` + `mss` + `pyobjc`)实现,使得任何人都可以在 macOS 上使用。详见 [Computer Use 功能指南](docs/computer-use.md)。 @@ -235,6 +237,29 @@ CLAUDE_CODE_FORCE_RECOVERY_CLI=1 ./bin/claude-haha --- +## 记忆系统 + +Claude Code 内置了一套**基于文件的持久化记忆系统**,能够跨会话积累对用户和项目的理解。核心理念:只记住无法从代码中推断出来的东西。 + +**四种记忆类型**: + +| 类型 | 用途 | 示例 | +|------|------|------| +| **User** | 用户角色、技能、偏好 | "深厚 Go 经验,React 新手" | +| **Feedback** | 对 Claude 工作方式的纠正或肯定 | "不要 mock 数据库" | +| **Project** | 无法从代码推导的项目上下文 | "周四后冻结非关键合并" | +| **Reference** | 外部系统的指针 | "Bug 追踪在 Linear INGEST 项目" | + +**核心能力**: + +- **自动提取**:每次对话结束后,后台分叉代理自动分析并保存值得记住的信息 +- **智能检索**:用户提问时,Sonnet 模型从所有记忆中选择最相关的(最多 5 个)注入上下文 +- **新鲜度管理**:超过 1 天的记忆附带陈旧警告,引用前自动验证 + +详细文档:**[使用指南](docs/memory/01-usage-guide.md)** | **[实现原理](docs/memory/02-implementation.md)** + +--- + ## 相对于原始泄露源码的修复 泄露的源码无法直接运行,主要修复了以下问题: diff --git a/docs/memory/01-usage-guide.md b/docs/memory/01-usage-guide.md new file mode 100644 index 00000000..06ca0eda --- /dev/null +++ b/docs/memory/01-usage-guide.md @@ -0,0 +1,256 @@ +# Claude Code 记忆系统 — 使用指南 + +> 让 Claude Code 跨会话记住你是谁、你偏好什么、项目正在发生什么。 + +![记忆系统概览](./images/01-memory-overview.png) + +--- + +## 一、什么是记忆系统? + +Claude Code 的记忆系统是一套**基于文件的持久化知识库**,让 Claude 能够跨越多次对话,持续积累对你和你的项目的理解。 + +核心理念:**只记住无法从代码中推断出来的东西。** + +| 记住 | 不记住 | +|------|--------| +| 你是数据科学家,关注日志系统 | 代码架构、文件结构 | +| "不要 mock 数据库" | Git 历史、谁改了什么 | +| 周四后冻结非关键合并 | 已有的 CLAUDE.md 内容 | +| Bug 跟踪在 Linear 的 INGEST 项目 | 调试方案(修复已在代码里) | + +--- + +## 二、四种记忆类型 + +![四种记忆类型](./images/02-memory-types.png) + +Claude Code 将记忆严格分为四类: + +### 1. User(用户画像) + +记录你的角色、目标、技能水平和偏好,帮助 Claude 调整协作方式。 + +``` +用户说:我写了十年 Go,但这是第一次碰这个仓库的 React 部分 +Claude 保存:深厚 Go 经验,React 新手 — 用后端类比解释前端概念 +``` + +### 2. Feedback(行为反馈) + +你对 Claude 工作方式的纠正或肯定。这类记忆让 Claude 不会犯同样的错。 + +``` +用户说:别在回复末尾总结你做了什么,我能看 diff +Claude 保存:用户要求简洁回复,不要尾部摘要 +``` + +**重要**:不只记录纠正,也记录肯定。如果 Claude 做了一个非显而易见的选择而你认可了,也会被记住。 + +### 3. Project(项目动态) + +无法从代码或 Git 历史中推导出的项目上下文:谁在做什么、为什么、截止日期。 + +``` +用户说:我们周四后冻结所有非关键合并,移动团队要切发布分支 +Claude 保存:2026-03-05 起合并冻结,标记该日期后的非关键 PR 工作 +``` + +**注意**:Claude 会将相对日期("周四")转换为绝对日期("2026-03-05"),确保记忆不会过时失效。 + +### 4. Reference(外部引用) + +指向外部系统中信息的指针:仪表板、工单系统、Slack 频道。 + +``` +用户说:oncall 看的是 grafana.internal/d/api-latency 这个面板 +Claude 保存:grafana.internal/d/api-latency 是 oncall 延迟仪表板 — 编辑请求路径代码时检查 +``` + +--- + +## 三、如何触发记忆保存 + +![记忆触发流程](./images/03-memory-trigger.png) + +### 方式一:自动提取(最常用) + +这是最主要的方式。**你不需要做任何事情**,Claude 会在每次对话结束时自动分析对话内容,提取值得记住的信息。 + +工作流程: +1. 你和 Claude 正常对话 +2. Claude 完成回复(没有工具调用时) +3. 后台启动一个**记忆提取子代理** +4. 子代理分析最近的对话内容 +5. 识别出值得保存的记忆 +6. 写入记忆文件 + 更新 MEMORY.md 索引 + +终端会显示通知: +``` +Memory updated in ~/.claude/projects/.../memory/feedback_testing.md · /memory to edit +``` + +### 方式二:显式要求 + +直接告诉 Claude "记住这个": + +``` +用户:记住,这个项目部署前必须运行 bun test +Claude:[立即保存为 feedback 类型记忆] +``` + +### 方式三:/memory 命令 + +在终端输入 `/memory` 命令,会打开一个文件选择器,让你在编辑器中直接编辑记忆文件。 + +``` +> /memory +``` + +这会列出所有可编辑的记忆文件(CLAUDE.md、CLAUDE.local.md、auto-memory 等),选择后用你的 `$EDITOR` 或 `$VISUAL` 打开。 + +### 方式四:/remember 命令 + +输入 `/remember` 触发记忆审查技能,它会: +- 审查所有自动记忆条目 +- 提议将合适的条目提升到 CLAUDE.md 或 CLAUDE.local.md +- 检测重复、过时和冲突的记忆 +- **不会直接修改**,所有变更需要你批准 + +--- + +## 四、记忆存储在哪里? + +### 目录结构 + +``` +~/.claude/ +└── projects/ + └── {项目路径哈希}/ + └── memory/ ← 自动记忆目录 + ├── MEMORY.md ← 索引文件(始终加载到上下文) + ├── user_role.md ← 用户画像记忆 + ├── feedback_testing.md ← 行为反馈记忆 + ├── project_freeze.md ← 项目动态记忆 + ├── reference_linear.md ← 外部引用记忆 + └── team/ ← 团队共享记忆(如启用) + ├── MEMORY.md + └── ... +``` + +### 记忆文件格式 + +每个记忆文件使用 YAML frontmatter + Markdown 内容: + +```markdown +--- +name: 测试策略偏好 +description: 集成测试必须使用真实数据库,不要 mock +type: feedback +--- + +集成测试必须使用真实数据库,不要 mock。 + +**Why:** 上季度 mock 测试通过但生产环境迁移失败,mock/生产差异掩盖了问题。 + +**How to apply:** 编写或审查测试时,确保数据库操作使用真实连接。 +``` + +### MEMORY.md 索引文件 + +MEMORY.md 是索引而不是内容。它**始终加载到上下文**中,每行一个条目: + +```markdown +- [用户角色](user_role.md) — 数据科学家,关注可观测性/日志 +- [测试策略](feedback_testing.md) — 集成测试用真实数据库,不 mock +- [合并冻结](project_freeze.md) — 2026-03-05 起冻结非关键合并 +- [Bug 追踪](reference_linear.md) — 流水线 bug 在 Linear INGEST 项目 +``` + +**限制**:最多 200 行或 25KB,超出会被截断。 + +--- + +## 五、如何管理记忆 + +### 让 Claude 遗忘 + +``` +用户:忘记关于合并冻结的记忆 +Claude:[找到并删除相关记忆文件和索引条目] +``` + +### 让 Claude 忽略记忆 + +``` +用户:忽略记忆,从零开始 +Claude:[本次对话中不使用任何记忆内容] +``` + +### 手动编辑 + +直接编辑 `~/.claude/projects/{hash}/memory/` 下的文件,或使用 `/memory` 命令。 + +### 禁用自动记忆 + +| 方法 | 做法 | +|------|------| +| 环境变量 | `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` | +| 设置文件 | `settings.json` 中 `"autoMemoryEnabled": false` | +| 精简模式 | `--bare` 启动 / `CLAUDE_CODE_SIMPLE=1` | + +### 自定义记忆目录 + +在 `~/.claude/settings.json` 中设置: + +```json +{ + "autoMemoryDirectory": "~/my-claude-memories" +} +``` + +支持 `~/` 展开。出于安全考虑,项目级 `.claude/settings.json` **不允许**设置此项。 + +--- + +## 六、记忆的生命周期 + +![记忆生命周期](./images/04-memory-lifecycle.png) + +``` +对话中学到新信息 + ↓ + 自动提取 / 显式保存 + ↓ + 写入记忆文件 + 索引 + ↓ + 下次对话加载 MEMORY.md + ↓ + 智能选择相关记忆(Sonnet) + ↓ + 注入到对话上下文 + ↓ + 记忆变旧?验证后再使用 + ↓ + 过时?更新或删除 +``` + +### 新鲜度管理 + +- **今天/昨天的记忆**:直接使用 +- **超过 1 天的记忆**:附带陈旧警告,提醒 Claude 验证后再引用 +- **引用文件路径/函数名的记忆**:使用前先 grep 确认还存在 + +--- + +## 七、快速参考 + +| 操作 | 方法 | +|------|------| +| 让 Claude 记住 | "记住:这个项目用 bun 不用 npm" | +| 让 Claude 忘记 | "忘记关于 XXX 的记忆" | +| 编辑记忆 | `/memory` 命令 | +| 审查和整理 | `/remember` 命令 | +| 忽略记忆 | "忽略记忆" / "不要用记忆" | +| 禁用自动记忆 | `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1` | +| 查看记忆目录 | `~/.claude/projects/{hash}/memory/` | diff --git a/docs/memory/02-implementation.md b/docs/memory/02-implementation.md new file mode 100644 index 00000000..758d0523 --- /dev/null +++ b/docs/memory/02-implementation.md @@ -0,0 +1,453 @@ +# Claude Code 记忆系统 — 实现原理 + +> 从系统提示词注入到后台自动提取,拆解记忆系统的每一个技术细节。 + +![实现架构总览](./images/05-architecture-overview.png) + +--- + +## 一、整体架构 + +记忆系统由 5 个核心模块协作完成: + +| 模块 | 源码位置 | 职责 | +|------|----------|------| +| **路径解析** | `src/memdir/paths.ts` | 计算记忆存储目录,处理覆盖和安全校验 | +| **提示词构建** | `src/memdir/memdir.ts` | 将记忆指令注入系统提示词 | +| **记忆扫描** | `src/memdir/memoryScan.ts` | 扫描目录、解析 frontmatter、排序 | +| **智能检索** | `src/memdir/findRelevantMemories.ts` | 用 Sonnet 选择与当前查询相关的记忆 | +| **自动提取** | `src/services/extractMemories/` | 后台分叉代理,从对话中提取记忆 | + +辅助模块: + +| 模块 | 源码位置 | 职责 | +|------|----------|------| +| **类型定义** | `src/memdir/memoryTypes.ts` | 四种记忆类型的分类法和提示词模板 | +| **新鲜度** | `src/memdir/memoryAge.ts` | 计算记忆年龄、生成陈旧警告 | +| **文件检测** | `src/utils/memoryFileDetection.ts` | 判断路径是否属于记忆系统 | +| **代理记忆** | `src/tools/AgentTool/agentMemory.ts` | 子代理专属的三级记忆目录 | +| **团队同步** | `src/services/teamMemorySync/` | 记忆的远程上传/下载 | + +--- + +## 二、路径解析系统 + +![路径解析流程](./images/06-path-resolution.png) + +### 核心函数:`getAutoMemPath()` + +``` +路径解析优先级(从高到低): + +1. CLAUDE_COWORK_MEMORY_PATH_OVERRIDE ← Cowork 环境变量(完整路径) +2. settings.json → autoMemoryDirectory ← 用户设置(支持 ~/ 展开) +3. {memoryBase}/projects/{sanitized-git-root}/memory/ ← 默认计算路径 +``` + +**关键源码** `src/memdir/paths.ts:223`: + +```typescript +export const getAutoMemPath = memoize( + (): string => { + const override = getAutoMemPathOverride() ?? getAutoMemPathSetting() + if (override) return override + const projectsDir = join(getMemoryBaseDir(), 'projects') + return join(projectsDir, sanitizePath(getAutoMemBase()), AUTO_MEM_DIRNAME) + sep + }, + () => getProjectRoot(), // 缓存 key = 项目根目录 +) +``` + +### 路径安全校验 + +`validateMemoryPath()` 拒绝危险路径: + +| 被拒路径 | 原因 | +|----------|------| +| `../foo` | 相对路径,CWD 相关 | +| `/` 或 `/a` | 根路径或过短路径 | +| `C:\` | Windows 驱动器根目录 | +| `\\server\share` | UNC 网络路径 | +| 含 `\0` | 空字节,可在系统调用中截断 | + +**安全限制**:项目级 `.claude/settings.json` **不允许**设置 `autoMemoryDirectory`,防止恶意仓库通过此项获取对 `~/.ssh` 等敏感目录的写权限。 + +### 启用条件 + +`isAutoMemoryEnabled()` 的判断链: + +``` +CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 → 关闭 +CLAUDE_CODE_SIMPLE (--bare) → 关闭 +远程模式 且 无 REMOTE_MEMORY_DIR → 关闭 +settings.json autoMemoryEnabled → 跟随设置 +默认 → 开启 +``` + +--- + +## 三、系统提示词注入 + +![提示词注入流程](./images/07-prompt-injection.png) + +### 入口:`loadMemoryPrompt()` + +这是记忆系统与系统提示词的接口。启动时调用一次(通过 `systemPromptSection` 缓存)。 + +``` +loadMemoryPrompt() + ├─ KAIROS 模式?→ buildAssistantDailyLogPrompt() [日志追加模式] + ├─ TEAMMEM 开启?→ buildCombinedMemoryPrompt() [个人+团队双目录] + ├─ 正常模式 → buildMemoryLines() [单目录] + └─ 禁用 → return null +``` + +### `buildMemoryLines()` 构建的提示词结构 + +``` +# auto memory + +你有一个持久化的文件记忆系统,位于 `{memoryDir}`... + +## Types of memory ← 四种类型的定义和示例 +## What NOT to save ← 排除规则 +## How to save memories ← 两步保存流程 +## When to access memories ← 何时查阅 +## Before recommending ← 引用前验证 +## Memory and other forms ← 与 Plan/Task 的区别 + +## MEMORY.md ← 索引内容(或"当前为空") +``` + +### MEMORY.md 截断策略 + +`truncateEntrypointContent()` 执行双重限制: + +```typescript +// 先截断行数 +if (lineCount > 200) → 截断到 200 行 + +// 再截断字节数(处理超长行) +if (bytes > 25,000) → 在最后一个换行符处截断 + +// 附加警告 +"WARNING: MEMORY.md is {reason}. Only part of it was loaded." +``` + +### 目录自动创建 + +`ensureMemoryDirExists()` 在加载提示词时确保目录存在: +- 递归创建 `mkdir`(处理整个父链) +- 吞掉 `EEXIST`(幂等) +- 真正的权限错误只记日志不中断(Write 工具会显示真实错误) + +提示词中明确告知模型目录已存在,避免浪费 turn 执行 `ls` 或 `mkdir`。 + +--- + +## 四、自动记忆提取 + +![自动提取流程](./images/08-auto-extraction.png) + +### 触发时机 + +在 `handleStopHooks` 中,当模型产生最终响应(无工具调用)时触发。 + +**关键源码** `src/services/extractMemories/extractMemories.ts` + +### 完整提取流程 + +``` +1. 模型完成回复(无 tool_use) + ↓ +2. executeExtractMemories() 被调用 + ↓ +3. 守卫检查: + - 是主代理?(子代理不提取) + - 功能门控开启? + - 自动记忆启用? + - 非远程模式? + - 没有并行提取在进行? + ↓ +4. 频率控制: + turnsSinceLastExtraction++ + if < tengu_bramble_lintel → 跳过 + ↓ +5. 互斥检查: + 主代理自己写了记忆?→ 跳过,推进游标 + ↓ +6. 扫描现有记忆目录(scanMemoryFiles) + 生成清单(formatMemoryManifest) + ↓ +7. 构建提取提示词(buildExtractAutoOnlyPrompt) + ↓ +8. 运行分叉代理(runForkedAgent) + - 共享父会话的提示词缓存 + - 最多 5 个 turn + - 限制工具权限 + ↓ +9. 提取写入的文件路径 + 推进游标到最新消息 + ↓ +10. 通知用户:"Memory updated in ..." +``` + +### 分叉代理(Forked Agent) + +自动提取使用 `runForkedAgent` — 这是对主会话的完美分叉: + +- **共享提示词缓存**:避免重复的 API 缓存创建费用 +- **隔离执行**:不影响主会话的消息历史 +- **受限工具**:只允许 Read、Grep、Glob、只读 Bash、以及对记忆目录的 Edit/Write +- **不记录转录**:防止与主线程的竞争条件 + +### 工具权限(`createAutoMemCanUseTool`) + +``` +✅ 允许:Read, Grep, Glob(无限制) +✅ 允许:Bash(仅只读命令:ls, find, grep, cat, stat...) +✅ 允许:Edit/Write(仅 auto-memory 目录内) +❌ 拒绝:MCP, Agent, 非只读 Bash, 其他写操作 +``` + +### 互斥机制 + +主代理和提取代理是**互斥的**: + +```typescript +function hasMemoryWritesSince(messages, sinceUuid): boolean { + // 扫描 sinceUuid 之后的所有 assistant 消息 + // 如果有任何 Edit/Write 的 tool_use 指向 auto-memory 目录 + // → return true(跳过提取,推进游标) +} +``` + +这避免了重复保存:主代理已经写了记忆时,后台提取直接跳过。 + +### 合并机制 + +如果前一次提取还在运行: +1. 新的上下文被暂存(`pendingContext`) +2. 旧提取完成后,立即启动一次**尾部提取** +3. 尾部提取只处理两次调用之间新增的消息 + +--- + +## 五、智能记忆检索 + +![记忆检索流程](./images/09-memory-retrieval.png) + +### 工作原理 + +每次用户发送查询时,`findRelevantMemories()` 被触发: + +``` +1. scanMemoryFiles(memoryDir) + - 递归读取所有 .md 文件(排除 MEMORY.md) + - 解析 frontmatter(前 30 行) + - 按修改时间降序排序 + - 最多 200 个文件 + ↓ +2. 过滤已展示过的记忆(alreadySurfaced) + ↓ +3. 格式化清单(formatMemoryManifest) + - [type] filename (ISO timestamp): description + ↓ +4. Sonnet 模型选择(sideQuery) + - 系统提示:你是记忆选择器... + - 用户消息:Query + Available memories + Recently used tools + - 输出:JSON { selected_memories: string[] } + - 最多选 5 个 + ↓ +5. 返回选中记忆的 { path, mtimeMs } +``` + +### Sonnet 选择器的提示词 + +``` +你正在选择对 Claude Code 处理用户查询有用的记忆。 +你将收到用户查询和可用记忆文件列表(含文件名和描述)。 + +返回最多 5 个明确有用的记忆文件名。 +- 不确定是否有用就不要选 +- 没有明确有用的就返回空列表 +- 如果提供了最近使用的工具列表,不要选这些工具的使用文档 + (但 DO 选择关于这些工具的警告/陷阱/已知问题) +``` + +### 新鲜度警告 + +选中的记忆在注入上下文时会附带新鲜度信息: + +```typescript +function memoryFreshnessText(mtimeMs: number): string { + const d = memoryAgeDays(mtimeMs) + if (d <= 1) return '' // 今天/昨天:无警告 + return `This memory is ${d} days old. Memories are point-in-time observations... + Verify against current code before asserting as fact.` +} +``` + +--- + +## 六、记忆扫描详解 + +### `scanMemoryFiles()` + +**关键设计**:单次遍历(read-then-sort),避免双重 stat 系统调用。 + +```typescript +async function scanMemoryFiles(memoryDir, signal): Promise { + const entries = await readdir(memoryDir, { recursive: true }) + const mdFiles = entries.filter(f => f.endsWith('.md') && basename(f) !== 'MEMORY.md') + + // 并行读取所有文件的 frontmatter(前 30 行) + const headerResults = await Promise.allSettled( + mdFiles.map(async (relativePath) => { + const { content, mtimeMs } = await readFileInRange(filePath, 0, 30) + const { frontmatter } = parseFrontmatter(content) + return { filename, filePath, mtimeMs, description, type } + }) + ) + + // 过滤成功的、按时间降序排序、取前 200 + return fulfilled.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, 200) +} +``` + +### `formatMemoryManifest()` + +生成供 Sonnet 或提取代理消费的清单格式: + +``` +- [feedback] testing_policy.md (2026-03-15T10:30:00.000Z): 集成测试用真实数据库 +- [user] role.md (2026-03-14T08:00:00.000Z): 数据科学家,关注日志 +- [project] freeze.md (2026-03-10T15:00:00.000Z): 3/5 起合并冻结 +``` + +--- + +## 七、代理记忆(Agent Memory) + +![代理记忆三级作用域](./images/10-agent-memory.png) + +子代理(通过 Agent 工具启动的)有独立的三级记忆系统: + +| 作用域 | 路径 | 说明 | +|--------|------|------| +| **user** | `~/.claude/agent-memory/{agentType}/` | 全局用户级 | +| **project** | `.claude/agent-memory/{agentType}/` | 项目级(提交到 VCS) | +| **local** | `.claude/agent-memory-local/{agentType}/` | 本地级(不提交) | + +代理记忆与主记忆的差异: +- 无 MEMORY.md 索引步骤(`skipIndex = true`) +- 直接写文件即可,无需两步操作 +- 各代理类型隔离(explorer、planner 等各有各的目录) + +--- + +## 八、团队记忆同步 + +当 `TEAMMEM` feature flag 开启时: + +### 目录结构 + +``` +~/.claude/projects/{hash}/memory/ +├── MEMORY.md ← 个人记忆索引 +├── user_*.md ← 个人记忆 +└── team/ ← 团队共享目录 + ├── MEMORY.md ← 团队记忆索引 + └── *.md ← 团队记忆 +``` + +### 同步 API + +``` +GET /api/claude_code/team_memory?repo={owner/repo} ← 拉取 +PUT /api/claude_code/team_memory?repo={owner/repo} ← 推送 +``` + +### 同步语义 + +- **Pull**:服务器内容覆盖本地文件 +- **Push**:仅上传内容哈希不同的键(delta 上传) +- **删除不传播**:本地删除不会删除远程 +- **限制**:单文件最大 250KB,上传体最大 200KB(分批) + +### 团队 vs 个人的路由规则 + +在 `memoryTypes.ts` 中,每种类型有 `` 指导: + +| 类型 | 默认作用域 | +|------|-----------| +| user | 始终个人 | +| feedback | 默认个人,项目级规范放团队 | +| project | 偏向团队 | +| reference | 通常团队 | + +--- + +## 九、关键常量速查 + +```typescript +// 索引文件 +ENTRYPOINT_NAME = 'MEMORY.md' +MAX_ENTRYPOINT_LINES = 200 +MAX_ENTRYPOINT_BYTES = 25_000 + +// 扫描 +MAX_MEMORY_FILES = 200 +FRONTMATTER_MAX_LINES = 30 + +// 路径 +AUTO_MEM_DIRNAME = 'memory' + +// 提取 +maxTurns = 5 // 分叉代理最多 5 个 turn + +// 检索 +最多返回 5 个相关记忆 +``` + +--- + +## 十、数据流总览 + +``` +┌─────────────────────────────────────────────────────┐ +│ 会话启动 │ +│ │ +│ loadMemoryPrompt() │ +│ → ensureMemoryDirExists() │ +│ → buildMemoryLines() + MEMORY.md 内容 │ +│ → 注入系统提示词 │ +└────────────────────────┬────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────┐ +│ 用户提问 │ +│ │ +│ findRelevantMemories() │ +│ → scanMemoryFiles() [扫描 + frontmatter] │ +│ → Sonnet 选择最多 5 个相关记忆 │ +│ → 注入对话上下文 + 新鲜度警告 │ +└────────────────────────┬────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────┐ +│ Claude 回复 │ +│ │ +│ 模型可能直接写记忆(遵循系统提示词指导) │ +│ 或者不写 → 触发后台提取 │ +└────────────────────────┬────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────┐ +│ 后台自动提取 │ +│ │ +│ executeExtractMemories() │ +│ → 互斥检查(主代理已写?跳过) │ +│ → 构建提取提示词 + 记忆清单 │ +│ → runForkedAgent() [共享缓存, 限制工具, 5 turns] │ +│ → 写入新记忆文件 + 更新 MEMORY.md │ +│ → 通知用户 │ +└─────────────────────────────────────────────────────┘ +``` diff --git a/docs/memory/README.md b/docs/memory/README.md new file mode 100644 index 00000000..91a6a1ef --- /dev/null +++ b/docs/memory/README.md @@ -0,0 +1,99 @@ +# Claude Code 记忆系统文档 + +> 完整的记忆系统使用指南和实现原理文档 + +--- + +## 📚 文档目录 + +### [01-usage-guide.md](./01-usage-guide.md) — 使用指南 + +面向用户的完整使用手册,涵盖: + +- **四种记忆类型**:User(用户画像)、Feedback(行为反馈)、Project(项目动态)、Reference(外部引用) +- **四种触发方式**:自动提取、显式请求、`/memory` 命令、`/remember` 命令 +- **存储格式**:YAML frontmatter + Markdown 内容 +- **管理操作**:遗忘、忽略、手动编辑、禁用、自定义目录 +- **生命周期**:从学习到注入,新鲜度管理 + +**适合人群**:所有 Claude Code 用户 + +--- + +### [02-implementation.md](./02-implementation.md) — 实现原理 + +面向开发者的技术深度解析,涵盖: + +- **5 大核心模块**:路径解析、提示词构建、记忆扫描、智能检索、自动提取 +- **路径解析系统**:优先级链、安全校验、启用条件 +- **系统提示词注入**:`loadMemoryPrompt()` → `buildMemoryLines()`,MEMORY.md 截断策略 +- **自动记忆提取**:分叉代理、互斥机制、工具权限、合并机制 +- **智能检索**:`scanMemoryFiles()` → Sonnet 选择 → 新鲜度警告 +- **代理记忆**:三级作用域(user/project/local) +- **团队记忆同步**:Pull/Push API、合并语义 +- **完整数据流**:从会话启动到上下文注入 + +**适合人群**:贡献者、架构师、想深入了解实现的开发者 + +--- + +## 🖼️ 配图说明 + +所有配图采用深色背景(#1a1a2e)+ Anthropic 品牌橙铜色(#D97757)风格,与 Claude Code 官方文档一致。 + +| 图片 | 说明 | 尺寸 | +|------|------|------| +| `01-memory-overview.png` | 记忆系统概览 — 四层架构(触发/类型/存储/检索) | 632 KB | +| `02-memory-types.png` | 四种记忆类型 — 2x2 网格展示 User/Feedback/Project/Reference | 507 KB | +| `03-memory-trigger.png` | 记忆触发流程 — 从对话到存储的四种路径 | 474 KB | +| `04-memory-lifecycle.png` | 记忆生命周期 — 完整循环流程 + 新鲜度判断 | 1.0 MB | +| `05-architecture-overview.png` | 实现架构总览 — 5 个核心模块 + 辅助模块 | 3.5 MB | +| `06-path-resolution.png` | 路径解析流程 — 三层优先级 + 安全校验 | 1.0 MB | +| `07-prompt-injection.png` | 提示词注入流程 — loadMemoryPrompt 分发逻辑 | 1.1 MB | +| `08-auto-extraction.png` | 自动提取流程 — 分叉代理完整流程 | 1.2 MB | +| `09-memory-retrieval.png` | 智能检索流程 — Sonnet 选择 + 新鲜度管理 | 816 KB | +| `10-agent-memory.png` | 代理记忆作用域 — 三级嵌套结构 | 523 KB | + +--- + +## 🚀 快速开始 + +### 用户 + +1. 阅读 [使用指南](./01-usage-guide.md) +2. 了解四种记忆类型和触发方式 +3. 尝试 `/memory` 和 `/remember` 命令 + +### 开发者 + +1. 阅读 [实现原理](./02-implementation.md) +2. 查看源码位置: + - `src/memdir/paths.ts` — 路径解析 + - `src/memdir/memdir.ts` — 提示词构建 + - `src/memdir/memoryScan.ts` — 记忆扫描 + - `src/memdir/findRelevantMemories.ts` — 智能检索 + - `src/services/extractMemories/` — 自动提取 +3. 理解数据流和模块交互 + +--- + +## 📝 核心概念速查 + +| 概念 | 说明 | +|------|------| +| **MEMORY.md** | 索引文件,始终加载到上下文(最多 200 行 / 25KB) | +| **主题文件** | `*.md` 文件,包含 frontmatter + 内容 | +| **自动提取** | 每次回复后后台运行,分叉代理分析对话 | +| **智能检索** | Sonnet 模型从所有记忆中选择最多 5 个相关的 | +| **新鲜度** | ≤1 天无警告,>1 天附带陈旧警告 | +| **分叉代理** | 共享提示词缓存,限制工具权限,最多 5 turns | +| **三级作用域** | 代理记忆:user(全局)> project(项目)> local(本地) | + +--- + +## 🔗 相关资源 + +- [Claude Code 主文档](../) +- [记忆系统源码](../../src/memdir/) +- [自动提取服务](../../src/services/extractMemories/) +- [GitHub Issues](https://github.com/anthropics/claude-code/issues) diff --git a/docs/memory/images/01-memory-overview.png b/docs/memory/images/01-memory-overview.png new file mode 100644 index 00000000..99e20bf2 Binary files /dev/null and b/docs/memory/images/01-memory-overview.png differ diff --git a/docs/memory/images/02-memory-types.png b/docs/memory/images/02-memory-types.png new file mode 100644 index 00000000..81f4f934 Binary files /dev/null and b/docs/memory/images/02-memory-types.png differ diff --git a/docs/memory/images/03-memory-trigger.png b/docs/memory/images/03-memory-trigger.png new file mode 100644 index 00000000..65475ab0 Binary files /dev/null and b/docs/memory/images/03-memory-trigger.png differ diff --git a/docs/memory/images/04-memory-lifecycle.png b/docs/memory/images/04-memory-lifecycle.png new file mode 100644 index 00000000..9667167b Binary files /dev/null and b/docs/memory/images/04-memory-lifecycle.png differ diff --git a/docs/memory/images/05-architecture-overview.png b/docs/memory/images/05-architecture-overview.png new file mode 100644 index 00000000..c28aa16c Binary files /dev/null and b/docs/memory/images/05-architecture-overview.png differ diff --git a/docs/memory/images/06-path-resolution.png b/docs/memory/images/06-path-resolution.png new file mode 100644 index 00000000..9fe084de Binary files /dev/null and b/docs/memory/images/06-path-resolution.png differ diff --git a/docs/memory/images/07-prompt-injection.png b/docs/memory/images/07-prompt-injection.png new file mode 100644 index 00000000..b52d3832 Binary files /dev/null and b/docs/memory/images/07-prompt-injection.png differ diff --git a/docs/memory/images/08-auto-extraction.png b/docs/memory/images/08-auto-extraction.png new file mode 100644 index 00000000..24bf9ae4 Binary files /dev/null and b/docs/memory/images/08-auto-extraction.png differ diff --git a/docs/memory/images/09-memory-retrieval.png b/docs/memory/images/09-memory-retrieval.png new file mode 100644 index 00000000..56a62962 Binary files /dev/null and b/docs/memory/images/09-memory-retrieval.png differ diff --git a/docs/memory/images/10-agent-memory.png b/docs/memory/images/10-agent-memory.png new file mode 100644 index 00000000..92279535 Binary files /dev/null and b/docs/memory/images/10-agent-memory.png differ