从0打造编码Agent 岔路 阅读 + 实验 ≈ 15 分钟 页内实验 ×1
A3 权限与审批:它要执行 rm -rf 怎么办? 岔路课

hook:规则之外的拦截点,能放宽规则吗?

hook 与规则
Claude Code 的 deny 规则带不了例外,官方给的出路是 hook。把六步求值序在浏览器里一步步走:hook 能在规则之前拦下调用,连 bypassPermissions 都挡得住;但它返回 allow 也越不过 deny 和 ask。CoreCoder、learn-claude-code、Pi 的 hook 是同一个方向。
❓

本课一问:上一课说 Claude Code 的 deny 规则带不了例外。规则之外还有一个拦截点叫 hook——它能不能用来「放宽」规则?

这一课先不碰:hook 的完整事件列表与配置格式(官方 hooks 文档很长,这里只看 PreToolUse 和权限的关系)。

从已有出发

主线第 2 课里,一份规则交给 Claude Code 时先查 deny 组。于是「拒绝所有 git 命令、但允许 git status」写不出来:Bash(git *) 放进 deny,更具体的 Bash(git status) 放进 allow 也救不回来。

从已有出发 · 累计数据流 点已学环节看它回答什么
每一轮循环都经过

贯穿任务里有一个真实需求能说明这件事:我们希望 agent 能跑 python -m unittest …,但不能跑别的 shell 命令。miniagent 靠 last-match 写成「先拒绝 bash、再放行 unittest」(第 2 课);在 Claude Code 里这种写法行不通,只能换个方向:整体放行 Bash,再用 hook 拦下不想要的。这也是官方文档给的做法。

先自己设计:让 hook 返回 allow 来开例外

直觉做法:deny 规则照写,再写一个 PreToolUse hook,遇到 git status 就返回 allow。

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案deny 规则照写,hook 对例外返回 allow
Claude Code 的六步求值序:hook 能放宽规则吗

组件加载中……(需要 JavaScript;所有裁决都在你的浏览器里由移植的原算法现算)

🎯

试三件事:① 默认情景下点「▶ 一步一步走」:hook 返回 allow,可调用在第 ② 步被 deny 规则拦下;② 把 hook 改成「退出码 2」,看它在第 ① 步就定案;③ 选「没有规则 + hook 返回 allow」:这时 hook 确实跳过了弹窗——它能「省掉问人」,但前提是没有 deny、ask 规则命中。

六步求值序

Agent SDK 文档把 Claude Code 的权限求值写成六步,前一步定案就不再往下走:

Claude Code 的权限求值序(Agent SDK · Configure permissions)
→ → → → →
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
hook 在最前面,所以它能「先拦」;deny 和 ask 紧跟在后面、先于模式和 allow,所以 hook 的 allow 越不过它们。官方原话:Hook decisions don't bypass permission rules。组件里的求值器依据官方文档实现,非源码移植。

这个顺序说明了 hook 的定位 :它是规则之外的一道额外的闸,能让更多调用被拦下,不能让规则已经拦下或要求询问的调用通过。这就保住了第 2 课里 deny 优先的承诺——包括组织在托管设置里写的 deny。

其他几家的 hook:同一个方向

harnesshook 在哪里能拦吗能放宽规则吗
CoreCoder v0.7.0PreToolUse 在同意层之前跑(agent.py:97)能:退出码 2,stderr 作为理由回填给模型(hooks.py:43-45)不能:hook 没有 allow 这种输出;PostToolUse 只观察(agent.py:133-136)
learn-claude-code s04第 3 章的三道闸整个搬进一个 PreToolUse hook(s04_hooks/code.py:153-154)能权限本身就是 hook,不存在「放宽规则」
PibeforeToolCall 挂载点(agent-loop.ts:619-647)能:返回 block,被拦的调用变成一条错误 tool resultPi 核心没有规则;它的 34 行 permission-gate 本身就是一个 hook 扩展

learn-claude-code 的 README 把这件事写成一句口号:「Hook around the loop, never rewrite the loop」(README.md:215)——在循环外面挂拦截点,不改循环本身。

有一处值得对照第 4 课:CoreCoder 的 hook 出错或卡住时直接跳过(hooks.py:10-11,「hooks assist the loop, they never get to kill it」),也就是 fail open;而 Codex 的审批者出任何故障都不放行。两者都有道理:hook 是用户写的辅助脚本,不该因为它崩了就卡死整个 agent;审批者是安全措施,故障时放行就等于没有它。

⚠

常见误解:「PreToolUse hook 返回 allow,就能绕过 deny 规则。」

不能。Claude Code 在 hook 之后照样求值 deny 和 ask 规则;hook 能做的是更早地拦(退出码 2 连 bypassPermissions 都挡得住),以及在没有规则命中时省掉一次弹窗。

权限设计的演进:每一代都被上一代的某个真数字逼出来
  1. Pi 核心、bypassPermissions、CoreCoder --yes
    解决了零打断,模型想跑什么马上跑。
    卡在L1 的 6 条本意危险的构造命令(含 rm -rf /)会全部直接执行。
  2. lcc s01 / s03、CoreCoder bash 正则、Pi permission-gate
    解决了把已知危险的写法挡在执行之前,代码只有几行。
    卡在lcc s03 三道闸(pin 源码实跑):6 条危险命令里漏拦 4 条,5 条日常命令里误拦 2 条(cat sudoku_solver.py 因含子串 sudo 被拒)。
  3. 第一代 每次都问人
    CoreCoder 交互模式、Claude Code Manual、lcc s03 的第三道闸
    解决了判断交给人,规则写不全也不怕。
    卡在我们 26 次真实运行的 139 次工具调用,在 CoreCoder 交互模式下有 74 次要停下来问(53%);Anthropic 自报用户批准了约 93% 的弹窗——问多了,人就不看了。
  4. 第二代 规则匹配:allow / ask / deny 你在这里
    Claude Code(deny → ask → allow)、OpenCode(last-match)、Codex(最严格者胜)
    解决了把常见的放行和拒绝写成规则,只有规则没覆盖的才问人。
    卡在同一份规则换一种求值语义可能换一个答案:同一份 rules-standard.json 改用 first-match,真实运行 pd-firstmatch-s1 里模型的 python -m unittest -v test_dateparse.py 被规则 #8 拒掉。
  5. Claude Code auto、Codex Auto-review(代码名 Guardian)、Hermes smart
    解决了只读直放、项目内编辑免审,其余交给另一个模型判断;弹窗接近清零。
    卡在Anthropic 自报:auto 分类器在真实越权动作上仍有 17% 漏判(n = 52),官方原话「does not guarantee safety」。
  6. 下一章 与 OS 沙箱分层
    Claude Code sandbox、Codex Seatbelt / bubblewrap
    解决了规则管「允许调用什么」,沙箱管「调用之后能碰到什么」。
    卡在L1 的 python3 -c "import shutil; shutil.rmtree(…)" 在四个黑名单里被 4 个全部放行;规则看不见脚本在运行时做什么 → A4。

数字口径:黑名单与「每次都问」由原实现在 pin 源码上实跑(a03-permission-fixtures.json,2026-09-26);真实运行 = 本课程项目 miniagent 用 Qwen/Qwen3-8B-MLX-4bit 本机录制;93% 与 17% 为 Anthropic 官方自报。

证据三问

问本课的回答
① 它解决什么问题?规则写不出的精细判断(例外、看命令全文、看参数)交给用户自己的代码
② 为什么只能收紧?hook 排在 deny、ask 之前,而它的 allow 不跳过这两步:任何 hook 输出都不会让 deny 规则失效
③ 实践上?Claude Code、CoreCoder、lcc、Pi 的 hook 都只能拦不能放;官方推荐的「allow 整体 + hook 收紧」正是利用这一点

一句话

📌

hook 只能收紧、不能放宽:它在规则之前拦得住一切,却放不过规则已经拒绝或要求询问的调用。

🚦

回到主线:第 3 课:每个调用都问人,人会怎样?

下一个缺口

回到主线:规则再好,每个调用都要人点「允许」吗?hook 能省掉一部分弹窗,但前提是你为每一类调用写好了判断;没写到的,仍然落到「问人」。

你可能会问