帖子说了什么
今天多条帖子都在说同一类事:Claude Code 的 PreToolUse / PermissionRequest hook 是另一个要被启动的程序。解释器缺失、命令被解析错、脚本路径删了,都可能让「护栏」根本没跑起来,而工具调用照样通过。@sukin_s 总结成一句:跑不起来的 hook,等于在说 Yes。@RealAlexandreAI 追问:谁会在每次改 hook 或升级后,故意弄坏一次再测拦截?@PromptToPR 给出可操作做法——准备一条 hook 必须拒绝 的命令,每次升级后跑一遍;同时用 /hooks 确认 hook 已注册、以及它来自哪份 settings。
对照官方说明
CHANGELOG v2.1.309 / v2.1.310 记录了 Windows 上多起「hook 没真正拦住」的修复(例如缺 Git Bash、仅引号路径、PowerShell 退出码等)。这说明问题不是「写了 deny 就万事大吉」,而是护栏进程有没有按你以为的方式启动并返回拒绝。官方 hooks 文档也强调:要用明确的退出约定(例如 exit 2)表达拦截;需要 fail-closed 时配置 onFailure: block(具体字段以你当前版本文档为准)。
本站已有一篇专讲 2.1.310 Windows 缺 Git Bash 时 hook 曾 fail-open 的升级说明;本文不重复那个 bug 细节,只补运维习惯:升级或改配置后,用冒烟测试证明护栏还活着。
你可以立刻做的几件事
- 写一条固定的「必须被拦」命令(例如故意触发你 PreToolUse 要拦的
rm/git push --force模式),记在团队手册里,升级后原样再跑。 - 跑完看结果:应看到拒绝 / 会话停住;若命令悄悄成功,先查解释器、路径、
/hooks列表,而不是改业务代码。 - 打开
/hooks:确认 hook 存在、来自用户级还是项目级 settings;避免「改了 A 文件、实际加载的是 B」。 - 对关键写操作配 fail-closed:钩子脚本缺失或崩溃时选择拦截,而不是放行(字段名以当前文档为准)。
- 升级后重复一次:尤其是跨 2.1.309 → 2.1.310 这类修 hook 启动路径的版本。
小结
策略写在 settings 里只是一半;另一半是证明它今天仍然会说 No。把冒烟测试绑在升级流程上,比事后才发现「钩子从没跑过」便宜得多。
来源
- @PromptToPR:升级后用必拦命令做 hook 冒烟测试,并查 /hooks
- @RealAlexandreAI:谁会在改 hook 后故意弄坏再测?
- 背景亦可参考 @sukin_s
- 官方对照:Claude Code CHANGELOG v2.1.309 / v2.1.310(Windows hooks)
