Claude Code Hooks 教程:钩子自动化开发流程(2026)
Claude Code Hooks(钩子)是你自己定义的一组 shell 命令,会在 Claude Code 生命周期的特定节点自动执行——比如它编辑完一个文件、准备执行某条命令、会话开始、或者干完活等你输入的时候。和「靠提示词请 AI 记得做某事」不同,Hooks 提供的是确定性控制:只要触发条件满足,命令一定会跑。用它可以做自动格式化、拦截危险操作、写审计日志、在压缩后重新注入项目上下文等。这篇 Claude Code Hooks 教程带你从配置结构、常用事件,到退出码、JSON 输出和 2026 新增的进阶钩子一次讲清楚。
Claude Code Hooks 是什么
Hooks 是写在 Claude Code 设置文件(settings.json)里的一段 JSON 配置。它的核心结构是:hooks 对象下面按「事件名」分组,每个事件对应一个数组,数组里每一项包含一个 matcher(匹配器,用来过滤何时触发)和一个 hooks 列表(真正要执行的命令)。事件触发时,所有匹配的钩子会并行执行。和 CLAUDE.md(给 Claude 读的记忆/规则)、Subagents(隔离上下文里跑子任务)、Skills(额外指令与可执行命令)一样,Hooks 是扩展 Claude Code 的一种方式,区别在于它是「确定性触发的脚本」,不依赖模型自觉。
一句话定位
Claude Code Hooks = 在「编辑文件 / 执行命令 / 会话开始 / 完成响应」等生命周期节点自动触发的 shell 命令。用来把「必须做的事」变成确定发生,而不是祈祷 AI 记得做。
Hooks 能帮你做什么
- 编辑后自动格式化:每次 Claude 改完文件,自动跑 Prettier / gofmt / black,保持代码风格统一
- 拦截危险操作:在命令执行前检查,遇到 rm -rf、drop table、改 .env 等直接阻断并把原因反馈给 Claude
- 写审计日志:把每条 Bash 命令、每次配置变更追加到日志文件,方便合规和复盘
- 注入上下文:会话开始或上下文压缩后,自动把项目约定、最近提交塞回给 Claude,避免它「失忆」
- 桌面通知:Claude 干完活等你输入时,弹一条系统通知,你就能切去做别的事不用盯着终端
- 自动批准特定权限:对你总是放行的工具调用(如退出计划模式)自动确认,少点几次授权弹窗
配置放在哪:settings.json 的几个位置
你把钩子写在哪个文件,决定了它的作用范围。最常用的是前三个:全局对所有项目生效、项目级可提交进仓库共享、本地级不进版本库。
| 位置 | 作用范围 | 是否可共享 |
|---|---|---|
| ~/.claude/settings.json | 你的所有项目 | 否,只在本机 |
| .claude/settings.json | 单个项目 | 是,可提交进仓库给团队共享 |
| .claude/settings.local.json | 单个项目 | 否,默认被 gitignore |
| 托管策略设置 / 插件 / Skill 或 Agent 的 frontmatter | 组织级 / 启用插件时 / 组件激活时 | 是,由管理员或组件控制 |
用 /hooks 查看已注册的钩子
在 Claude Code 里输入 /hooks 可以打开钩子浏览器,按事件分组列出所有已生效的钩子和数量。注意这个菜单是只读的——增删改钩子要直接编辑 settings.json,或者直接让 Claude 帮你改。
第一个钩子:编辑后自动格式化
最经典的入门例子:用带 Edit|Write 匹配器的 PostToolUse 事件,在 Claude 每次改完文件后自动跑 Prettier。命令里用 jq 从钩子输入的 JSON 里取出被编辑的文件路径,再交给 prettier。把下面这段加到项目根目录的 .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}示例命令依赖 jq
本文多数 Bash 示例用 jq 解析钩子传进来的 JSON。没装的话先装:macOS 用 brew install jq,Debian/Ubuntu 用 apt-get install jq;不想用 jq 也可以改用 Python / Node 解析。另外若已有 hooks 配置,请把新事件作为同级键加进去,别整块覆盖。
常用 Hook 事件一览
Claude Code 的钩子事件很多,下面挑最常用的几个列出触发时机(完整列表可查官方 Hooks 参考)。不同事件在不同字段上匹配:工具类事件(PreToolUse/PostToolUse)用工具名匹配,SessionStart 用启动方式匹配(startup/resume/clear/compact),Notification 用通知类型匹配。
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
| PreToolUse | 一次工具调用执行前(可阻断) | 拦截危险命令、保护敏感文件 |
| PostToolUse | 一次工具调用成功后 | 编辑后格式化、记录命令日志 |
| UserPromptSubmit | 你提交提示词、Claude 处理它之前 | 校验/补充上下文(stdout 会加进上下文) |
| SessionStart | 会话开始或恢复时 | 注入项目约定、加载环境变量 |
| Notification | Claude 发通知时(如等你输入/授权) | 桌面弹窗提醒 |
| Stop | Claude 完成本轮响应时 | 检查任务是否真的完成、收尾清理 |
| SubagentStop | 子智能体跑完时 | 汇总子任务结果 |
| SessionEnd | 会话结束时 | 清理临时文件 |
拦截危险操作:PreToolUse + 退出码 2
钩子最有价值的场景之一,是在命令真正执行前把关。做法是给 PreToolUse 挂一个脚本:脚本从标准输入读到 Claude 想执行的命令,命中危险模式就以退出码 2 退出——这会阻断这次调用,并把你写到 stderr 的原因反馈给 Claude,让它换个做法。下面这个脚本拦截 rm -rf 和 drop table:
#!/bin/bash
# block-dangerous.sh —— 放到 .claude/hooks/ 下,记得 chmod +x
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -qiE 'rm -rf|drop table'; then
echo "已拦截:危险命令不允许执行" >&2 # stderr 会作为反馈发回给 Claude
exit 2 # 退出码 2 = 阻断这次工具调用
fi
exit 0 # 退出码 0 = 不干预,走正常权限流程然后在 .claude/settings.json 里把脚本注册到 PreToolUse。$CLAUDE_PROJECT_DIR 是 Claude Code 提供的环境变量,指向当前项目根目录,用它引用脚本比写绝对路径更稳:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/block-dangerous.sh"
}
]
}
]
}
}PreToolUse 拦截优先级高于权限模式
PreToolUse 钩子在任何权限模式检查之前触发。即使开了 --dangerously-skip-permissions 或 bypassPermissions,返回拒绝的钩子照样能挡住工具——这让你能强制执行用户改权限模式也绕不过的策略。反过来不成立:钩子返回 allow 不能覆盖设置里的 deny 规则,钩子只能收紧、不能放宽。真正的硬性允许/拒绝应交给权限系统,钩子做防护栏。
退出码与 JSON 输出:钩子怎么和 Claude 对话
命令钩子通过标准输入、标准输出、标准错误和退出码与 Claude Code 通信。事件触发时,Claude Code 把事件数据以 JSON 喂到脚本的 stdin;脚本干完活后,用退出码告诉 Claude Code 接下来怎么办:
- 退出码 0:没有异议,操作照常进行。对 UserPromptSubmit / SessionStart 等事件,你写到 stdout 的内容会被加进 Claude 的上下文
- 退出码 2:阻断操作,stderr 的内容作为反馈发回给 Claude 让它调整(部分事件如 SessionStart/Notification 无法阻断,此时 stderr 只展示给用户)
- 其他退出码:操作继续,但成绩单会显示一条 hook error 通知,完整 stderr 进调试日志
想要更精细的控制,就别用退出码,而是退出 0 并往 stdout 打印一个 JSON 对象。比如 PreToolUse 可以返回 permissionDecision 为 deny/allow/ask,并给出理由——deny 会取消这次工具调用并把 permissionDecisionReason 反馈给 Claude。注意:退出 2 和 JSON 输出二选一,别混用(退出 2 时 Claude Code 会忽略 JSON)。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "这里请改用 rg 代替 grep,性能更好"
}
}用 matcher 和 if 精确过滤
不加匹配器,钩子会在每次该事件发生时都触发。matcher 让你按工具名缩小范围,比如 "Edit|Write" 只在文件编辑工具后触发,"mcp__github__.*" 匹配某个 MCP 服务器的所有工具。想更细,可以用 if 字段:它用权限规则语法按「工具名 + 参数」一起过滤,只有工具调用真正匹配时才启动钩子进程。下面这个只在 Claude 执行 git push 时才跑检查脚本:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git push *)",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-git.sh"
}
]
}
]
}
}if 只对工具类事件(PreToolUse / PostToolUse / PostToolUseFailure / PermissionRequest / PermissionDenied)有效,加到别的事件上会让钩子直接不跑。matcher 区分大小写,写错工具名钩子就静默不触发——排查时先用 /hooks 确认它出现在正确事件下。
更进阶:prompt / agent / http 钩子(2026)
除了最常见的 "type": "command",Claude Code 还支持几种钩子类型,适合「需要判断而非死规则」或「要对接外部系统」的场景:prompt 钩子把事件数据交给一个 Claude 模型(默认 Haiku)做一次是/否判断;agent 钩子会生成一个能读文件、跑命令的子智能体来验证条件(官方标注为实验性);http 钩子把事件 POST 到一个 URL 由外部服务处理;还有 mcp_tool 钩子可以直接调用已连接 MCP 服务器上的工具。举个 prompt 钩子的例子——在 Claude 想停下时,让模型判断任务是否真的都完成了,没完成就让它继续干:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "检查是否所有请求的任务都已完成;如果没有,返回 ok=false 并说明还差什么。"
}
]
}
]
}
}钩子事件在持续增加,以官方参考为准
Claude Code 的钩子事件和类型迭代很快——除了本文列的常用事件,还有 PreCompact/PostCompact、FileChanged、CwdChanged、ConfigChange、SubagentStart 等更多事件,部分事件(如某些 Notification 匹配器)还要求较新的 Claude Code 版本。配置前建议对照官方 Hooks 参考确认事件名、字段和版本要求。agent 钩子目前仍是实验性,生产流程更推荐用 command 钩子。
Hooks 把「AI 编程里那些必须做、又容易被忘掉的事」变成了确定发生的自动化。但钩子只是把关卡,真正决定产出质量的,还是你会不会拆需求、设边界、审代码,把 AI 的能力稳定用进真实项目。想系统掌握用 Claude Code 等 AI 工具做出能交付产品的方法,欢迎来 IMAI 看看我们的体系化实战课程。
想系统学会用 AI 编程,从入门到做出真实产品?
查看系统课程