W
AI-Wiki
CONCEPT

PostToolUse

定义

PostToolUseclaude-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 架构中,与 SessionStartUserPromptSubmitsummary-hook.jscleanup-hook.js 等阶段或脚本共同组成一次 Claude Code 会话中的采集与处理链路。

其所在系统采用“两进程架构”:扩展或宿主侧负责快速发出 HTTP 请求,worker 负责异步处理 observation,因此 PostToolUse 不是在前台同步完成 AI 总结,而是把工具调用结果送入后台队列。文档特别强调,这样做的目标是不阻塞 IDE 或 Claude 的工具执行。

生命周期位置

在完整的 5 个阶段中,PostToolUse 排在第 3 位:

    1. SessionStartcontext-hook.js,注入历史上下文
    1. UserPromptSubmitnew-hook.js,创建或获取会话并初始化 worker
    1. PostToolUsesave-hook.js,在工具调用后排队 observation
    1. Stop:summary-hook.js,生成会话摘要
    1. SessionEnd:cleanup-hook.js,标记会话完成

这说明 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 里。文档列出的后续流程包括:

  1. 查找或创建会话:createSDKSession(claudeSessionId, '', '')
  2. 获取 prompt counter
  3. 检查隐私状态;如果对应用户 prompt 完全是私密内容,则跳过
  4. tool_inputtool_response 中剥离 memory tags
  5. 将 observation 排队给 SDK agent 处理
  6. SDK agent 调用 Claude,把原始工具使用压缩成结构化 observation
  7. 将 observation 存入数据库,并同步到 Chroma

这说明 PostToolUse 与最终数据库落库之间隔着一个异步压缩链路。它本身不是压缩器,而是压缩任务的入口。

输出行为

PostToolUse 的输出为:

{ "continue": true, "suppressOutput": true }

这代表:

  • 会话继续执行,不中断 Claude 流程;
  • 不向用户显式输出额外内容。

与扩展集成示例的对应关系

在文档的 VS Code 集成示例中,PostToolUse 被映射为一种中间件式事件处理:当文档保存后,扩展向 worker 提交一次 observation 请求。示例中发送的数据包含:

  • claudeSessionId
  • tool_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_inputtool_response 中的 memory tags