Claude Code Hooks 怎么配置?自动化工作流实战
Claude Code Hooks 的配置方法很简单:在 ~/.claude/settings.json(或项目级 .claude/settings.json)里加一个 hooks 字段,按事件类型(如 PreToolUse、PostToolUse、Stop)注册要运行的 shell 命令,Claude Code 会在对应时机自动执行这些命令。它本质上是一套确定性的「事件触发器」,让你把格式化、检查、拦截、通知等动作固化进工作流,而不是每次都靠提示词去提醒模型。
Hooks 是什么,解决什么问题
Claude Code 是 Anthropic 官方命令行工具,它在执行任务时会频繁调用工具:写文件、跑命令、编辑代码。模型的行为是概率性的,你没法保证它每次写完代码都去跑一遍 prettier,也没法保证它不会执行某条危险命令。Hooks 把这些「必须发生」的动作从模型的自由发挥里抽出来,变成由 Claude Code 运行时强制执行的脚本。
典型用途包括:
- 写完或改完文件后自动格式化、自动 lint。
- 在执行 Bash 命令前做安全校验,拦截
rm -rf之类的高危操作。 - 任务结束时发系统通知、写日志、做提交前检查。
- 给模型注入额外上下文,或记录完整的操作审计。
如果你还不熟悉 Claude Code 的基本操作,建议先看 Claude Code 常用命令大全(附使用场景) 和 Claude Code CLAUDE.md 配置文件怎么写?完整模板,再回来配 Hooks 会顺畅很多。
钩子事件类型一览
Hooks 按「事件」触发,常用的几类事件如下:
| 事件名 | 触发时机 | 典型用途 |
|---|---|---|
| PreToolUse | 工具调用执行前 | 校验、拦截、改写参数 |
| PostToolUse | 工具调用成功后 | 格式化、lint、测试 |
| UserPromptSubmit | 用户提交输入后 | 注入上下文、记录 |
| Stop | 主回合结束时 | 通知、收尾检查 |
| SessionStart | 会话开始时 | 加载环境信息 |
其中 PreToolUse 和 PostToolUse 支持用 matcher 按工具名过滤,比如只在 Write、Edit 这类写文件工具上触发,或者用正则 Edit|Write 匹配多个工具。
配置结构与 settings.json 写法
Hooks 写在 settings.json 的 hooks 字段里,结构是「事件 → matcher 数组 → hooks 命令数组」。下面这个例子在每次 Write 或 Edit 后自动用 Prettier 格式化改动的文件:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs -r npx prettier --write"
}
]
}
]
}
}
关键点:每个 hook 的 type 目前是 command,command 是一条 shell 命令。Claude Code 会通过 stdin 把一段 JSON 传给你的命令,里面包含会话信息和本次工具调用的输入。上面用 jq 从 .tool_input.file_path 取出被修改的文件路径,再交给 prettier。
stdin 数据与退出码协议
钩子脚本和 Claude Code 之间的通信靠两样东西:stdin 的 JSON 输入,以及脚本的退出码。
stdin JSON 的常见字段有 session_id、hook_event_name、tool_name、tool_input(PostToolUse 还有 tool_response)。退出码的语义是重点:
- 退出码 0:成功,正常继续。stdout 一般不影响流程(部分事件下会作为上下文)。
- 退出码 2:阻断。Claude Code 会拦截这次操作,并把脚本的 stderr 反馈给模型,让它据此调整。这是实现「拦截危险命令」的核心机制。
- 其他非 0 退出码:视为一般错误,stderr 会显示出来但不强制阻断。
下面是一个 PreToolUse 拦截危险 Bash 命令的脚本示例(保存为 guard.sh 并赋予可执行权限):
#!/usr/bin/env bash
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf|:\(\)\{|mkfs|dd if='; then
echo "已拦截高危命令:$cmd,请确认后手动执行。" >&2
exit 2
fi
exit 0
对应在 settings.json 里注册:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/guard.sh" }
]
}
]
}
}
命令里可以用 $CLAUDE_PROJECT_DIR 这个环境变量定位项目根目录,避免写死绝对路径。
实战案例:三个高频自动化工作流
1. 改完代码自动跑测试
在 PostToolUse 上 matcher 设为 Edit|Write,命令里判断如果改的是 .py 文件就跑相关测试,把失败信息通过 stderr + 退出码 2 反馈给模型,让它自己修。这样模型每改一次代码就有一道质量闸门。
2. 任务结束发通知
在 Stop 事件挂一条命令,Linux 上用 notify-send、macOS 上用 osascript 弹通知,长任务跑完不用一直盯着终端。
3. 操作全量审计日志
在 PreToolUse(matcher 留空匹配全部工具)追加一条命令,把每次 stdin JSON 连同时间戳写进 .claude/audit.log。团队协作或合规场景下,这份日志能完整还原 Claude Code 做过的每一步。
调试与避坑要点
- 用
claude --debug启动,可以看到每个钩子的执行命令、退出码和输出,排错最直接。 - 钩子命令以你当前的用户权限运行,且默认有超时限制(可在配置里调整),写脚本时务必只放可信代码。
- matcher 是对工具名的匹配,写错工具名(比如把
Bash写成bash)钩子就不会触发。 - 修改 settings.json 后,新的会话才会加载最新配置,必要时重启 Claude Code。
- Windows 用户建议在 WSL 或 Git Bash 环境下写钩子脚本,避免路径和 shell 差异。安装相关问题可参考 Claude Code 怎么安装?Windows 完整安装教程(2026)。
Hooks 经常和子代理、MCP 一起组合使用:钩子负责确定性的「卡点」,子代理负责拆分复杂任务,MCP 负责接外部数据源。想进一步搭建自动化流水线,可以接着看 Claude Code 子代理(Subagent)怎么用?实战教程 和 Claude Code 配置 MCP 服务器完整步骤。
常见问题
Hooks 配置后不生效怎么办?
先确认三点:一是 settings.json 是合法 JSON(多一个逗号都会让整个配置失效),二是 matcher 的工具名大小写正确,三是钩子脚本有可执行权限且路径正确。用 claude --debug 观察钩子是否被调用、退出码是多少。如果完全没触发,多半是 JSON 格式错误或事件名拼错。更多排查思路见 Claude Code 报错不工作?常见问题排查清单。
项目配置和全局配置冲突时以谁为准?
Claude Code 会同时加载用户级(~/.claude/settings.json)和项目级(.claude/settings.json)的 Hooks,两者通常是合并叠加而非互相覆盖,即同一事件上的多个钩子都会执行。建议把通用规则放用户级、项目专属规则放项目级,并把项目配置纳入版本管理,方便团队共享。
Hooks 会消耗 API Token 吗?
钩子脚本本身在本地运行,不直接调用 Messages API,所以执行命令这一步不产生 Token 费用。但钩子通过 stderr 反馈给模型的内容、或注入的上下文,会进入后续对话,间接增加输入 Token。想控制成本可以让钩子只在必要时输出精简信息,相关技巧见 Claude API 怎么省钱?5 个降低 Token 成本的方法。