除 PreToolUse 与 PostToolUse 外,还有更多 Hook 类型:
Notification:Claude 请求工具权限或 60 秒空闲时触发Stop:Claude 回复结束时触发SubagentStop:子代理任务结束时触发PreCompact:compact 操作前触发UserPromptSubmit:用户提交提示词时触发SessionStart:会话开始或恢复时触发SessionEnd:会话结束时触发
令人困惑的地方在于:
- 不同 Hook 的标准输入结构完全不同
- PreToolUse/PostToolUse 的输入还会随工具类型变化
例如,下面是一个 PostToolUse(监听 TodoWrite)的输入:
{
"session_id": "9ecf22fa-edf8-4332-ae85-b6d5456eda64",
"transcript_path": "<path_to_transcript>",
"hook_event_name": "PostToolUse",
"tool_name": "TodoWrite",
"tool_input": {
"todos": [{ "content": "write a readme", "status": "pending", "priority": "medium", "id": "1" }]
},
"tool_response": {
"oldTodos": [],
"newTodos": [{ "content": "write a readme", "status": "pending", "priority": "medium", "id": "1" }]
}
}
而 Stop Hook 的输入是:
{
"session_id": "af9f50b6-f042-4773-b3e2-c3a4814765ce",
"transcript_path": "<path_to_transcript>",
"hook_event_name": "Stop",
"stop_hook_active": false
}
可以看到,不同 Hook 的输入差异非常大,这使得编写 Hook 变得困难——你不一定知道该解析哪些字段。
建议做一个辅助 Hook 来记录输入:
"PostToolUse": [ // Or "PreToolUse" or "Stop", etc
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "jq . > post-log.json"
}
]
},
]
该命令会把 Hook 输入写入 post-log.json,方便你观察真实结构,从而更容易编写稳定的 Hook。