Claude Code Hooks 入门 5 分钟让 AI 编码助手自动干活
目标读者:用过 Claude Code、想做工作流自动化的开发者预计阅读时间:6 分钟
令人困扰的操作环节
每次 Claude Code 完成代码修改后,你是不是还得亲自再跑一次 prettier 进行格式化?
格式化结束,紧接着还得记得运行测试?
更让人捏把汗的是,它偶尔会生成一条 rm -rf 命令——即使它大概率不会真删错,你的手指已经下意识准备按下 Ctrl+C 了。
这些重复性强又至关重要的步骤,能否让它自行完成?能不能在危险指令真正生效之前,为你设下一道防护?
hooks 就是干这个的。
理解 Hook
一句话概括:Hook 是在 Claude Code 生命周期的特定节点自动运行的命令。
你可以将它类比为 Git 的 pre-commit 钩子,但触发时机变成了“用户提交 prompt”“工具调用前后”以及“响应结束”等节点。
当相应事件发生时,Claude 会自动执行你预设好的脚本。
⚡ Hook 与 CLAUDE.md 的区别
CLAUDE.md 指令
Hook
执行方式
模型“理解”后自主决定
由代码触发,确定性执行
可靠性
偶尔遗漏
每次必运行,无一例外
适用场景
需要判断力的软性规则
必须强制遵守的硬性规则
下图展示了一次完整交互中 Hook 的触发位置:

图1:Hook 生命周期触发顺序
图1:Hook 生命周期触发顺序——从左侧入口进入,右侧出口退出,中间可能循环多次。你的 Hook 可以挂载在任何一个标注了事件名称的箭头上。
从左侧进入、右侧退出,中间环节可能重复循环。你可以在图中任何一个标注了事件名的箭头上挂载 Hook。
5 分钟上手:你的第一个 hook
hook 写在 settings.json 里,结构是三层嵌套:
事件名 → matcher(匹配的工具)→ hooks(执行的动作)
这看似套娃式结构,实际配置起来非常直观。
以下 hook 的作用:每当 Claude 完成文件写入或编辑后,自动执行 prettier 格式化。
// 📁 .claude/settings.json
{
"hooks": {
"PostToolUse": [ // ← 事件名:工具执行完毕后触发
{
"matcher": "Edit|Write", // ← 限定只匹配写文件类的工具
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
逐字段解析:
PostToolUse— 事件名称,表示“工具执行完成后触发”matcher: "Edit|Write"— 使用管道符号匹配两个工具名称,仅当涉及写文件操作时才会激活type: "command"— 执行一条 shell 命令jq -r '.tool_input.file_path'— 从标准输入的 JSON 中提取文件路径,通过xargs传递给 prettier
💡 核心机制
hook 的事件上下文通过 stdin 以 JSON 格式传入,包含
tool_name、tool_input等字段,脚本利用jq进行解析。所有案例中提取数据都沿用这一模式。
将这段 JSON 粘贴到配置文件中,保存后 hook 会立刻生效。
想要验证?让 Claude 随便修改一个文件,观察缩进是否变得规整——如果变化了,就说明 hook 正在运行。
配置文件存放位置
文件路径
作用范围
适用场景
~/.claude/settings.json
用户级别,适用于所有项目
个人偏好:通知、日志
.claude/settings.json
项目级别,可提交到仓库
团队规范:代码格式化、lint 检查
.claude/settings.local.json
本地级别,被 gitignore 忽略
临时配置,不影响团队其他人
核心事件速查表
在日常开发中,最常用的其实只有 5 个事件,掌握这张表格基本就能应对大部分场景:
| 事件名 | 触发时机 | 典型用途 | 记忆口诀 |
|---|---|---|---|
PreToolUse |
工具调用前 | 拦截危险命令、保护敏感文件 | 想拦截用 Pre |
PostToolUse |
工具调用后 | 自动格式化、lint、类型检查 | 想善后用 Post |
UserPromptSubmit |
用户提交 prompt 后 | 注入上下文、校验输入 | 想开头加料用它 |
Notification |
触发通知时 | 软提醒、消息推送 | 旁路轻量提醒 |
Stop |
Claude 结束响应时 | 桌面通知、强制跑测试 | 想结尾卡关用 Stop |
📚 延伸阅读
官方还提供了
SessionStart、SubagentStop、PreCompact等 30 多个事件,具体可查阅官方文档。对于绝大多数日常需求,以上五个事件就已经足够覆盖。
3 个实战案例
案例一:拦截危险命令
在 PreToolUse 上部署一个检查脚本,如果检测到 rm -rf 或 DROP TABLE 这样的危险指令,就用 exit 2 进行拦截:
// 📁 .claude/settings.json{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "COMMAND=$(jq -r '.tool_input.command'); echo \"$COMMAND\" | grep -qE 'rm -rf|DROP TABLE' && exit 2 || exit 0" } ] } ] }}
这一行代码的核心逻辑很清晰:从标准输入读取命令 → 用 grep 检查是否匹配危险模式 → 命中时 exit 2 阻止执行 → 未命中时 exit 0 放行。
实际测试显示:Claude 会收到"操作被阻断"的提示,随后改用更安全的方式完成任务,而不会强行突破限制。
案例二:任务完成时弹出桌面通知
执行耗时任务时无需一直盯着终端——在 Stop 事件上绑定系统通知即可:
// 📁 .claude/settings.json{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "osascript -e 'display notification \"任务已完成\" with title \"Claude Code\"'" } ] } ] }}
💡 跨平台使用说明
- macOS 系统 → 使用
osascript- Linux 系统 → 使用
notify-send "任务已完成"
配置完成后,每次 Claude 执行完任务,屏幕右上角就会弹出一个气泡提示,提醒你回来查看结果。
案例三:注入 git 分支上下文
通过 UserPromptSubmit 将当前分支名称传递给 Claude,让它清楚自己正在哪个分支上工作:
// 📁 .claude/settings.json{ "hooks": { "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "echo \"当前分支: $(git branch --show-current)\"" } ] } ] }}
UserPromptSubmit 输出的纯文本 stdout 会直接作为上下文注入到对话中。效果很明显:Claude 在生成提交信息或操作文件时,会自动感知当前所处的分支——比如你在 feature/auth 分支上,它就不会误操作 main 分支的内容。
规避陷阱与安全底线
Exit Code 通信协议
hook 与 Claude 之间的交互机制相当简洁——全部依靠 exit code 来决定:
| Exit Code | 含义 | 行为表现 |
|---|---|---|
0 |
放行 | 一切正常,程序继续推进 |
2 |
阻断 | 当前操作被拦截,stderr 内容回传给 Claude |
| 其他非零值 | 非阻断错误 | 仅 verbose 模式下显示,操作照常执行 |
⚠️ 常见误区:
exit 1并不能阻止操作!如果需要强制拦截,必须使用exit 2。
调试方法
手动向脚本传入数据进行测试:
# 模拟危险指令输入,检验 hook 是否能正确拦截
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' | your-hook.sh
echo $? # 预期结果:2
如果已经配置了 hook 却始终无法触发,多半是 JSON 语法存在错误——可以通过 /hooks 菜单查看配置是否成功加载。
⚠️ 安全底线
hook 会以你当前的本地权限执行任意指令,恶意脚本可能窃取数据或删除文件。切勿随意复制网上的 hook 配置,在注册之前务必读懂每一行代码的作用。hook 运行在 agent 循环中,自动触发、无需确认,一旦出现问题你可能毫无察觉。
Hook 的适用场景
Hook 并非万能工具,只有在合适的场景下使用才能真正省心:
| 场景 | 推荐方案 | 理由 |
|---|---|---|
| 确定性自动化、强制规则 | ✅ Hook | 格式化、拦截、提交前测试等"必须每次执行"的操作 |
| 需要判断力的任务 | ❌ 用 subagent 或 prompt handler | 规则难以写死、需要模型进行思考判断的场景 |
| 一次性临时操作 | ❌ 手动执行 | 仅为执行一次的命令配置 hook,反而徒增复杂度 |
💡 实用判断标准
如果你在某个操作之后总是手动重复执行同一条命令,那么就应该考虑将它改造成 hook。反之,如果操作不固定、逻辑涉及分支判断,使用 CLAUDE.md 指令或 subagent 更为恰当。
后续步骤
现在你已熟悉 hook 的核心机制,可以尝试以下进阶操作:
- 从单个 hook 入手 — 将你最常用的某条命令配置为一个 hook,先试用两天,体验其效果
- 循序渐进地扩展 — 依次添加格式化、lint 检查、危险操作拦截、通知提醒等功能,逐步完善你的配置
- 查阅完整事件清单 — 除了文中提到的 5 个事件,Git 还提供了 30 余个事件,等待你进一步探索
参考链接
- 自动化工作流:Claude Code Hooks — 事件类型与配置结构详解
- 2026年3月版Claude Code Hooks完整指南 — 事件、处理器与退出代码机制
- 使用Claude Code Hooks实现自动化操作 — 实战配置范例
- Claude Code中文教程第24章:hooks — 面向入门的中文讲解
评论区 (3)
发表评论
共有 3 条评论
这个`rm -rf`防护的比喻简直说到我心坎里去了,每次看到AI生成那条命令都得先默念三遍"别手抖"。hooks自动格式化确实能省不少事,以前老忘记跑lint,现在终于不用事后补救了。
之前一直用CLAUDE.md加软性提示,结果经常漏掉格式化步骤。看了这个hooks确定性执行的对比,果断去配了PostToolUse的prettier,自动跑起来的感觉真爽。
刚按文章把prettier hook配上了,真的5分钟搞定!以前每次手动跑格式化烦死了,现在改了文件自动美颜,可操作性满分,就差把测试也挂上去了。