PostToolUse
定义
PostToolUse 是 claude-mem 的 Hook Lifecycle 中第 3 个阶段。文档明确写出:Stage 3 is PostToolUse。它对应的 hook 脚本是 save-hook.js,触发条件是 Claude uses any tool,作用是 Queue observation for AI compression。
在 5 阶段生命周期表中,PostToolUse 的位置与定义非常明确:
- Stage:3. PostToolUse
- Hook:
save-hook.js - Trigger:Claude uses any tool
- Purpose:Queue observation for AI compression
在本文档中的语境
该概念出现在 Hook Lifecycle - Claude-Mem 摘要 所描述的 5 阶段 Hook 架构中,与 SessionStart、UserPromptSubmit、summary-hook.js、cleanup-hook.js 等阶段或脚本共同组成一次 Claude Code 会话中的采集与处理链路。
其所在系统采用“两进程架构”:扩展或宿主侧负责快速发出 HTTP 请求,worker 负责异步处理 observation,因此 PostToolUse 不是在前台同步完成 AI 总结,而是把工具调用结果送入后台队列。文档特别强调,这样做的目标是不阻塞 IDE 或 Claude 的工具执行。
生命周期位置
在完整的 5 个阶段中,PostToolUse 排在第 3 位:
-
- SessionStart:
context-hook.js,注入历史上下文
- SessionStart:
-
- UserPromptSubmit:
new-hook.js,创建或获取会话并初始化 worker
- UserPromptSubmit:
-
- PostToolUse:
save-hook.js,在工具调用后排队 observation
- PostToolUse:
-
- Stop:
summary-hook.js,生成会话摘要
- Stop:
-
- SessionEnd:
cleanup-hook.js,标记会话完成
- SessionEnd:
这说明 PostToolUse 发生在用户提交提示之后、总结与清理之前,负责持续记录会话中每一次有价值的工具使用痕迹。
触发条件与配置
文档给出的配置中,PostToolUse 在 hooks.json 里被单独声明,且 matcher 为 *,表示匹配任意工具使用事件:
{
"PostToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js",
"timeout": 120
}]
}]
}
这里有几个不能省略的细节:
- 对应脚本是
save-hook.js。 - 实际执行命令是
node ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js。 matcher为*,不是只针对某个单独工具。- 超时时间配置为
120秒。
不过,虽然配置层面是“任意工具使用都触发”,实现层面并不是所有工具最终都会进入 observation 队列,后续还有跳过规则。
关键机制
1. 触发时机
PostToolUse 的时机是:在 Claude 使用任意工具之后。文档举例说明包括 Read、Bash、Grep、Write 等。也就是说,它关注的是工具执行后的结果,而不是用户刚提交 prompt 的时刻。
2. 输入内容
该阶段从标准输入接收一个结构化对象,至少包含以下字段:
{
"session_id": "claude-session-123",
"cwd": "/path/to/project",
"tool_name": "Read",
"tool_input": { "file_path": "/src/index.ts" },
"tool_response": "file contents..."
}
这表明 PostToolUse 处理的不只是“用了什么工具”,还包括:
- 当前会话
session_id - 当前工作目录
cwd - 工具名
tool_name - 工具输入
tool_input - 工具输出
tool_response
3. 立即返回,不等待 AI 压缩完成
这是该阶段最关键的运行模式。文档明确说明:hook 在发出 HTTP POST 后会立即返回,AI compression 在 worker 中异步执行,不阻塞 Claude 的工具执行。
换句话说,PostToolUse 的直接职责不是当场生成最终 observation,而是排队。这也正是文档在生命周期表中把其 Purpose 写成 Queue observation for AI compression 的原因。
处理步骤
根据文档给出的 Stage 3 顺序图与伪代码,PostToolUse 的处理逻辑可概括为以下步骤:
1. 检查跳过名单
系统会先过滤低价值或噪声类工具。文档给出的 SKIP_TOOLS 包含:
ListMcpResourcesTool:MCP 基础设施噪声SlashCommand:命令调用Skill:Skill 调用TodoWrite:任务管理元工具AskUserQuestion:用户交互
如果 tool_name 命中这些项目,则该次触发会直接返回,不进入后续 observation 队列。
这也是一个重要边界:PostToolUse 的触发条件是 Claude uses any tool,但并不意味着每次触发都会保存有效 observation。
2. 确保 worker 正在运行
在真正发送 observation 前,会先调用类似 ensureWorkerRunning() 的逻辑,确保后台 worker 可用。
3. 通过 HTTP 发送 observation 请求
随后脚本向 worker 发送一个 fire-and-forget 风格的 HTTP POST,请求地址为:
POST http://127.0.0.1:<worker-port>/api/sessions/observations
请求体包含:
{
"claudeSessionId": "session_id",
"tool_name": "...",
"tool_input": { },
"tool_response": "...",
"cwd": "..."
}
这里还有一个明确数字边界:
- HTTP 超时为 2000ms。
因此,前台 hook 不会长时间等待 worker 或 AI 处理结果。只要请求已投递,PostToolUse 就会尽快结束。
Worker 侧后续处理
PostToolUse 本身负责“入队”,真正的 observation 压缩与存储发生在 worker 里。文档列出的后续流程包括:
- 查找或创建会话:
createSDKSession(claudeSessionId, '', '') - 获取 prompt counter
- 检查隐私状态;如果对应用户 prompt 完全是私密内容,则跳过
- 从
tool_input和tool_response中剥离 memory tags - 将 observation 排队给 SDK agent 处理
- SDK agent 调用 Claude,把原始工具使用压缩成结构化 observation
- 将 observation 存入数据库,并同步到 Chroma
这说明 PostToolUse 与最终数据库落库之间隔着一个异步压缩链路。它本身不是压缩器,而是压缩任务的入口。
输出行为
PostToolUse 的输出为:
{ "continue": true, "suppressOutput": true }
这代表:
- 会话继续执行,不中断 Claude 流程;
- 不向用户显式输出额外内容。
与扩展集成示例的对应关系
在文档的 VS Code 集成示例中,PostToolUse 被映射为一种中间件式事件处理:当文档保存后,扩展向 worker 提交一次 observation 请求。示例中发送的数据包含:
claudeSessionIdtool_name: 'FileSave'tool_input中的文件路径tool_response: 'File saved successfully'
这个示例说明,PostToolUse 的抽象并不依赖某一种具体工具实现;它的核心是:只要发生了可观察的工具行为,就可以把该行为包装成 observation 事件提交给 worker。
细节与边界
任意工具触发,不等于任意工具都保留
配置里的 matcher: '*' 表示所有工具使用都会命中这个 hook;但实现中仍会通过 SKIP_TOOLS 跳过低价值工具。因此“触发范围广”与“最终保留内容有筛选”是同时成立的。
作用是排队,不是同步总结
文档对该阶段 purpose 的定义是 Queue observation for AI compression,不是直接“生成 observation”。真正的 AI 压缩发生在 worker 和 SDK agent 里。
不阻塞前台执行
异步队列与 2 秒 HTTP 超时是这里的关键边界。设计目标是扩展进程永不阻塞,Claude 的工具执行也不应被 observation 压缩拖慢。
仍然受隐私与清洗规则约束
即使工具调用已经被捕获,worker 端仍会:
- 检查对应 prompt 是否完全私密
- 去除
tool_input与tool_response中的 memory tags