Hook 系统

Hook 系统让用户可以在 Claude Code 的生命周期关键节点注入自定义行为 — 从工具执行前后到会话开始结束。

Hook 系统概览

Hook 是用户配置的 shell 命令,在特定事件触发时自动执行。每个 Hook 接收 JSON 格式的输入(通过 stdin),通过 exit code 和 stdout/stderr 影响系统行为。

核心文件: src/utils/hooks/ 目录下包含:AsyncHookRegistry.ts(异步注册表)、hookEvents.ts(事件系统)、hooksConfigManager.ts(配置管理)、execPromptHook.ts(执行引擎)。

15+ 生命周期事件

事件名 触发时机 输入 (stdin JSON) 可控行为
核心生命周期
SessionStart 会话开始 (init/resume/clear/compact) session 信息 初始化自定义环境
Setup 仓库初始化/维护 repo 信息 执行 setup 脚本
UserPromptSubmit 用户输入处理前 用户提示内容 拦截/替换用户输入
Stop 助手即将结束回复 回复信息 exit 2 → stderr 显示给模型
工具钩子
PreToolUse 工具执行前 工具名 + 输入参数 JSON exit 0=静默, 2=阻止+原因
PostToolUse 工具执行后 {inputs, response} exit 0=transcript, 2=显示给模型
PostToolUseFailure 工具执行失败 {tool_name, error, is_timeout} 错误日志/通知
PermissionRequest 权限对话框显示时 {tool_name, tool_input} Hook 决定 allow/deny
PermissionDenied auto 模式分类器拒绝 {tool_name, reason} 设置 {retry: true} 重试
Agent 钩子
SubagentStart 子 Agent 生成时 {agent_id, agent_type} 记录/通知
SubagentStop 子 Agent 结束时 {agent_id, transcript_path} 清理/分析
压缩钩子
PreCompact 上下文压缩前 {trigger: 'manual'|'auto'} exit 0=追加指令, 2=阻止压缩
PostCompact 上下文压缩后 {trigger} exit 0=stdout 显示给用户
其他钩子
Notification 通知发送时 {notification_type} 自定义通知行为
TaskCreated/Completed 任务生命周期 {task_id, task_subject} exit 2=阻止

配置方式

Hook 在 settings.json 中配置:

// ~/.claude/settings.json 或 .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": { "tool_name": "Bash" },
        "command": "python3 check_bash_safety.py"
      }
    ],
    "PostToolUse": [
      {
        "matcher": { "tool_name": "FileWriteTool" },
        "command": "./scripts/auto-format.sh"
      }
    ],
    "SessionStart": [
      {
        "command": "echo 'Session started' >> ~/.claude/session.log"
      }
    ]
  }
}
    

执行机制

Hook 通过子进程执行,输入通过 stdin 传递,输出通过 stdout/stderr 收集:

// 执行流程 (execPromptHook.ts)
async function executePromptHook(hookConfig, input) {
  // 1. 启动子进程
  const proc = spawn(hookConfig.command, { shell: true });

  // 2. 传入 JSON 输入
  proc.stdin.write(JSON.stringify(input));
  proc.stdin.end();

  // 3. 收集输出
  const stdout = await readStream(proc.stdout);
  const stderr = await readStream(proc.stderr);

  // 4. 根据 exit code 决定行为
  const exitCode = await proc.exitCode;
  return { exitCode, stdout, stderr };
}
    

Exit Code 约定

Exit 0 — 成功

PreToolUse: 静默通过
PostToolUse: stdout 以 transcript 模式显示
PreCompact: stdout 追加到压缩指令

Exit 2 — 特殊控制

PreToolUse: 阻止工具执行,stderr 作为原因显示给模型
PreCompact: 阻止压缩
TaskCreated: 阻止任务创建

其他 Exit Code

stderr 仅显示给用户(不传递给模型)。用于日志记录和调试信息。

异步 Hook 注册表

AsyncHookRegistry 管理长时间运行的 Hook: