下午三点,你给 Claude Code 布置了一个大活——重构某个模块的架构链路。你预估它要跑个十来分钟,于是切到浏览器去查资料。
十分钟后你切回来,发现 Claude 在第二分钟就弹了个权限确认框:Allow this bash command? 崩了,它在等待你确认,干等了你八分钟。
你盯着屏幕的时候它不需要你,你一走开它就等你。这种错位每天会发生好几次——尤其当你同时在多个终端跑多个 Claude Code 会话的时候。
如果 Claude 等你的时候,能主动喊你一声呢?这就是 Hooks 要解决的问题。今天我们就从这个最实际的需求出发,搞懂 Claude Code 的 Hooks 机制,并且配出一个飞书/如流的通道通知。
一、Hooks 是什么
Hooks 是 Claude Code 在工具执行生命周期的固定节点上,允许你挂载自定义脚本的机制。可以在 Claude 动手之前做检查、执行后自动 lint、会话结束时发通知等。
配置位于 ~/.claude/settings.json 顶层字段 hooks,与 permissions 平级。
二、整体执行流程
Claude Code 每次调用工具都会经历一个固定的生命周期,Hooks 就是在这个生命周期的关键节点上插入你的自定义逻辑。

- 用户下达指令 — 你让 Claude 做事,它决定要调用某个工具(比如 Bash、Write)
- PreToolUse — 工具还没执行,你的脚本先跑。可以检查、记日志,甚至 exit 2 直接阻断(比如禁止 rm -rf)
- PermissionRequest — 如果工具需要权限决策(非预授权),触发此 hook。hook 可以做通知,也可以直接返回 allow/deny 决策替代用户确认
- 执行工具 — 用户确认放行后(或已预授权、或 hook 直接 allow),工具正常执行
- PostToolUse — 工具执行完了,你的脚本再跑。适合自动 lint、格式化
- Claude 回复 → Stop — Claude 生成回复后,Stop hook 触发。exit 0 会话结束,exit 2 产生 blocking error 传给模型,Claude 继续对话
- Notification(旁路) — 独立于主流程,只在用户空闲超过 6 秒后才触发,不是每次权限请求都触发,仅作补充通知
场景图:没有 Hook vs 有 Hook
配了 PermissionRequest Hook 后,Claude 需要权限确认时不再是"干等":

三、配置结构
三层嵌套:
hooks
└── 事件名(如 PreToolUse)
└── [] HookMatcher 数组
├── matcher: 匹配规则(可选,字符串模式匹配)
└── hooks: [] HookCommand 数组
Hook 的 4 种类型
HookCommand 是一个 discriminated union,通过 type 字段区分 4 种类型:
| 类型 | 说明 | 核心字段 |
|---|---|---|
| command | 执行 shell 命令 | command(shell 命令字符串) |
| prompt | 用 LLM 评估 | prompt(prompt 字符串,$ARGUMENTS 占位符) |
| http | POST JSON 到指定 URL | url(目标地址),headers(可选) |
| agent | 代理型验证器 | prompt(验证指令) |
所有类型共享的可选字段:
- if:权限规则语法过滤(如 "Bash(git *)"),只在匹配时运行
- timeout:超时(秒)
- statusMessage:自定义状态消息,显示在 spinner 中
- once:true 时只执行一次后自动移除
command 类型额外支持:
- async:true 时后台异步执行,不阻塞
- asyncRewake:异步执行,但 exit code 2 时唤醒模型
- shell:指定 shell 类型(bash/powershell)
四、事件类型(重点:别搞混 PermissionRequest 和 Notification)
Claude Code 源码中定义了 27 种 hook 事件,日常最常用的如下:
| 事件 | 触发时机 | 有 matcher | 阻断能力 |
|---|---|---|---|
| PreToolUse | 工具调用前 | 有(匹配工具名) | exit 2 可阻断 |
| PermissionRequest | 工具需要权限决策 | 有(匹配工具名) | JSON 输出可 allow/deny |
| PostToolUse | 工具执行成功后 | 有(匹配工具名) | exit 2 可反馈模型 |
| PostToolUseFailure | 工具执行失败后 | 有(匹配工具名) | exit 2 可反馈模型 |
| Stop | Claude 结束回复 | 无 | exit 2 / JSON 可让 Claude 继续 |
| Notification | Claude 发送系统通知 | 有(匹配 notification_type) | 无(即发即忘) |
| UserPromptSubmit | 用户提交 prompt | 无 | exit 2 可阻断 |
| SessionStart | 会话启动 | 有(匹配 source) | exit 2 可阻断 |
| SessionEnd | 会话结束 | 有(匹配 reason) | 无 |
PermissionRequest vs Notification
这是实际配置中踩过的坑,非常容易搞混:
| PermissionRequest | Notification (permission_prompt) | |
|---|---|---|
| 触发时机 | 工具需要权限决策时触发(包括弹确认框前、自动模式下的权限检查) | 用户空闲超过6 秒后,Claude 发系统通知时触发 |
| 触发频率 | 每次工具需要权限决策都触发 | 不确定,依赖于用户是否空闲超过阈值 |
| 本质 | 权限决策事件,hook 可以直接 allow/deny 替代用户操作 | Claude Code 的系统级通知(类似 OS 通知) |
| 适合做 | 每次权限决策时发 IM 提醒 | 补充性通知(锦上添花) |
苏米注:这个区分非常关键。我最初只配了 Notification,结果发现有时候收到通知、有时候收不到。排查后发现 Notification 只在用户空闲超过 6 秒后才触发。改用 PermissionRequest 后,每次权限决策都能稳定收到消息。想要"每次需要权限确认时收到飞书/如流消息",必须用 PermissionRequest,不能只用 Notification。
五、实战配置 — 飞书/如流通道通知
5.1 飞书自定义机器人
前置步骤:获取飞书 Webhook URL
- 打开飞书,进入你要接收通知的群聊
- 点击群设置(右上角 ...)→ 群机器人 → 添加机器人
- 选择「自定义机器人」,填写名称(如 "Claude Code 通知")
- 创建成功后复制 Webhook 地址(格式:https://open.feishu.cn/open-apis/bot/v2/hook/xxx)

飞书消息体格式:
{
"msg_type": "text",
"content": {
"text": "你的消息内容"
}
}
5.2 如流自定义机器人
前置步骤:获取如流 Webhook URL
- 打开如流,进入你要接收通知的企业群
- 点击群右上角「机器人图标」→ 添加机器人 → 创建机器人
- 填写机器人名称(如 "Claude Code 通知"),完成创建
- 创建成功后复制 Webhook 地址(格式:http://apiin.im.baidu.com/api/msg/groupmsgsend?access_token=xxx)

如流消息体格式:
{
"message": {
"body": [
{ "type": "TEXT", "content": "你的消息内容" }
]
}
}
5.3 完整 settings.json 配置
以下是 PermissionRequest + Notification + Stop 三个事件同时推送飞书和如流的完整配置:
{
"hooks": {
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "TOOL=$(cat | jq -r '.tool_name // \"unknown\"') && curl -s -X POST -H 'Content-Type: application/json' -d '{\"msg_type\":\"text\",\"content\":{\"text\":\"[Claude Code] 权限确认:'\"$TOOL\"' 需要你的批准\"}}' 'https://open.feishu.cn/open-apis/bot/v2/hook/你的飞书webhook' && curl -s -X POST 'http://apiin.im.baidu.com/api/msg/groupmsgsend?access_token=你的如流 token' -H 'Content-Type: application/json' -d '{\"message\":{\"body\":[{\"type\":\"TEXT\",\"content\":\"[Claude Code] 权限确认:'\"$TOOL\"' 需要你的批准\"}]}}'",
"async": true
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "MSG=$(cat | jq -r '.notification_type // \"通知\"') && curl -s -X POST -H 'Content-Type: application/json' -d '{\"msg_type\":\"text\",\"content\":{\"text\":\"[Claude Code 提醒] '\"$MSG\"': 需要你的注意\"}}' 'https://open.feishu.cn/open-apis/bot/v2/hook/你的飞书webhook' && curl -s -X POST 'http://apiin.im.baidu.com/api/msg/groupmsgsend?access_token=你的如流 token' -H 'Content-Type: application/json' -d '{\"message\":{\"body\":[{\"type\":\"TEXT\",\"content\":\"[Claude Code 提醒] '\"$MSG\"': 需要你的注意\"}]}}'",
"async": true
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST -H 'Content-Type: application/json' -d '{\"msg_type\":\"text\",\"content\":{\"text\":\"[Claude Code] 任务已完成,请查看结果\"}}' 'https://open.feishu.cn/open-apis/bot/v2/hook/你的飞书webhook' && curl -s -X POST 'http://apiin.im.baidu.com/api/msg/groupmsgsend?access_token=你的如流 token' -H 'Content-Type: application/json' -d '{\"message\":{\"body\":[{\"type\":\"TEXT\",\"content\":\"[Claude Code] 任务已完成,请查看结果\"}]}}'",
"async": true
}
]
}
]
}
}


5.4 关键参数说明
| 设计点 | 说明 |
|---|---|
| PermissionRequest(核心) | 每次弹权限确认框都触发,从 stdin 提取 tool_name 告诉你是哪个工具需要批准 |
| Notification(补充) | Claude 发系统通知时触发(如长时间等待后的提醒),作为补充通道 |
| Stop 事件 | Claude 完成一轮任务时触发,发送固定的"任务完成"消息 |
| 双通道并行 | 一条命令内用 && 串联飞书和如流的 curl,确保两个 IM 都收到 |
| async: true | 后台异步发送,不阻塞 Claude 的执行流程 |
5.5 验证方法
配置完成后,可以用 curl 手动测试 Webhook 是否连通:
# 测试飞书
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"msg_type":"text","content":{"text":"[Claude Code] Hook 测试:飞书通知已连通"}}' \
'https://open.feishu.cn/open-apis/bot/v2/hook/你的飞书webhook'
# 测试如流
curl -s -X POST \
'http://apiin.im.baidu.com/api/msg/groupmsgsend?access_token=你的如流 token' \
-H 'Content-Type: application/json' \
-d '{"message":{"body":[{"type":"TEXT","content":"[Claude Code] Hook 测试:如流通知已连通"}]}}'
成功时飞书返回 {"StatusCode":0,"StatusMessage":"success",...},如流返回 {"errcode":0,"errmsg":"ok",...}。
六、其他实用配置示例
写文件后自动 lint
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{ "type": "command", "command": "cd $CLAUDE_PROJECT_DIR && pnpm lint --fix", "timeout": 30 }]
}
]
}
}
阻断危险 Bash 命令
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "bash /path/to/guard.sh" }]
}
]
}
}
记录所有 Bash 命令到日志
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.command // empty' >> /tmp/claude-bash.log", "async": true }]
}
]
}
}
七、注意事项
- 工作区信任:hook 需要工作区处于受信任状态才执行
- 来源优先级:pluginSettings 数组合并(各层的 hook 都会执行),而非简单覆盖
- 超时控制:建议设置合理 timeout(单位秒),避免脚本卡住阻塞 Claude
- exit code 2 是核心机制:PreToolUse 用它阻断,Stop 用它让 Claude 继续,PostToolUse 用它反馈模型
- policySettings 特权:企业管理员可通过 disableAllHooks(禁用所有)或 allowManagedHooksOnly(仅允许管控 hooks)来限制用户自定义 hooks
总结
Claude Code 的 Hooks 机制是一个强大的扩展系统,通过在工具执行生命周期的关键节点插入自定义逻辑,可以实现权限通知、自动 lint、命令审计等功能。本文重点讲解了如何配置飞书和如流通知,解决 Claude 等待用户确认时"干等"的痛点。
苏米注:Hooks 最实用的场景就是权限通知。配置完成后,无论你在哪里,只要 Claude 需要确认权限,飞书/如流就会立即推送消息。这个配置我用了两周,效率提升非常明显——再也不用时不时切回终端检查 Claude 是不是在等我了。