Skip to content
雲里
里雾

05 Hook 生命周期钩子——Agent 的中间件

claude code guide AI 更新于 2026/3/26

原文:Hooks Reference + Hooks Guide

什么是 Hook

Hook 是在 Claude Code 生命周期特定点自动执行的脚本。和 CLAUDE.md(“建议性”指令)不同,Hook 是确定性的——它保证每次都执行,不依赖 LLM 的判断。

类比:Hook 就像 Express 的 MiddlewareGit Hook。Express 的 app.use() 在请求处理的特定点注入逻辑;Git 的 pre-commit 在提交前自动执行脚本。Claude Code 的 Hook 有 SessionStartPreToolUsePostToolUseStop。你在这些节点注入自定义行为,而不需要修改主流程。

关键区别:

Hook 三层配置

{
  "hooks": {
    "PreToolUse": [          // 1. 事件名
      {
        "matcher": "Bash",    // 2. 匹配器(过滤条件)
        "hooks": [
          {
            "type": "command", // 3. 处理器(执行什么)
            "command": ".claude/hooks/check.sh"
          }
        ]
      }
    ]
  }
}

核心事件一览

会话级别

事件时机能做什么
SessionStart会话开始/恢复加载环境变量、初始化
SessionEnd会话结束清理资源

工具级别(最常用)

事件时机能做什么
PreToolUse工具执行前拦截、修改、放行
PostToolUse工具成功后验证结果、追加信息
PostToolUseFailure工具失败后错误处理
PermissionRequest权限弹窗时自动允许/拒绝

代理级别

事件时机能做什么
SubagentStartSubAgent 开始初始化环境
SubagentStopSubAgent 结束清理
StopClaude 完成回复阻止结束、追加任务

其他

事件时机
UserPromptSubmit用户 prompt 提交前
FileChanged监控的文件变更
CwdChanged工作目录变更
PreCompact / PostCompact上下文压缩前后

四种处理器类型

类型说明适用
command执行 shell 命令最常用,脚本验证
http发 POST 请求集成外部服务
prompt单轮 LLM 评估需要语义判断的验证
agent启动 SubAgent 验证复杂验证逻辑

退出码的含义

退出码效果
0成功。如果有 JSON 输出则处理
2阻断。操作被拒绝,stderr 显示给用户
其他非阻断错误。仅在 verbose 模式显示

这是 Hook 最强大的能力PreToolUse + 退出码 2 = 安全门控。

实际应用示例

阻止危险命令

#!/bin/bash
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
if echo "$COMMAND" | grep -q 'rm -rf'; then
  echo "Blocked dangerous command" >&2
  exit 2
fi
exit 0

编辑后自动格式化

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "npx prettier --write \"$TOOL_INPUT_FILE\""
        }]
      }
    ]
  }
}

桌面通知(Claude 完成任务时)

{
  "hooks": {
    "Notification": [
      {
        "matcher": "idle_prompt",
        "hooks": [{
          "type": "command",
          "command": "osascript -e 'display notification \"Claude 完成了\" with title \"Claude Code\"'"
        }]
      }
    ]
  }
}

配置位置

位置作用域
~/.claude/settings.json所有项目
.claude/settings.json当前项目(可分享)
.claude/settings.local.json当前项目(不提交)
Plugin hooks/hooks.json插件范围
Skill/Agent frontmatter特定 Skill/Agent 活跃期间

知识检测

概念理解题

  1. Hook 和 CLAUDE.md 指令的根本区别是什么?为什么说 Hook 是”确定性的”?

  2. PreToolUse 的退出码 2 有什么特殊含义?为什么说这是 Hook 最强大的能力?

  3. Hook 的四种处理器类型(command/http/prompt/agent)各自适合什么场景?prompt 类型和 CLAUDE.md 指令有什么区别?

应用题

  1. 你想确保 Claude 永远不会修改 package-lock.jsonpnpm-lock.yaml 文件。写出对应的 Hook 配置(JSON 格式)和验证脚本。

  2. 你想让 Claude 每次编辑 .ts 文件后自动跑 eslint --fix,每次编辑 .py 文件后自动跑 ruff check --fix。怎么配置?

迁移思考题

  1. Claude Code 的 Hook 和 Git Hook 的设计思路有什么相似和不同?Claude Code 的 Hook 增加了什么 Git Hook 没有的能力?(提示:参考 SlipBox 中的 Hook 卡片)

  2. OpenClaw 的 Hook 分为 Internal Hook(响应 Agent 事件)和 Webhook(接收外部 HTTP)。Claude Code 如何覆盖这两个场景?


参见

参考答案

1. Hook vs CLAUDE.md 的根本区别

CLAUDE.md 是”建议”——Claude 看到后”尽量”遵守,但可能因为上下文拥挤、指令冲突或模型推理而忽略。Hook 是”程序”——系统在事件触发时无条件执行脚本,不依赖 LLM 判断。“确定性”意味着:给定相同的输入,Hook 的输出 100% 一致;而 CLAUDE.md 的遵守率是概率性的。

2. 退出码 2 的意义

退出码 2 是 Hook 的否决权——它能阻止 Claude 的操作生效。这让你可以实现硬性安全策略:比如”绝对禁止删除 production 目录的文件”,无论 Claude 的推理多么”合理”都不行。这是 CLAUDE.md 做不到的(CLAUDE.md 写”不要删除 production 文件”,Claude 可能在某些情况下仍然这么做)。

3. 四种处理器的适用场景

command(最常用):快速的确定性检查(lint、格式验证、文件权限检查)。http:需要集成外部服务(通知 Slack、记录到监控系统)。prompt:需要语义判断但仍想由 LLM 做决定的场景(“这个命令看起来危险吗?”),比手写规则更灵活但有延迟。agent:需要多步验证的复杂场景(运行测试套件并分析结果)。prompt 和 CLAUDE.md 的区别:prompt 是独立的单轮评估,不受主对话上下文影响。

4. 保护 lock 文件的 Hook

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Edit|Write",
      "hooks": [{
        "type": "command",
        "command": "bash -c 'FILE=$(jq -r \".tool_input.file_path // .tool_input.path\" < /dev/stdin); case \"$FILE\" in */package-lock.json|*/pnpm-lock.yaml) echo \"Blocked: lock files are read-only\" >&2; exit 2;; esac; exit 0'"
      }]
    }]
  }
}

5. 按文件类型自动 lint

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{
          "type": "command",
          "command": "bash -c 'FILE=$(jq -r \".tool_input.file_path // .tool_input.path\" < /dev/stdin); case \"$FILE\" in *.ts|*.tsx) npx eslint --fix \"$FILE\";; *.py) ruff check --fix \"$FILE\";; esac; exit 0'"
        }]
      }
    ]
  }
}

6. Claude Code Hook vs Git Hook

相似:都在流程”关节处”执行(pre-commit / PreToolUse),都支持否决(非零退出码阻止操作)。不同:(1) Claude Code Hook 有 4 种处理器(Git Hook 只有 shell)(2) Claude Code Hook 可以修改工具输入/输出(Git Hook 不能修改 commit 内容)(3) Claude Code Hook 有语义判断能力(prompt 类型)(4) Claude Code Hook 粒度更细(20+ 事件 vs Git 的 ~10 个)。

7. OpenClaw 的两个 Hook 场景

OpenClaw Internal Hook(TypeScript 函数 + 事件订阅)覆盖了 Claude Code 的 command 类型 Hook 的场景。OpenClaw Plugin Hook(before_tool_call / tool_result_persist 等)提供了 Claude Code 没有的”修改 Agent Loop 内部状态”的能力——如 tool_result_persist 可以在工具输出写入记录前修改它,Claude Code 的 PostToolUse Hook 只能观察和反馈,不能直接修改。