Claude Code Hooks 理论篇:理解事件驱动的自动化钩子
你可能已经用 CLAUDE.md 管理项目知识,用 Skills 封装可复用能力,用 MCP 接入外部工具。但有些事情,这三层都搞不定:
- 每次 Claude 编辑文件后,自动跑 lint
- 每次 Claude 要动
.env文件时,直接拦截 - 长时间任务跑完后,自动发通知到 Slack
你当然可以每次在对话里提醒它"改完记得跑 lint"“别碰 .env”,但说实话,你不可能每次都记得说,而且说了它也不一定每次都照做。
这些需求有个共同特点:它们不是"对话"能驱动的,而是需要在特定事件发生时自动触发。这就是 Hooks 的领地。

如图所示,左边是传统的"对话驱动"模式,每个自动化动作都需要你主动开口。右边是 Hooks 带来的"事件驱动"模式——规则设好之后,Claude 的操作会自动触发后续流程,你可以真正地从重复性监督中解放出来。
一、Hooks 是什么
当 Claude Code 中发生特定事件时,自动执行你指定的 shell 命令。
打个比方:你家门口装了一个智能门铃。有人按门铃(事件发生),摄像头自动拍照并推送到你手机(自动执行)。你不需要一直盯着门口,规则设好了,它自己会跑。
-
Hooks 的思路完全一样:
- 事件 = Claude Code 的操作(编辑文件、写文件、执行命令……)
- 自动执行 = 你写的脚本(检查代码、拦截操作、发通知……)
如果你用过 Git,应该对
pre-commit、post-commit这类钩子不陌生。Hooks 就是把对象从 Git 操作换成了 Claude Code 的操作,编辑文件、运行命令、发送通知、结束回复,这些都是可以挂钩子的事件。 -
更重要的是,Hook 的执行结果可以影响 Claude 的行为。比如你在 “编辑文件前” 挂了一个检查脚本,如果脚本返回非零退出码,这次编辑就会被阻止。Claude 会收到你的反馈,然后根据反馈调整行为。
-
这不是被动的日志记录,而是主动的流程控制。
二、支持哪些事件
Claude Code 目前支持五种 Hook 事件:
| 事件 | 触发时机 | 典型用途 |
|---|---|---|
| PreToolUse | Claude 调用工具之前 | 拦截危险操作、校验参数 例如检查要编辑的文件是不是敏感文件,如果是就拦截 |
| PostToolUse | Claude 调用工具之后 | 自动 lint、格式化、测试 编辑完文件后自动跑 lint |
| Notification | Claude 发送通知时 | 转发到 Slack、桌面通知 把通知转发到 Slack 或桌面弹窗 |
| Stop | Claude 结束回复时 | 自动化收尾工作 |
| SubagentStop | 子代理结束时 | 监控子任务完成状态 |
其中 PreToolUse 和 PostToolUse 是最常用的两个。因为 Claude Code 的大部分操作(编辑文件、写文件、执行命令)都是通过"工具调用"实现的,你可以精确地在这些操作前后插入自己的逻辑。编辑文件用的是 Edit 工具,写新文件用的是 Write 工具,跑命令用的是 Bash 工具。你可以针对特定工具设置 Hook,比如"只在 Claude 用 Edit 工具的时候触发"。
五种事件并非平级关系:PreToolUse 和 PostToolUse 围绕"工具执行"这条主线展开,是最精细的控制点;Notification 和 Stop 则是独立于具体工具的全局事件,适合做收尾和通知类的工作。
三、怎么配置
Hooks 的配置写在 settings.json 里,有两个位置可以放:
| 位置 | 作用域 | 适合放什么 |
|---|---|---|
~/.claude/settings.json | 全局,所有项目生效 | 安全类规则(如敏感文件保护) |
项目根目录/.claude/settings.json | 仅当前项目生效 | 项目特定的规则(如跑某个 linter) |
💡 如果两个地方都配了同一类 Hook,两边都会执行,不会冲突。
3.1 配置内容
配置的基本结构长这样:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "bash /path/to/your-script.sh"
}
]
}
]
}
}
3.2 内容说明
看起来层级有点深,但其实就回答了三个问题:
| 问题 | 对应字段 | 上面的例子 |
|---|---|---|
| 什么时候触发? | 外层的 key | PreToolUse(Claude 动手之前) |
| 对哪个工具触发? | matcher | "Edit"(只在编辑文件时) |
| 触发后执行什么? | command | 跑你写的 shell 脚本 |
matcher 可以不写,不写就表示"不管 Claude 用什么工具都触发"。
- 这个结构支持同一个事件挂多个 hook,也支持同一个事件对不同工具配不同的 hook。灵活度很高。
四、Hook 脚本是怎么工作的
这一节解释你的脚本和 Claude Code 之间是怎么"对话"的。如果你对 shell 脚本不太熟,先看个整体画面就好,细节可以等到实战篇再对照理解。
4.1 输入(Claude 怎么把信息传给你的脚本)
当 Hook 触发时,Claude Code 会往你的脚本里输入一段 JSON 数据,告诉你"我正在做什么"。比如 Claude 要编辑一个文件,你收到的数据大概长这样:
{
"tool_name": "Edit",
"tool_input": {
"file_path": "/path/to/file.ts",
"old_string": "...",
"new_string": "..."
}
}
你的脚本可以从这段 JSON 里提取信息(比如取出 file_path,看看是不是敏感文件),然后决定怎么处理。
4.2 你的脚本怎么把结果告诉 Claude
你的脚本有两种方式给 Claude 反馈:
-
第一种:打印文字。
脚本里
echo出来的内容会被 Claude 看到。比如你echo "这个文件不允许修改",Claude 会读到这句话并调整后续行为。 -
第二种:退出码。
这是最关键的控制信号:
- 脚本正常结束(退出码 0)= 放行,Claude 继续操作
- 脚本报错退出(退出码非 0)= 拦截,Claude 的操作会被取消
| PreToolUse(动手前) | PostToolUse(做完后) | |
|---|---|---|
| 退出码 0 | ✅ 允许操作 | ✅ 反馈给 Claude |
| 退出码非 0 | 🚫 阻止操作(文件不会被改) | ⚠️ 告诉 Claude “有问题”(但操作已经做了) |
注意区别:PreToolUse 的非零退出码会真正阻止操作(文件不会被修改),而 PostToolUse 的非零退出码只是告诉 Claude “后处理发现了问题”,因为操作已经执行了。
五、注意事项
5.1 执行时间要短
Hook 是同步执行的,在它跑完之前 Claude 会一直等着。一个跑 3 秒的 lint 没问题,一个跑 30 秒的全量测试就不合适了。长时间的检查应该放到其他地方(比如 CI)。
5.2 先手动测试
在把脚本配到 hooks 之前,先用管道模拟一下:
echo '{"tool_name":"Edit","tool_input":{"file_path":"test.ts"}}' | bash ~/scripts/guard-sensitive-files.sh
echo $?
确认脚本能正确解析 JSON、返回正确的退出码、输出合理的反馈信息,再写进配置。
5.3 其他
-
jq 是必备依赖。 几乎所有 Hook 脚本都需要解析 JSON 输入,确保你的环境里装了
jq。sudo apt install jq(Ubuntu)或brew install jq(macOS)。 -
配置合并。 如果全局和项目级都配了同一个事件的 hook,两边都会执行。安全类的 hook(如敏感文件保护)建议放全局配置,项目特定的(如特定 linter)放项目级配置。
六、Hooks 在扩展体系中的位置
回顾一下 Claude Code 的扩展体系,Hooks 补全了最后一块拼图:
| 层级 | 职责 | 触发方式 |
|---|---|---|
| CLAUDE.md | 知识:项目约定和规范 | 自动加载 |
| Skills | 能力:可复用的指令集 | 用户手动调用 |
| MCP | 集成:连接外部工具和服务 | Claude 按需调用 |
| Hooks | 自动化:事件驱动的流程控制 | 事件自动触发,无需人工干预 |
Hooks 是这四层里唯一能做到"无人值守"的。CLAUDE.md 提供知识但不执行动作,Skills 需要你主动触发,MCP 需要 Claude 决定调用,只有 Hooks 是真正的"设好就忘"。

四层扩展体系各司其职:知识、能力、集成、自动化,从被动到主动逐层递进。Hooks 站在最顶层,是唯一不需要人或 Claude 主动触发的那一层。
2万+



被折叠的 条评论
为什么被折叠?



