工具 Hooks 与审批决策
区分运行前阻断、审批请求决策、运行后反馈,以及 code mode 中 Promise 的结果。
工具事件通过 matcher 正则匹配工具名。apply_patch 可匹配 Edit 或 Write,但载荷仍报告规范名 apply_patch。Bash 和 apply_patch 的输入使用 tool_input.command;其他本地工具和 MCP 使用自己的参数对象。
PreToolUse:执行前处理
输入包含 turn_id、tool_name、tool_use_id 与 tool_input。阻止已覆盖的工具调用可返回:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}也支持旧式 decision: "block" 加 reason,或 exit 2 并把原因写入 stderr。增加上下文可使用 hookSpecificOutput.additionalContext。
需要重写参数时,只能将 updatedInput 与 permissionDecision: "allow" 一起返回。Bash/apply_patch 的新输入必须包含字符串 command,其他工具使用完整替代参数对象。
permissionDecision: "ask"、旧式 decision: "approve"、continue: false、stopReason、suppressOutput 当前不受支持。返回这些字段会使 Hook 失败并报告错误,随后继续工具调用;不能用它们建立拒绝策略。
PermissionRequest:审批前决策
只在 Codex 即将请求审批时运行,无需审批的调用不会触发。输入包括 turn_id、tool_name、tool_input;某些输入还提供 description,但不能假定总存在。
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}behavior: "allow" 可允许请求。多个处理器中任何 deny 优先;没有 deny 时,allow 允许继续且不显示审批提示;没人做决定时回到正常审批流程。updatedInput、updatedPermissions、interrupt 为保留字段,当前使用会 fail closed,应避免返回。
PostToolUse:处理已经发生的结果
输入在工具字段外增加 tool_response;Bash 非零退出也会触发。可以注入 additionalContext,或用 decision: "block" 加 reason(也可 exit 2 + stderr)替换反馈。但它不能撤销已经执行的命令或外部副作用。
continue: false 停止对原工具结果的正常处理,用 Hook 反馈继续模型流程。updatedMCPToolOutput 和 suppressOutput 尚不支持;Hook 会失败并继续正常结果处理。
Code mode 的嵌套调用
PreToolUse 阻断会在执行前让工具 Promise reject;重写则用新参数执行。PostToolUse block 或 exit 2 会在执行后让 Promise reject。PostToolUse 的 continue false 只替换模型可见反馈,不会让嵌套 Promise reject。
应分别测试拒绝、允许、无决定、超时和无效输出路径。一个 Hook 报错不等于对应动作已被成功拦截。