12Lifecycle Hooks

L3P1五步章 · 技术章
Why · 为什么要学
每次 tool 执行前要审计、每次 compaction 触发前要保存进度、每个 session 启动时要预加载——这些都不应该改 harness 核心。Hooks 是 harness 把"扩展点"暴露给用户的标准机制,做 harness 工程师就要会设计这套接口:哪些时机暴露、传什么数据、允许修改什么。
1 ·核心要点

Claude Code 提供的钩子事件:

Hook 触发时机 是否可拦截
PreToolUsetool 执行前是(block/allow/modify)
PostToolUsetool 执行完否(只能观察)
UserPromptSubmit用户输入提交时
PreCompact自动 compaction 触发前
Stopagent 决定结束时
SessionStart新 session 启动
SessionEndsession 结束

每个 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

  1. 审计/合规——PostToolUse 记录所有 tool 调用
  2. 安全门——PreToolUse 拦截 destructive 操作
  3. 跨 session 状态——PreCompact / SessionEnd 持久化关键数据
  4. 团队定制——不同团队有不同 ops 习惯,hook 让 harness 主体不变前提下做差异化