12Lifecycle Hooks
L3P1五步章 · 技术章
Why · 为什么要学
每次 tool 执行前要审计、每次 compaction 触发前要保存进度、每个 session 启动时要预加载——这些都不应该改 harness 核心。Hooks 是 harness 把"扩展点"暴露给用户的标准机制,做 harness 工程师就要会设计这套接口:哪些时机暴露、传什么数据、允许修改什么。
1 ·核心要点
Claude Code 提供的钩子事件:
| Hook | 触发时机 | 是否可拦截 |
|---|---|---|
PreToolUse | tool 执行前 | 是(block/allow/modify) |
PostToolUse | tool 执行完 | 否(只能观察) |
UserPromptSubmit | 用户输入提交时 | 是 |
PreCompact | 自动 compaction 触发前 | 是 |
Stop | agent 决定结束时 | 是 |
SessionStart | 新 session 启动 | 否 |
SessionEnd | session 结束 | 否 |
每个 hook 是用户配置的 shell 命令或函数,接收 JSON 输入(含 tool 名、参数、context 等),输出 JSON 决策({decision: "block" | "allow" | "modify", ...})。
典型用途:PostToolUse 写审计日志;PreToolUse 拦截 destructive 命令;PreCompact 在压缩前把进度写到 progress.md(配合 #17 Long-Running);SessionStart 预加载用户偏好;Stop 在 agent 提前退出时触发 cleanup。
设计原则:Pre-* hooks 可拦截/修改(给用户介入空间);Post-* / SessionEnd 只能观察(已经发生的事不能改)。这个区分是 hook 接口设计的核心。
2 ·最小代码示例
# PreToolUse hook 示例:拦截 rm 相关命令
# ~/.claude/settings.json
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "/path/to/check-bash.sh"
}]
}]
}
}
# check-bash.sh
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qE '^rm\s+-rf|sudo rm'; then
echo '{"decision":"block","reason":"危险命令需要明确确认"}'
else
echo '{"decision":"allow"}'
fi
3 ·工程权衡
什么场景该用 hook
- 审计/合规——PostToolUse 记录所有 tool 调用
- 安全门——PreToolUse 拦截 destructive 操作
- 跨 session 状态——PreCompact / SessionEnd 持久化关键数据
- 团队定制——不同团队有不同 ops 习惯,hook 让 harness 主体不变前提下做差异化