Skip to content

Hooks 钩子

Hook 是在 Claude Code 生命周期的固定节点上自动执行的 shell 命令

它和 CLAUDE.md 的本质区别:CLAUDE.md 里的规则是请求模型遵守,模型可能忘;Hook 是由程序强制执行的,模型绕不过去。

需要「每次改完代码自动格式化」「提交前必须跑测试」这类硬约束时,用 Hook,不要靠写在 CLAUDE.md 里祈祷。

配置位置

写在 settings.jsonhooks 字段里:

文件作用范围
~/.claude/settings.json所有项目
<项目根>/.claude/settings.json该项目,提交到 Git
<项目根>/.claude/settings.local.json该项目,个人本地,.gitignore

可用的钩子点

事件触发时机典型用途
PreToolUse工具执行拦截危险命令、校验参数
PostToolUse工具执行自动格式化、跑 lint
UserPromptSubmit你按下回车后注入上下文、记录审计日志
Notification需要你注意时发系统通知、响铃
Stop一轮回答结束跑测试、汇总改动
SessionStart会话开始打印环境信息

例 1:写完文件自动格式化

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read f; case \"$f\" in *.ts|*.tsx) npx prettier --write \"$f\" ;; *.go) gofmt -w \"$f\" ;; *.py) ruff format \"$f\" ;; esac; }"
          }
        ]
      }
    ]
  }
}

Hook 从 stdin 收到一个 JSON,里面有 tool_nametool_input 等字段,用 jq 取出来即可。

例 2:拦截危险命令

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.command' | grep -qE 'rm -rf /|DROP DATABASE|git push --force' && { echo '拒绝执行高危命令' >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

退出码语义

退出码效果
0放行
2阻止这次工具调用,stderr 的内容回传给模型
其它报错但不阻止

exit 2 是唯一能真正拦住模型的方式。

例 3:一轮结束自动跑测试

json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "cd \"$CLAUDE_PROJECT_DIR\" && go test ./... 2>&1 | tail -20"
          }
        ]
      }
    ]
  }
}

别在 Stop 里跑很慢的东西

Stop 每一轮都会跑。全量测试要两分钟的话,你每问一句都要等两分钟。 慢任务改用 PostToolUse + matcher 精确匹配,或者干脆手动跑。

例 4:完成时响铃

json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          { "type": "command", "command": "afplay /System/Library/Sounds/Glass.aiff" }
        ]
      }
    ]
  }
}

macOS 用 afplay;Linux 用 paplay;Windows 用 PowerShell 的 [console]::beep(800,300)

可用的环境变量

变量含义
$CLAUDE_PROJECT_DIR当前项目根目录
stdin JSON .tool_name触发的工具名
stdin JSON .tool_input工具入参对象
stdin JSON .session_id会话 ID

调试 Hook

bash
claude --debug

会打印每个 hook 的命令、退出码和输出。Hook 不生效时最常见的三个原因:

  1. JSON 语法错误——整个 settings.json 失效,用 jq . ~/.claude/settings.json 验证
  2. 命令里的引号没转义——JSON 字符串里的 " 要写成 \"
  3. matcher 没匹配上——matcher 是正则,匹配的是工具名(BashEditWriteRead…)

安全提醒

Hook 会用你的权限执行任意命令

不要直接复制来路不明的 hook 配置,尤其是别人仓库里的 .claude/settings.json

克隆陌生项目后,先看一眼 .claude/settings.json 里有没有 hooks,再启动 Claude Code。

和成本的关系

Hook 本身不产生 API 调用,不花钱。但它能间接省钱:

  • 自动格式化 → 模型不用再花一轮去修格式
  • 自动跑测试 → 错误当场暴露,不用来回问「跑一下测试」
  • 拦截危险命令 → 不用事后花上下文去补救

配套阅读

文档持续更新 · 以 站内价格页 与控制台实际配置为准