Claude-Mem 如何使用 Hooks:一种生命周期驱动的架构
核心原则
从外部观察主要的Claude代码会话,在后台处理观察,在适当的时候注入上下文。
大局
Claude-Mem 本质上是一个 钩子驱动的系统。每一项功能都是对生命周期事件的响应而发生的:
┌─────────────────────────────────────────────────────────┐
│ CLAUDE CODE SESSION │
│ (Main session - user interacting with Claude) │
│ │
│ SessionStart → UserPromptSubmit → Tool Use → Stop │
│ ↓ ↓ ↓ ↓ ↓ ↓ │
│ [3 Hooks] [Hook] [Hook] [Hook] │
└─────────────────────────────────────────────────────────┘
↓ ↓ ↓ ↓ ↓ ↓
┌─────────────────────────────────────────────────────────┐
│ CLAUDE-MEM SYSTEM │
│ │
│ Smart Worker Context New Obs │
│ Install Start Inject Session Capture │
└─────────────────────────────────────────────────────────┘从 Claude Code 2.1.0(ultrathink 更新)开始,SessionStart 钩子不再显示用户可见的消息。上下文通过 hookSpecificOutput.additionalContext 静默注入。
关键见解: Claude-Mem 不会打断或修改 Claude Code 的行为。它从外部观察,并通过生命周期钩子提供价值。
为什么选择 Hooks?
非侵入性要求
Claude-Mem 有几个建筑上的限制:
- 无法修改 Claude Code:它是闭源的二进制文件
- 必须快:不能拖慢主会话
- 必须可靠:如果失败,不能破坏Claude代码
- 必须便携:无需配置即可在任何项目上运行
解决方案: 通过 settings.json 配置的外部命令钩子
钩子系统优势
Claude Code 的钩子系统正好提供了我们所需要的:
- Lifecycle Events
SessionStart, UserPromptSubmit, PostToolUse, Stop
- Non-Blocking
Hooks run in parallel, don't wait for completion
- Context Injection
SessionStart and UserPromptSubmit can add context
- Tool Observation
PostToolUse sees all tool inputs and outputs
钩子脚本
Claude-Mem 在 5 个生命周期事件中使用生命周期钩子脚本。SessionStart 按顺序运行 3 个钩子:smart-install、worker-service start 和 context-hook。
预挂钩:智能安装(会话开始前)
目的: 智能管理依赖项并启动 Worker 服务
注意: 这不是生命周期钩子——它是在上下文钩子运行之前通过命令链执行的预钩子脚本。
时间: Claude Code 启动时(启动、清空或压缩)
它的功能:
- 检查依赖项是否需要安装(版本标记)
- 仅在必要时运行
npm install:- 首次安装
- package.json 中的版本已更改
- 提供特定于 Windows 的错误消息
- 启动 Bun Worker 服务
配置:
{
"hooks": {
"SessionStart": [{
"matcher": "startup|clear|compact",
"hooks": [{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/../scripts/smart-install.js\" && node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js",
"timeout": 300
}]
}]
}
}主要特点:
- ✅ 版本缓存 (
.install-version文件) - ✅ 安装完成后速度快(约10毫秒 vs 2-5秒)
- ✅ 跨平台兼容
- ✅ 对构建工具有帮助的 Windows 错误信息
v5.0.3 增强功能: 智能缓存消除了冗余安装
来源: scripts/smart-install.js
钩子 1:会话开始 - 上下文注入
目的: 注入来自之前会话的相关上下文
时间: Claude Code 启动(在 smart-install pre-hook 之后运行)
它的功能:
- 从当前工作目录中提取项目名称
- 查询 SQLite 最近的会话摘要(最近 10 条)
- 查询 SQLite 最近的观测(可配置,默认50)
- 格式为渐进式披露索引
- 输出到标准输出(自动注入到上下文中)
关键决策:
- ✅ 开机启动、简洁、紧凑
- ✅ 300 秒超时(如有需要,可进行 npm 安装)
- ✅ 渐进式披露格式(索引,而非完整细节)
- ✅ 可通过
CLAUDE_MEM_CONTEXT_OBSERVATIONS配置的观察次数
输出格式:
# [claude-mem] recent context
**Legend:** 🎯 session-request | 🔴 gotcha | 🟡 problem-solution ...
### Oct 26, 2025
**General**
| ID | Time | T | Title | Tokens |
|----|------|---|-------|--------|
| #2586 | 12:58 AM | 🔵 | Context hook file empty | ~51 |
*Use MCP search tools to access full details*来源: src/hooks/context-hook.ts → plugin/scripts/context-hook.js
钩子 2:用户提示提交(新会话钩子)
目的: 当用户提交提示时初始化会话跟踪
时间: 在Claude处理用户的消息之前
它的功能:
- 从标准输入读取用户提示和会话ID
- 在 SQLite 中创建新的会话记录
- 保存原始用户提示以用于全文搜索 (v4.2.0)
- 如果未运行,则启动 Bun Worker 服务
- 立即返回(非阻塞)
配置:
{
"hooks": {
"UserPromptSubmit": [{
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/new-hook.js"
}]
}]
}
}关键决策:
- ✅ 无匹配器(适用于所有提示)
- ✅ 立即创建会话记录
- ✅ 存储用于搜索的原始提示(隐私说明:仅本地 SQLite)
- ✅ 自动启动 Worker 服务
- ✅ 抑制输出 (
suppressOutput: true)
数据库操作:
INSERT INTO sdk_sessions (claude_session_id, project, user_prompt, ...)
VALUES (?, ?, ?, ...)
INSERT INTO user_prompts (session_id, prompt, prompt_number, ...)
VALUES (?, ?, ?, ...)来源: src/hooks/new-hook.ts → plugin/scripts/new-hook.js
钩子3:PostToolUse(保存观察钩子)
目的: 捕捉工具执行的观察结果以供后续处理
何时: 在任何工具成功完成后立即
它的功能:
- 从标准输入接收工具名称、输入和输出
- 查找当前项目的活动会话
- 将观测记录加入 observation_queue 表
- 立即返回(处理在Worker 进程中进行)
配置:
{
"hooks": {
"PostToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js"
}]
}]
}
}关键决策:
- ✅ 匹配器:
*(捕获所有工具) - ✅ 非阻塞(仅入队,不处理)
- ✅ 工作进程异步处理观察结果
- ✅ 并行执行安全(每个钩子都有自己的标准输入)
数据库操作:
INSERT INTO observation_queue (session_id, tool_name, tool_input, tool_output, ...)
VALUES (?, ?, ?, ?, ...)排队的内容:
{
"session_id": "abc123",
"tool_name": "Edit",
"tool_input": {
"file_path": "/path/to/file.ts",
"old_string": "...",
"new_string": "..."
},
"tool_output": {
"success": true,
"linesChanged": 5
},
"created_at_epoch": 1698765432
}来源: src/hooks/save-hook.ts → plugin/scripts/save-hook.js
钩 4:停止钩(摘要生成)
目的: 在会话期间生成由 AI 驱动的会话摘要
时间: 当 Claude 停止时(由停止生命周期事件触发)
它的功能:
- 从数据库收集会话观察
- 发送到 Claude 代理 SDK 进行摘要
- 处理响应并提取结构化摘要
- 存储在 session_summaries 表中
配置:
{
"hooks": {
"Stop": [{
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/summary-hook.js"
}]
}]
}
}关键决策:
- ✅ 由停止生命周期事件触发
- ✅ 每次会话的多重摘要 (v4.2.0 )
- ✅ 总结是检查点,而不是终点
- ✅ 使用 Claude Agent SDK 进行 AI 压缩
摘要结构:
<summary>
<request>User's original request</request>
<investigated>What was examined</investigated>
<learned>Key discoveries</learned>
<completed>Work finished</completed>
<next_steps>Remaining tasks</next_steps>
<files_read>
<file>path/to/file1.ts</file>
<file>path/to/file2.ts</file>
</files_read>
<files_modified>
<file>path/to/file3.ts</file>
</files_modified>
<notes>Additional context</notes>
</summary>来源: src/hooks/summary-hook.ts → plugin/scripts/summary-hook.js
钩子 5:会话结束(清理钩子)
目的: 在会话结束时将其标记为已完成
时间: Claude Code 会话结束(不在 /clear 上)
它的功能:
- 将会话在数据库中标记为已完成
- 允许Worker完成处理
- 执行优雅的清理
配置:
{
"hooks": {
"SessionEnd": [{
"hooks": [{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js"
}]
}]
}
}关键决策:
- ✅ 优雅完成 (v4.1.0)
- ✅ 不再向Worker 进程发送 DELETE
- ✅ 在
/clear命令上跳过清理 - ✅ 保留正在进行的会话
为什么要优雅地清理?
旧方法 (v3):
// ❌ Aggressive cleanup
SessionEnd → DELETE /worker/session → Worker stops immediately问题:
- 摘要生成被中断
- 丢失的待处理观察
- 竞争条件
新方法 (v4.1.0):
// ✅ Graceful completion
SessionEnd → UPDATE sessions SET completed_at = NOW()
Worker sees completion → Finishes processing → Exits naturally好处:
- Worker 完成重要操作
- 汇总完成成功
- 干净的状态转换
来源: src/hooks/cleanup-hook.ts → plugin/scripts/cleanup-hook.js
钩子执行流程
会话生命周期
钩爪时机
| 事件 | 时间 | 阻塞 | 超时 | 输出处理 |
|---|---|---|---|---|
| SessionStart (智能安装) | 会话开始前 | 否 | 300秒 | 标准错误(仅日志) |
| 会话开始 (worker-start) | 会话前 | 否 | 60秒 | 标准错误 (仅日志) |
| SessionStart (context) | 会话开始前 | 否 | 60秒 | JSON → additionalContext(静默) |
| 用户提交提示 | 处理前 | 否 | 60秒 | 标准输出 → 上下文 |
| 使用工具后 | 使用工具后 | 否 | 120秒 | 仅转录 |
| 摘要 | 工作触发 | 否 | 120秒 | 数据库 |
| SessionEnd | 退出时 | 否 | 120秒 | 仅记录 |
从 Claude Code 2.1.0(ultrathink 更新)开始,SessionStart 钩子不再显示用户可见的消息。上下文通过 hookSpecificOutput.additionalContext 静默注入。
Worker 服务架构
为什么使用后台Worker?
问题: 钩子必须快速(< 1 秒)
现实: AI 压缩每个观测需 5-30 秒
解决方案: 钩子排队观察,工作进程异步处理
┌─────────────────────────────────────────────────────────┐
│ HOOK (Fast) │
│ 1. Read stdin (< 1ms) │
│ 2. Insert into queue (< 10ms) │
│ 3. Return success (< 20ms total) │
└─────────────────────────────────────────────────────────┘
↓ (queue)
┌─────────────────────────────────────────────────────────┐
│ WORKER (Slow) │
│ 1. Poll queue every 1s │
│ 2. Process observation via Claude SDK (5-30s) │
│ 3. Parse and store results │
│ 4. Mark observation processed │
└─────────────────────────────────────────────────────────┘Bun 过程管理
技术: Bun(JavaScript 运行时和进程管理器)
为什么选择Bun:
- 失败时自动重启
- 快速启动和低内存占用
- 内置 TypeScript 支持
- 跨平台(适用于 macOS、Linux、Windows)
- 无需单独的进程管理器
Worker 生命周期:
# Started by hooks automatically (if not running)
npm run worker:start
# Status check
npm run worker:status
# View logs
npm run worker:logs
# Restart
npm run worker:restart
# Stop
npm run worker:stopWorker HTTP API
技术: 端口 37777 的 Express.js REST API
端点:
| 端点 | 方法 | 目的 |
|---|---|---|
/health | GET | 健康检查 |
/sessions | POST | 创建会话 |
/sessions/:id | GET | 获取会话状态 |
/sessions/:id | 补丁 | 更新会话 |
/observations | POST | 排入观察队列 |
/observations/:id | GET | 获取观测 |
为什么使用 HTTP API?
- 语言无关(钩子可以是任何语言)
- 轻松调试(curl 命令)
- 标准错误处理
- 正确的异步处理
设计模式
模式 1:一次性钩子
原则: 钩子应立即返回,不应等待完成
// ❌ Bad: Hook waits for processing
const observation = parseInput(stdin);
await processObservation(observation); // BLOCKS!
return success();
}
// ✅ Good: Hook enqueues and returns
const observation = parseInput(stdin);
await enqueueObservation(observation); // Fast
return success(); // Immediate
}模式 2:基于队列的处理
原则: 将捕获与处理分离
Hook (capture) → Queue (buffer) → Worker (process)好处:
- 并行钩子执行安全
- Worker 进程失败不会影响钩子
- 重试逻辑集中化
- 背压处理
模式 3:优雅降级
原则: 内存系统故障不应破坏Claude代码
try {
await captureObservation();
} catch (error) {
// Log error, but don't throw
console.error('Memory capture failed:', error);
return { continue: true, suppressOutput: true };
}失效模式:
- 数据库已锁定 → 跳过观测,记录错误
- Worker 进程崩溃 → 通过 Bun 自动重启
- 网络问题 → 使用指数退避重试
- 磁盘已满 → 提示用户,禁用内存
模式 4:渐进增强
原则: 核心功能在没有记忆的情况下也能工作,记忆能增强它
Without memory: Claude Code works normally
With memory: Claude Code + context from past sessions
Memory broken: Falls back to working normally钩子调试
调试模式
启用详细的钩子执行日志:
claude --debug输出:
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js with timeout 60000ms
[DEBUG] Hook command completed with status 0: {"continue":true,"suppressOutput":true}常见问题
**Symptoms:** Hook command never runs
**Debugging:**
1. Check `/hooks` menu - is hook registered?
2. Verify matcher pattern (case-sensitive!)
3. Test command manually: `echo '{}' | node save-hook.js`
4. Check file permissions (executable?)
**Symptoms:** Hook execution exceeds timeout
**Debugging:**
1. Check timeout setting (default 60s)
2. Identify slow operation (database? network?)
3. Move slow operation to worker
4. Increase timeout if necessary
**Symptoms:** SessionStart hook runs but context missing
**Debugging:**
1. Check stdout (must be valid JSON or plain text)
2. Verify no stderr output (pollutes JSON)
3. Check exit code (must be 0)
4. Look for npm install output (v4.3.1 fix)
**Symptoms:** PostToolUse hook runs but observations missing
**Debugging:**
1. Check database: `sqlite3 ~/.claude-mem/claude-mem.db "SELECT * FROM observation_queue"`
2. Verify session exists: `SELECT * FROM sdk_sessions`
3. Check worker status: `npm run worker:status`
4. View worker logs: `npm run worker:logs`
手动测试钩子
# Test context hook
echo '{
"session_id": "test123",
"cwd": "/Users/alex/projects/my-app",
"hook_event_name": "SessionStart",
"source": "startup"
}' | node plugin/scripts/context-hook.js
# Test save hook
echo '{
"session_id": "test123",
"tool_name": "Edit",
"tool_input": {"file_path": "test.ts"},
"tool_output": {"success": true}
}' | node plugin/scripts/save-hook.js
# Test with actual Claude Code
claude --debug
/hooks # View registered hooks
# Submit prompt and watch debug output性能考虑
钩子执行时间
目标: 每个钩子 < 100 毫秒
实际测量:
| 钩子 | 平均 | p95 | p99 |
|---|---|---|---|
| 会话开始(智能安装,缓存) | 10毫秒 | 20毫秒 | 40毫秒 |
| 会话开始(智能安装,首次运行) | 2500毫秒 | 5000毫秒 | 8000毫秒 |
| 会话开始 (上下文) | 45毫秒 | 120毫秒 | 250毫秒 |
| 会话开始(用户消息) | 5毫秒 | 10毫秒 | 15毫秒 |
| 用户提示提交 | 12毫秒 | 25毫秒 | 50毫秒 |
| 工具使用后 | 8毫秒 | 15毫秒 | 30毫秒 |
| 会话结束 | 5毫秒 | 10毫秒 | 20毫秒 |
为什么智能安装有时会很慢:
- 首次:完整 npm 安装(2-5 秒)
- 缓存:仅版本检查(约10毫秒)
- 版本更改:完整的 npm 安装 重启工作进程
优化 (v5.0.3):
.install-version标记的版本缓存- 仅在版本更改或缺少依赖时安装
- 带有构建工具帮助的 Windows 特定错误消息
数据库性能
模式优化:
project、created_at_epoch、claude_session_id上的索引- 用于全文搜索的 FTS5 虚拟表
- 用于并发读写的 WAL 模式
查询模式:
-- Fast: Uses index on (project, created_at_epoch)
SELECT * FROM session_summaries
WHERE project = ?
ORDER BY created_at_epoch DESC
LIMIT 10
-- Fast: Uses index on claude_session_id
SELECT * FROM sdk_sessions
WHERE claude_session_id = ?
LIMIT 1
-- Fast: FTS5 full-text search
SELECT * FROM observations_fts
WHERE observations_fts MATCH ?
ORDER BY rank
LIMIT 20Worker 吞吐量
瓶颈: Claude API 延迟(每次观测 5-30 秒)
缓解:
- 按顺序处理观察结果(更简单,更可预测)
- 跳过低价值的观察(TodoWrite,ListMcpResourcesTool)
- 批次汇总(每 N 个观测生成一次,而不是每个观测都生成)
未来优化:
- 并行处理(多Worker)
- 智能批处理(合并相关观测)
- 懒惰总结(仅在需要时总结)
安全注意事项
钩命令安全
风险: 钩子以用户权限执行任意命令
缓解措施:
- 启动时冻结: 启动时捕获的钩子配置,更改需要审查
- 需要用户审核:
/hooks菜单显示了更改,需要批准 - 插件隔离:
${CLAUDE_PLUGIN_ROOT}防止路径遍历 - 输入验证: 钩子在处理前验证标准输入模式
数据隐私
存储的内容:
- 用户提示(原始文本)- v4.2.0
- 工具输入和输出
- 文件路径 读取/修改
- 会议摘要
隐私保证:
- 所有数据存储在本地的
~/.claude-mem/claude-mem.db - 不进行云端上传(仅用于 AI 压缩的 API 调用)
- SQLite 文件权限:仅用户可读/写
- 没有分析或遥测
API 密钥保护
配置:
- Anthropic API 密钥在
~/.anthropic/api_key或ANTHROPIC_API_KEY环境变量中 - Worker 继承自 Claude Code 的环境
- 从未记录或存储在数据库中
关键要点
- Hooks 是接口:它们定义了系统之间的清晰边界
- 非阻塞至关重要:钩子必须快速返回,工作由 Worker 进程完成
- 优雅降级:内存系统可以在不破坏Claude代码的情况下失败
- 基于队列的解耦:捕获和处理独立进行
- 渐进披露:上下文注入使用先索引方法
- 生命周期对齐:每个钩子都有明确、单一的目的
进一步阅读
- Claude Code Hooks Reference - 官方文档
- Progressive Disclosure - 上下文启发哲学
- Architecture Evolution - 从 v3 到 v4 的旅程
- Worker Service Design - 后台处理详情
钩子驱动的架构使Claude-Mem既强大又隐形。用户从未注意到记忆系统的工作——它只是随着时间的推移让Claude变得更聪明。