Hooks 失败也能拦住:onFailure 设为 block
团队用 hooks 做门禁:危险命令要过脚本检查,敏感操作要打 HTTP 审批。问题是——钩子自己挂了怎么办?脚本路径错了、服务超时、进程异常退出,旧行为往往是:钩子没跑成,动作照样放行。门禁形同虚设。
CLI 2.1.295 给命令型和 HTTP hooks 加了 onFailure: "block":钩子启动失败、超时、或以非预期退出码结束时,会阻止目标动作,而不是默默放行。
默认放行为什么危险
常见事故链:
- 写了 PreToolUse 脚本,禁止未审批的
rm -rf或生产库写入; - 同事改了脚本路径,或审批服务临时 502;
- 钩子起不来或超时,旧逻辑把这当成「没意见」——命令直接执行。
你以为有闸门,实际闸门坏了还开着。CI、无人值守会话尤其危险:没人盯着终端里的钩子报错。
onFailure: "block" 的含义
配置后,下列情况都会拦住动作:
- 钩子根本启动不了(命令不存在、权限不够、配置写错);
- 钩子超时;
- 钩子以非预期退出码结束(具体哪些码算「非预期」,以你 hooks 配置约定为准)。
也就是说:「没检查到」不再等于「可以做」。检查链路不可用时,默认偏安全侧。
示意(字段名以你本机 hooks 配置为准,核心是加上失败即拦):
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "./scripts/check-dangerous-bash.sh",
"onFailure": "block"
}
]
}
]
}
}HTTP 审批类钩子同理:审批服务挂了,宁可先拦,再修服务,也不要静默通过。
适合开、不适合开
适合:
- 生产目录、密钥、支付相关操作的 PreToolUse;
- 必须经外部审批才能执行的工具调用;
- 组织托管设置里的强制门禁(和用户自选钩子不同,失败放行代价更高)。
要谨慎:
- 本地随便写的辅助钩子(格式化提示、统计)——失败就拦会打断正常工作流;
- 依赖不稳定外网的非关键钩子——网络抖一下就全停。
原则很简单:这道门坏了是否比误拦更可怕?是,就 block;否,保持默认或修好可靠性再开。
和 2.1.294 指令型 hooks 修复的关系
紧挨着的 2.1.294 修了另一类问题:写成自然语言指令的 prompt / agent hooks(例如「Block commands that…」)有时该拦却没拦住。那是「判断错了」;本次是「钩子挂了还放行」。两条线一起,门禁才靠谱:
- 指令写对了,真的会拦;
- 钩子挂了,也可以选择不放行。
同版本还加了终端 Program Status Protocol(OSC 7501):支持该协议的终端能显示 Claude Code 是在工作、等你,还是已结束。和 hooks 无关,但对长时间会话更直观。
小结
- 2.1.295 起,命令 / HTTP hooks 可设
onFailure: "block"。 - 启动失败、超时、异常退出时阻止动作,避免「门禁坏了却当通过」。
- 关键门禁建议打开;非关键辅助钩子按体验权衡。
- 升级后顺带确认 2.1.294+:指令型 prompt/agent hooks 的拦截判断也更准了。
用 claude --version 确认 ≥ 2.1.295,再给团队真正在意的门禁钩子加上 onFailure: "block",并做一次「故意弄坏脚本路径」的演练,看危险命令是否被拦住。