memory-quality-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. memory_quality_mcp-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  2. memory_quality_mcp-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
  3. memory_quality_mcp-0.1.0/.github/ISSUE_TEMPLATE/wrong_score.md +31 -0
  4. memory_quality_mcp-0.1.0/BUILD_PLAN.md +218 -0
  5. memory_quality_mcp-0.1.0/CLAUDE_CODE_INTERNALS.md +360 -0
  6. memory_quality_mcp-0.1.0/DESIGN.md +446 -0
  7. memory_quality_mcp-0.1.0/ISSUES.md +255 -0
  8. memory_quality_mcp-0.1.0/LICENSE +21 -0
  9. memory_quality_mcp-0.1.0/PKG-INFO +290 -0
  10. memory_quality_mcp-0.1.0/README.md +264 -0
  11. memory_quality_mcp-0.1.0/README_CN.md +280 -0
  12. memory_quality_mcp-0.1.0/benchmark/README.md +203 -0
  13. memory_quality_mcp-0.1.0/benchmark/dataset.json +189 -0
  14. memory_quality_mcp-0.1.0/config.yaml +55 -0
  15. memory_quality_mcp-0.1.0/examples/demo_memories/MEMORY.md +10 -0
  16. memory_quality_mcp-0.1.0/examples/demo_memories/code_commenting_preference.md +11 -0
  17. memory_quality_mcp-0.1.0/examples/demo_memories/code_commenting_style.md +11 -0
  18. memory_quality_mcp-0.1.0/examples/demo_memories/explanation_approach_preference.md +10 -0
  19. memory_quality_mcp-0.1.0/examples/demo_memories/project_retail_inventory_analysis.md +16 -0
  20. memory_quality_mcp-0.1.0/examples/demo_memories/step2_memory_reading_development.md +10 -0
  21. memory_quality_mcp-0.1.0/examples/demo_memories/user_background.md +10 -0
  22. memory_quality_mcp-0.1.0/examples/demo_memories/user_communication_preference.md +11 -0
  23. memory_quality_mcp-0.1.0/examples/demo_memories/user_dietary_preferences.md +15 -0
  24. memory_quality_mcp-0.1.0/examples/demo_memories/user_expertise_level.md +10 -0
  25. memory_quality_mcp-0.1.0/examples/demo_memories/writing_style_feedback.md +10 -0
  26. memory_quality_mcp-0.1.0/pyproject.toml +48 -0
  27. memory_quality_mcp-0.1.0/scripts/generate_memories.py +692 -0
  28. memory_quality_mcp-0.1.0/scripts/seed_memories.py +342 -0
  29. memory_quality_mcp-0.1.0/scripts/test_live.py +172 -0
  30. memory_quality_mcp-0.1.0/src/__init__.py +1 -0
  31. memory_quality_mcp-0.1.0/src/config.py +201 -0
  32. memory_quality_mcp-0.1.0/src/dashboard.py +769 -0
  33. memory_quality_mcp-0.1.0/src/llm_client.py +252 -0
  34. memory_quality_mcp-0.1.0/src/memory_reader.py +605 -0
  35. memory_quality_mcp-0.1.0/src/memory_writer.py +198 -0
  36. memory_quality_mcp-0.1.0/src/prompts.py +186 -0
  37. memory_quality_mcp-0.1.0/src/quality_engine.py +605 -0
  38. memory_quality_mcp-0.1.0/src/server.py +753 -0
  39. memory_quality_mcp-0.1.0/src/session_store.py +250 -0
  40. memory_quality_mcp-0.1.0/tests/test_memory_reader.py +354 -0
  41. memory_quality_mcp-0.1.0/tests/test_quality_engine.py +468 -0
  42. memory_quality_mcp-0.1.0/tests/test_session_store.py +138 -0
  43. memory_quality_mcp-0.1.0/tests/test_step4.py +426 -0
  44. memory_quality_mcp-0.1.0/uv.lock +1179 -0
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Something isn't working correctly
4
+ title: "Bug: "
5
+ labels: bug
6
+ ---
7
+
8
+ **Describe the bug**
9
+ <!-- A clear description of what went wrong -->
10
+
11
+ **To reproduce**
12
+ 1.
13
+ 2.
14
+ 3.
15
+
16
+ **Expected behavior**
17
+
18
+ **Actual behavior**
19
+
20
+ **Environment**
21
+ - OS:
22
+ - Claude Code version (`claude --version`):
23
+ - Python version:
24
+ - LLM provider configured:
25
+
26
+ **Error message (if any)**
27
+ ```
28
+ paste error here
29
+ ```
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: Feature Request
3
+ about: Suggest an improvement or new feature
4
+ title: "Feature: "
5
+ labels: enhancement
6
+ ---
7
+
8
+ **What problem does this solve?**
9
+ <!-- Describe the pain point or use case -->
10
+
11
+ **Proposed solution**
12
+ <!-- How would you like it to work? -->
13
+
14
+ **Alternatives you've considered**
15
+
16
+ **Additional context**
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: Wrong Score
3
+ about: A memory was scored incorrectly — help us improve the model
4
+ title: "Wrong Score: [filename]"
5
+ labels: wrong-score
6
+ ---
7
+
8
+ **Memory filename**
9
+ <!-- e.g. user_background.md -->
10
+
11
+ **My memory content (or a summary)**
12
+ <!-- Paste or describe the memory content -->
13
+
14
+ **What the plugin scored it as**
15
+ - [ ] keep
16
+ - [ ] review
17
+ - [ ] delete
18
+
19
+ **What it should be**
20
+ - [ ] keep
21
+ - [ ] review
22
+ - [ ] delete
23
+
24
+ **Why do you think so?**
25
+ <!-- The more context, the better — this directly helps calibrate the scoring model -->
26
+
27
+ **Memory type** (if known)
28
+ - [ ] user
29
+ - [ ] feedback
30
+ - [ ] project
31
+ - [ ] reference
@@ -0,0 +1,218 @@
1
+ # Memory Quality MCP · 构建计划
2
+
3
+ > 目标:跑通 Step 1-4(脚手架 → 文件读取 → 评分引擎 → 四个 MCP 工具)
4
+ > Step 5(Benchmark)之后单独启动
5
+ > 最后更新:2026-04-04
6
+
7
+ ---
8
+
9
+ ## 依赖关系图
10
+
11
+ ```
12
+ Step 1:脚手架
13
+ └── Step 2:记忆文件读取层
14
+ ├── Step 3:质量评分引擎
15
+ │ └── Step 4a:memory_score() ← 最简单,先做
16
+ │ └── Step 4b:memory_audit()
17
+ │ └── Step 4c:memory_report()
18
+ │ └── Step 4d:memory_cleanup() ← 最后做,涉及写操作
19
+ └── Step 6:集成测试 + 打包(Step 4 完成后)
20
+ ```
21
+
22
+ **串行依赖**:1 → 2 → 3 → 4a → 4b → 4c → 4d
23
+ **没有可并行的部分**:每一步都依赖上一步的输出。
24
+
25
+ ---
26
+
27
+ ## Step 1:项目脚手架
28
+
29
+ **目标**:`uvx memory-quality-mcp` 能启动,Claude Code 能识别到这个 MCP server。
30
+
31
+ **产出文件**:
32
+ ```
33
+ memory-quality-mcp/
34
+ ├── pyproject.toml ← 依赖声明(mcp SDK、anthropic、pyyaml)
35
+ ├── config.yaml ← 评分阈值、API key 占位
36
+ └── src/
37
+ ├── __init__.py
38
+ └── server.py ← MCP server 入口,注册工具名(逻辑先留空)
39
+ ```
40
+
41
+ **验收标准**:
42
+ - `uv run python -m src.server` 能启动不报错
43
+ - Claude Code 的 MCP 配置里加入后,能看到 4 个工具名
44
+
45
+ ---
46
+
47
+ ## Step 2:记忆文件读取层
48
+
49
+ **目标**:能正确扫描本机真实记忆目录,返回结构化数据。
50
+
51
+ **产出文件**:
52
+ ```
53
+ src/memory_reader.py
54
+ ```
55
+
56
+ **实现内容**:
57
+ - `get_memory_dir()` ——解析实际路径,优先级:
58
+ 1. `CLAUDE_CODE_REMOTE_MEMORY_DIR` 环境变量
59
+ 2. `~/.claude/settings.json` 的 `autoMemoryDirectory` 字段
60
+ 3. 默认:`~/.claude/projects/<sanitized-git-root>/memory/`
61
+ - `scan_memory_files()` ——遍历目录,只读前 30 行(frontmatter),返回 header 列表
62
+ - 排除 MEMORY.md
63
+ - 按 mtime 降序排列
64
+ - 上限 200 个文件
65
+ - `read_memory_file(path)` ——读取单条记忆的完整内容
66
+ - `parse_frontmatter(content)` ——解析 name / description / type / mtime
67
+ - `check_memory_index_health()` ——检测 MEMORY.md 是否接近 200 行 / 25KB 上限
68
+
69
+ **边界情况**:
70
+ - 目录不存在 → 返回空列表 + 提示,不报错
71
+ - type 字段缺失 → 降级处理(type=None),不崩溃
72
+ - frontmatter 格式损坏 → 跳过该文件,记录 warning
73
+
74
+ **验收标准**:
75
+ - 对本机真实记忆目录跑一遍,打印所有记忆的 name / type / mtime,结果正确
76
+
77
+ ---
78
+
79
+ ## Step 3:质量评分引擎
80
+
81
+ **目标**:对一批记忆做四维质量评分,输出结构化结果。
82
+
83
+ **产出文件**:
84
+ ```
85
+ src/quality_engine.py
86
+ src/prompts.py ← 所有 LLM prompt 模板,集中管理
87
+ ```
88
+
89
+ **实现顺序**(先规则,后 LLM):
90
+
91
+ ### 3a. 规则引擎(零 API 成本的初筛)
92
+
93
+ 直接从 frontmatter 识别明显信号,不调 LLM:
94
+
95
+ | 规则 | 信号 | 处理方式 |
96
+ |------|------|---------|
97
+ | `type=project` + mtime > 90天 | 时效性极低 | 时效性预打分 1/5,标记待 LLM 确认 |
98
+ | 无 `**Why:**` 结构 | 可信度存疑 | 可信度预打分降权 |
99
+ | 内容符合「不该存」规则 | 低质量 | 直接标记为「建议删除」,跳过 LLM |
100
+ | `type=user` + mtime > 180天 | 可能过时 | 时效性预打分 2/5 |
101
+
102
+ 「不该存」规则(来自 Anthropic 官方 `WHAT_NOT_TO_SAVE_SECTION`):
103
+ - 描述代码模式 / 架构 / 文件路径
104
+ - 描述 git 历史 / 近期变更
105
+ - 临时任务状态、当前会话进行中的工作
106
+ - CLAUDE.md 里已有的内容
107
+
108
+ ### 3b. LLM 评分(Haiku,批量 5-8 条)
109
+
110
+ 对规则引擎未能直接判断的记忆,发给 LLM 做四维评分:
111
+
112
+ ```
113
+ 输入:一批记忆(5-8 条),每条包含完整内容
114
+ 输出:每条的四维评分 + 建议操作 + 原因
115
+ ```
116
+
117
+ **四维定义**(详见 DESIGN.md 第五节):
118
+ - 重要性(40%):对未来对话的帮助程度
119
+ - 时效性(25%):信息是否仍然准确
120
+ - 可信度(15%):是否有明确来源
121
+ - 准确性(20%):记录是否忠实于来源(可信度 < 3 时标为「无法评估」)
122
+
123
+ **综合分**:
124
+ ```
125
+ < 2.5 → 建议删除
126
+ 2.5-3.5 → 建议复查
127
+ > 3.5 → 保留
128
+ ```
129
+
130
+ ### 3c. 冲突检测
131
+
132
+ 在同批次内,检测两两语义矛盾:
133
+ ```
134
+ 例:「用户喜欢简洁代码」vs「用户要求注释详尽」→ 潜在冲突
135
+ ```
136
+
137
+ **验收标准**:
138
+ - 对 10 条样本记忆跑评分,结果符合直觉
139
+ - 批量调用:50 条记忆 ≤ 10 次 API 调用
140
+
141
+ ---
142
+
143
+ ## Step 4:四个 MCP 工具
144
+
145
+ **目标**:在 server.py 里实现四个工具,能跑完整对话流程。
146
+
147
+ **实现顺序**(按依赖和复杂度):
148
+
149
+ ### 4a. `memory_score(content: str)`
150
+ - 最简单,单条评分
151
+ - 直接调用 quality_engine 的 LLM 评分
152
+ - 用于调试和验证评分模型
153
+
154
+ ### 4b. `memory_audit()`
155
+ - 调用 scan_memory_files() + 规则引擎
156
+ - 返回健康摘要:总数、各类异常数
157
+ - 检测 MEMORY.md 是否接近上限
158
+ - **不调 LLM**(audit 是快速体检,不做深度分析)
159
+
160
+ ### 4c. `memory_report(verbose=False)`
161
+ - 调用完整评分流程(规则引擎 + LLM)
162
+ - 返回详细清单,每条附四维评分 + 建议操作 + 原因
163
+ - verbose=False 时只返回「建议删除」和「建议复查」的条目
164
+
165
+ ### 4d. `memory_cleanup(dry_run=True)`
166
+ - **最后做,涉及文件写操作**
167
+ - 执行顺序:
168
+ 1. 读取要清理的记忆列表(来自 memory_report 的结果)
169
+ 2. 备份:把待删文件移入 `memory/.trash/<timestamp>/`
170
+ 3. 删除原文件
171
+ 4. 同步更新 MEMORY.md 索引(删除对应条目)
172
+ 5. 返回操作摘要
173
+ - `dry_run=True` 时只预览,不执行任何写操作
174
+ - 永远不静默删除(即使 dry_run=False 也要先确认)
175
+
176
+ **验收标准**:
177
+ - 跑完整对话流程:`audit` → `report` → 确认 → `cleanup(dry_run=True)` → 确认 → `cleanup(dry_run=False)`
178
+ - dry_run 模式下文件系统零变化
179
+ - .trash 备份正常工作,MEMORY.md 索引同步更新
180
+
181
+ ---
182
+
183
+ ## Step 5(之后单独启动):Benchmark 小数据集
184
+
185
+ ```
186
+ benchmark/
187
+ annotation_guide.md ← 四维评分标注规范
188
+ dataset.json ← 100 条标注样本
189
+ eval.py ← 评估脚本
190
+ ```
191
+
192
+ 需要 Mavis 参与:从真实 Chatbot 数据抽取样本,人工标注。
193
+
194
+ ---
195
+
196
+ ## 文件结构(完成后)
197
+
198
+ ```
199
+ memory-quality-mcp/
200
+ ├── DESIGN.md ← 产品设计方案
201
+ ├── BUILD_PLAN.md ← 本文件:构建计划
202
+ ├── CLAUDE_CODE_INTERNALS.md ← Claude Code 源码分析
203
+ ├── README.md ← 用户安装文档(Step 4 完成后写)
204
+ ├── pyproject.toml
205
+ ├── config.yaml
206
+ ├── src/
207
+ │ ├── __init__.py
208
+ │ ├── server.py ← MCP server 主入口
209
+ │ ├── memory_reader.py ← 文件读取层
210
+ │ ├── quality_engine.py ← 四维评分引擎
211
+ │ └── prompts.py ← LLM prompt 模板
212
+ ├── benchmark/
213
+ │ ├── annotation_guide.md
214
+ │ ├── dataset.json
215
+ │ └── eval.py
216
+ └── tests/
217
+ └── test_quality.py
218
+ ```
@@ -0,0 +1,360 @@
1
+ # Claude Code 记忆系统内部机制
2
+
3
+ > 目的:为 memory-quality-mcp 开发提供足够的内部机制参考,避免反复查阅源码。
4
+ > 来源:对 claude-code-main 源码的直接阅读与分析(2026-04-04)。
5
+ > 覆盖范围:Auto Memory 子系统(我们的直接操作对象),附带其他子系统的关键说明。
6
+
7
+ ---
8
+
9
+ ## 一、整体架构速览
10
+
11
+ Claude Code 的记忆系统由 5 个子系统组成,我们只需关注 **Auto Memory**:
12
+
13
+ ```
14
+ ┌─────────────────────────────────────────────────────┐
15
+ │ Auto Memory ← 我们的操作对象(持久跨会话) │
16
+ │ Session Memory ← 只在当前会话内有效,不需要操作 │
17
+ │ Agent Memory ← 专用 Agent 的独立记忆,不需要操作 │
18
+ │ memdir 核心层 ← Auto Memory 的底层基础设施 │
19
+ │ Team Memory ← 需要 feature flag,暂不考虑 │
20
+ └─────────────────────────────────────────────────────┘
21
+ ```
22
+
23
+ ---
24
+
25
+ ## 二、文件系统结构(最重要)
26
+
27
+ ### 2.1 Auto Memory 的完整目录布局
28
+
29
+ ```
30
+ ~/.claude/projects/<sanitized-git-root>/memory/
31
+ ├── MEMORY.md ← 索引文件(只是目录,不包含记忆内容本身)
32
+ ├── user_role.md ← 一条记忆 = 一个独立 .md 文件
33
+ ├── feedback_testing.md ← 一条记忆
34
+ ├── project_deadline.md ← 一条记忆
35
+ └── team/ ← Team Memory 子目录(需 TEAMMEM flag,忽略)
36
+ ```
37
+
38
+ **关键设计**:单文件单记忆。MEMORY.md 是纯索引,记忆内容全在独立 `.md` 文件里。
39
+
40
+ ### 2.2 路径解析逻辑(`paths.ts`)
41
+
42
+ ```
43
+ getAutoMemPath() 的解析顺序:
44
+ 1. CLAUDE_COWORK_MEMORY_PATH_OVERRIDE 环境变量(全路径覆盖)
45
+ 2. settings.json 的 autoMemoryDirectory 字段(支持 ~/ 展开)
46
+ 3. 默认:{memoryBaseDir}/projects/{sanitizePath(git-root)}/memory/
47
+
48
+ memoryBaseDir 的解析:
49
+ 1. CLAUDE_CODE_REMOTE_MEMORY_DIR 环境变量
50
+ 2. 默认:~/.claude/
51
+ ```
52
+
53
+ **对我们的影响**:扫描记忆前必须调用 `getAutoMemPath()` 的等价逻辑(不能硬编码 `~/.claude/`),因为用户可能通过 settings.json 自定义了记忆目录。
54
+
55
+ ### 2.3 Auto Memory 的启用状态检测
56
+
57
+ 以下任一条件会禁用 Auto Memory:
58
+ - 环境变量 `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`
59
+ - 环境变量 `CLAUDE_CODE_SIMPLE=1`(bare 模式)
60
+ - 远程模式(`CLAUDE_CODE_REMOTE=1`)且未设置 `CLAUDE_CODE_REMOTE_MEMORY_DIR`
61
+ - `settings.json` 里 `autoMemoryEnabled: false`
62
+
63
+ 我们的 MCP 工具在启动时应检测记忆目录是否存在,若不存在则提示用户可能已禁用 Auto Memory。
64
+
65
+ ---
66
+
67
+ ## 三、单条记忆的文件格式
68
+
69
+ ### 3.1 标准 Frontmatter 格式
70
+
71
+ 每条记忆文件的结构:
72
+
73
+ ```markdown
74
+ ---
75
+ name: 用户角色描述
76
+ description: 用户是数据科学家,关注可观测性
77
+ type: user
78
+ ---
79
+
80
+ 正文内容(具体的记忆详情)
81
+
82
+ **Why:** 这条记忆的来源原因(用户自己说的,或某次纠正)
83
+ **How to apply:** 在什么情况下应用这条记忆
84
+ ```
85
+
86
+ **扫描时只读前 30 行**(`FRONTMATTER_MAX_LINES = 30`)即可获取所有结构化字段,不需要读全文。
87
+
88
+ ### 3.2 四种记忆类型(type 字段)
89
+
90
+ 源码定义(`memoryTypes.ts`),完整语义如下:
91
+
92
+ | 类型 | 默认 Scope | 核心用途 | 典型保存时机 |
93
+ |------|-----------|---------|------------|
94
+ | `user` | 始终 private | 用户身份、目标、背景知识、偏好 | 了解用户角色/习惯时 |
95
+ | `feedback` | 默认 private | AI 行为纠正或确认(避免重复犯同样的错) | 被纠正「别这样」或被确认「对,就这样」时 |
96
+ | `project` | 建议 team | 项目进展、决策、背景、截止日期 | 了解谁在做什么、为什么、何时完成时 |
97
+ | `reference` | 通常 team | 外部系统指针(URL、Linear、Slack 等) | 了解外部资源位置及用途时 |
98
+
99
+ **重要**:`type` 字段缺失时 `parseMemoryType()` 返回 `undefined`,系统降级处理(不报错)。历史遗留文件可能没有 `type` 字段。
100
+
101
+ ### 3.3 「不该存的记忆」—— 官方明确列出(可直接用于我们的 prompt)
102
+
103
+ 以下类型的内容**不该出现在记忆里**(来自源码 `WHAT_NOT_TO_SAVE_SECTION`):
104
+
105
+ - 代码模式、架构、文件路径、项目结构(可以从代码推断)
106
+ - git 历史、近期变更(`git log`/`git blame` 才是权威)
107
+ - 调试方案、bug 修复记录(fix 在代码里,commit message 有上下文)
108
+ - CLAUDE.md 里已有的内容(重复存储)
109
+ - 临时任务状态、当前对话的进行中工作
110
+
111
+ **设计洞察**:这些规则可以直接复用到我们的「低质量记忆识别」prompt,等于 Anthropic 官方背书的质量标准。
112
+
113
+ ---
114
+
115
+ ## 四、MEMORY.md 索引文件的限制
116
+
117
+ ### 4.1 硬上限(`memdir.ts`)
118
+
119
+ ```
120
+ MAX_ENTRYPOINT_LINES = 200 行
121
+ MAX_ENTRYPOINT_BYTES = 25,000 字节(约 25KB)
122
+ 截断规则:先按行截断(自然边界),再按字节截断(防止长行绕过行限制)
123
+ ```
124
+
125
+ 超出时,系统会追加警告并截断,用户看不到被截断的记忆索引。
126
+
127
+ **对我们的影响**:
128
+ - 这是一个可以检测的健康指标——MEMORY.md 接近或超过上限说明记忆库需要清理
129
+ - `memory_audit()` 应该检测 MEMORY.md 的当前行数和大小,并在接近上限时警告
130
+
131
+ ### 4.2 MEMORY.md 的内容格式
132
+
133
+ MEMORY.md 是纯索引,每条记忆一行,格式为:
134
+
135
+ ```
136
+ - [Title](filename.md) — 一行摘要(建议 < 150 字符)
137
+ ```
138
+
139
+ 不包含 frontmatter,不包含记忆详情。修改记忆时,需要同步更新这里的索引条目。
140
+
141
+ ---
142
+
143
+ ## 五、扫描机制(`memoryScan.ts`)
144
+
145
+ ### 5.1 `scanMemoryFiles()` 的完整行为
146
+
147
+ ```python
148
+ # 等价的 Python 伪代码,描述扫描逻辑:
149
+
150
+ def scan_memory_files(memory_dir):
151
+ entries = readdir(memory_dir, recursive=True)
152
+ md_files = [f for f in entries if f.endswith('.md') and basename(f) != 'MEMORY.md']
153
+
154
+ headers = []
155
+ for f in md_files:
156
+ content, mtime = read_file_first_30_lines(f)
157
+ frontmatter = parse_frontmatter(content)
158
+ headers.append({
159
+ 'filename': f, # 相对路径
160
+ 'filePath': absolute(f), # 绝对路径
161
+ 'mtimeMs': mtime, # 修改时间(毫秒时间戳)
162
+ 'description': frontmatter.get('description'),
163
+ 'type': frontmatter.get('type'), # 可能为 None
164
+ })
165
+
166
+ headers.sort(key=lambda x: x['mtimeMs'], reverse=True) # 最新优先
167
+ return headers[:200] # 硬上限 200 个文件
168
+ ```
169
+
170
+ **关键点**:
171
+ - 递归扫描(包含子目录)
172
+ - 只读前 30 行(含 frontmatter),省 I/O
173
+ - 按 mtime 降序排列(最近修改的优先)
174
+ - 最多返回 200 个文件,超出部分静默截断
175
+
176
+ ### 5.2 `formatMemoryManifest()` 的输出格式
177
+
178
+ 扫描结果格式化后的样子(用于 LLM 输入):
179
+
180
+ ```
181
+ - [user] user_role.md (2026-04-03T10:00:00.000Z): 用户是数据科学家,关注可观测性
182
+ - [feedback] feedback_testing.md (2026-04-02T08:30:00.000Z): 用户不喜欢 mock 数据库
183
+ - project_deadline.md (2026-03-15T12:00:00.000Z) ← type 为 None 时省略标签
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 六、新鲜度系统(`memoryAge.ts`)
189
+
190
+ ### 6.1 内置的时效性警告
191
+
192
+ Claude Code 自己有一套时效性警告,会在每次使用记忆时注入到 system prompt:
193
+
194
+ ```python
195
+ def get_freshness_warning(mtime_ms):
196
+ days = (now() - mtime_ms) / 86_400_000
197
+ if days <= 1:
198
+ return "" # 当天或昨天:不警告
199
+ return f"This memory is {days} days old. " \
200
+ f"Memories are point-in-time observations, not live state — " \
201
+ f"claims about code behavior or file:line citations may be outdated. " \
202
+ f"Verify against current code before asserting as fact."
203
+ ```
204
+
205
+ **设计洞察**:Anthropic 自己承认时效性是问题,但他们的解法是「每次使用时提醒」而非「主动清理」。我们做的是他们没做的那一半。
206
+
207
+ ### 6.2 时效性阈值建议
208
+
209
+ 基于 Anthropic 的设计,我们的时效性评分可以参考:
210
+
211
+ | 年龄 | Claude Code 的处理 | 我们的评分建议 |
212
+ |------|-------------------|--------------|
213
+ | ≤ 1 天 | 无警告 | 时效性 5/5 |
214
+ | 2-7 天 | 轻量警告 | 时效性 4/5 |
215
+ | 7-30 天 | 警告 | 时效性 3/5(视内容类型) |
216
+ | 30-90 天 | 警告 | 时效性 2/5(project 类型降权更快)|
217
+ | > 90 天 | 警告 | 时效性 1/5,强烈建议复查 |
218
+
219
+ 特别注意:`project` 类型记忆衰减最快(项目状态变化快),`user` 类型相对稳定。
220
+
221
+ ---
222
+
223
+ ## 七、记忆提取机制(`extractMemories.ts`)
224
+
225
+ ### 7.1 触发时机
226
+
227
+ 每轮对话结束(模型产生最终响应、无 tool call)后,由 `handleStopHooks()` 触发,fire-and-forget(不阻塞用户看到响应)。
228
+
229
+ ### 7.2 提取流程关键细节
230
+
231
+ ```
232
+ 每轮对话结束
233
+ → 检查:是子 Agent?→ 跳过(防递归)
234
+ → 检查:功能关闭?→ 跳过
235
+ → 检查:已有提取在跑?→ stash,trailing run
236
+ → 检查:主 Agent 本轮已手动写过记忆?→ 跳过
237
+ → 启动 Forked Agent(沙箱权限,最多 5 轮)
238
+ ├── 只能读任意文件
239
+ └── 只能写 auto memory 目录内的文件
240
+ → 最多等 60 秒(drainPendingExtraction)
241
+ ```
242
+
243
+ ### 7.3 提取的「不保存」规则(对我们识别低质量记忆有直接价值)
244
+
245
+ 源码 `WHAT_NOT_TO_SAVE_SECTION` 明确列出,即使用户明确要求保存,也不该存:
246
+ - PR 列表、活动摘要(提示用户说「哪个是非显而易见的发现」,那才值得记)
247
+ - 临时状态(当前会话中的进行中工作)
248
+ - 能从代码/git 推断的内容
249
+
250
+ ---
251
+
252
+ ## 八、对 memory-quality-mcp 的直接影响(设计决策依据)
253
+
254
+ ### 8.1 「一条记忆」的定义(问题一的答案)
255
+
256
+ **不需要 NLP 切分**。每个 `.md` 文件 = 一条记忆,`name` 字段是摘要,`type` 字段可直接用。我们的 `memory_report()` 直接遍历 `.md` 文件即可。
257
+
258
+ ### 8.2 扫描范围(问题二的答案)
259
+
260
+ **只扫描 Auto Memory 目录**(`~/.claude/projects/<hash>/memory/`),排除 MEMORY.md。
261
+
262
+ **不扫描**:
263
+ - `CLAUDE.md`——用户手写指令,不是 Claude 自动提取的记忆,语义不同
264
+ - `session_memory/session_notes.md`——会话内临时摘要,会话结束即过时
265
+ - `agent-memory/`——专用 Agent 的独立记忆,与主对话记忆分开
266
+
267
+ ### 8.3 评分调用方式(问题三的答案)
268
+
269
+ 参考 Claude Code 自己的「先扫 frontmatter,再做轻量 LLM 调用」模式:
270
+
271
+ ```
272
+ 第一步:扫描所有 .md 文件,只读 frontmatter(纯文件 I/O,零 API 成本)
273
+ → 直接识别低质量信号:
274
+ · type=project + mtime > 90天 → 大概率过时,标记待审
275
+ · 无 Why/How to apply 结构 → 可信度信号弱
276
+ · 符合「不该存」规则(代码模式、git 历史等)→ 直接标记
277
+
278
+ 第二步:每批 5-8 条发给 LLM 做四维质量评分(Haiku)
279
+ → 一次 API 调用处理一批(批内有上下文,冲突检测在这里做)
280
+ → 50 条记忆 ≈ 7-10 次 API 调用
281
+ ```
282
+
283
+ ### 8.4 Cleanup 的安全机制(问题四的答案)
284
+
285
+ 删除一条记忆 = 删除对应 `.md` 文件 + 更新 MEMORY.md 中的索引条目(两步都要做)。
286
+
287
+ 安全策略:
288
+ ```
289
+ 执行前:把要删除的文件移入 memory/.trash/<timestamp>/
290
+ 执行中:删除原文件 → 更新 MEMORY.md 索引
291
+ 执行后:告知用户「已备份到 .trash,可手动恢复」
292
+ ```
293
+
294
+ 不能只删文件不更新 MEMORY.md:索引文件有 200 行上限,孤立条目会占用索引空间。
295
+
296
+ ### 8.5 可以直接复用的 Anthropic 官方规则
297
+
298
+ 以下内容可以直接搬进我们的 LLM prompt,不需要自己设计:
299
+
300
+ 1. **四种类型定义**(`memoryTypes.ts` 的 `TYPES_SECTION_INDIVIDUAL`)
301
+ 2. **「不该存」规则**(`WHAT_NOT_TO_SAVE_SECTION`)——用于识别低质量记忆
302
+ 3. **时效性警告文本模板**(`memoryFreshnessText()`)——用于告知用户哪些记忆可能过时
303
+ 4. **「Before recommending from memory」section**(`TRUSTING_RECALL_SECTION`)——可用于我们的「记偏了」检测 prompt
304
+
305
+ ---
306
+
307
+ ## 九、关键常量速查
308
+
309
+ | 常量 | 值 | 来源文件 | 用途 |
310
+ |------|-----|---------|------|
311
+ | `MAX_MEMORY_FILES` | 200 | `memoryScan.ts` | 扫描上限,超出静默截断 |
312
+ | `FRONTMATTER_MAX_LINES` | 30 | `memoryScan.ts` | 只读前 30 行获取 frontmatter |
313
+ | `MAX_ENTRYPOINT_LINES` | 200 | `memdir.ts` | MEMORY.md 行数上限 |
314
+ | `MAX_ENTRYPOINT_BYTES` | 25,000 | `memdir.ts` | MEMORY.md 字节上限(≈25KB)|
315
+ | `AUTO_MEM_DIRNAME` | `'memory'` | `paths.ts` | 记忆目录名 |
316
+ | `AUTO_MEM_ENTRYPOINT_NAME` | `'MEMORY.md'` | `paths.ts` | 索引文件名 |
317
+ | Forked Agent 最大轮数 | 5 | `extractMemories.ts` | 提取 Agent 的执行上限 |
318
+ | `drainPendingExtraction` 超时 | 60 秒 | `extractMemories.ts` | 等待提取完成的最大时间 |
319
+
320
+ ---
321
+
322
+ ## 十、需要注意的边界情况
323
+
324
+ ### 10.1 记忆目录不存在
325
+
326
+ 用户可能刚安装 Claude Code 还没有任何记忆,或 Auto Memory 被禁用。我们的工具需要优雅处理目录不存在的情况(返回空结果,给出提示,而不是报错退出)。
327
+
328
+ ### 10.2 没有 type 字段的历史文件
329
+
330
+ `parseMemoryType()` 对未知或缺失的 type 返回 `undefined`,我们的代码也需要处理这种情况(不能假设 type 一定存在)。
331
+
332
+ ### 10.3 MEMORY.md 已截断
333
+
334
+ 如果 MEMORY.md 已经达到 200 行上限,索引是不完整的。但实际的记忆文件仍然完整存在——我们直接扫描 `.md` 文件,不依赖 MEMORY.md 做枚举,所以这个问题对我们不影响扫描完整性,但会影响我们更新索引时的准确性(需要先读全量再写回)。
335
+
336
+ ### 10.4 并发写入竞争
337
+
338
+ Claude Code 的提取是异步后台运行的。如果用户正在使用 Claude Code 同时我们的工具在运行清理,可能出现同时写 MEMORY.md 的竞争。
339
+
340
+ 处理方式:cleanup 操作建议加文件锁,或在文档中明确提示「清理时请关闭 Claude Code 会话」。
341
+
342
+ ### 10.5 git worktree 的记忆共享
343
+
344
+ `getAutoMemBase()` 使用 `findCanonicalGitRoot()`,同一 git repo 的所有 worktree 共享同一个记忆目录。这是预期行为,我们扫描时无需区分 worktree。
345
+
346
+ ---
347
+
348
+ ## 附录:相关源文件索引
349
+
350
+ | 文件 | 关键内容 |
351
+ |------|---------|
352
+ | `src/memdir/paths.ts` | `getAutoMemPath()`、`isAutoMemoryEnabled()`、路径解析完整逻辑 |
353
+ | `src/memdir/memoryTypes.ts` | 四种类型定义、「不该存」规则、frontmatter 格式示例 |
354
+ | `src/memdir/memoryScan.ts` | `scanMemoryFiles()`、`formatMemoryManifest()`、扫描逻辑 |
355
+ | `src/memdir/memoryAge.ts` | `memoryAgeDays()`、`memoryFreshnessText()`、时效性警告 |
356
+ | `src/memdir/memdir.ts` | `truncateEntrypointContent()`、MEMORY.md 截断规则、`buildMemoryLines()` |
357
+ | `src/memdir/findRelevantMemories.ts` | `scanMemoryFiles()` + Sonnet selector 完整流程 |
358
+ | `src/services/extractMemories/extractMemories.ts` | Auto Memory 提取状态机(Forked Agent 编排)|
359
+ | `claude_memory_system_analysis.md` | 系统整体架构分析(人工梳理文档)|
360
+ | `claude_auto_memory_extraction_deep_dive.md` | 提取流程深度拆解(人工梳理文档)|