用 Hooks 接入自动检查
基于官方 Codex Hooks 教程,讲清 hooks 能做什么、不能做什么,以及如何从低风险检查开始。
Hooks 是 Codex 的扩展机制:在会话、提示词提交、工具调用、权限请求、工具调用结束、turn 停止等节点运行脚本。它适合做自动检查、日志记录、策略提醒和团队规范执行。
Hook 不是让 Codex 更聪明的魔法。它是在工作流旁边插入脚本;脚本写错了,会打断体验、泄露信息,甚至放大权限风险。
Hooks
官方 Hooks 配置、事件、matcher 和输出格式。
Build plugins
需要分发生命周期配置时,再把 hook 放进 plugin。
Approvals
Hooks 不能替代 sandbox、approval 和代码审查。
它解决什么
flowchart LR
Prompt["UserPromptSubmit"] --> Check["敏感信息 / 范围检查"]
Tool["PreToolUse"] --> Policy["命令 / 路径策略"]
Result["PostToolUse"] --> Review["输出审查"]
Stop["Stop"] --> Continue["遗漏验证时继续"]
Hooks 适合做边界清楚的检查:
- 用户提交 prompt 前,检查是否误粘贴 API key。
- 工具运行前,检查危险命令或禁止路径。
- 权限请求时,把团队策略加到审批环节。
- 工具运行后,审查输出或补充上下文。
- turn 停止时,要求再跑一次验证。
Hooks 不适合做复杂业务逻辑,也不适合替代测试框架。它应该只做“是否允许继续”“是否补充上下文”“是否提示用户注意”的轻量决策。
启用和加载位置
Hooks 需要在 config.toml 打开 feature:
[features]
codex_hooks = trueCodex 会在 active config layers 旁边发现:
hooks.jsonconfig.toml里的 inline[hooks]
常见位置:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
项目本地 hooks 只会在项目 .codex/ layer 受信任时加载。一个层级里不要同时维护 hooks.json 和 inline hooks;官方会合并并给 warning,但新手排障会更难。
事件怎么选
UserPromptSubmit:用户输入发给模型前。适合检查敏感信息、任务范围、是否需要补充上下文。PreToolUse:工具执行前。适合拦截危险 shell、禁止路径、提醒确认。PermissionRequest:权限请求时。适合把团队审批策略放进请求前后。PostToolUse:工具执行后。适合审查命令输出或把额外上下文反馈给 Codex。Stop:turn 结束时。适合发现测试没跑、文档没同步时让 Codex 继续。SessionStart:session 启动、恢复或清空时加载上下文。
注意两个细节:
UserPromptSubmit和Stop当前不使用 matcher。PreToolUse、PermissionRequest、PostToolUse的 matcher 过滤 tool name,例如Bash、apply_patch或 MCP tool name。
第一版怎么做
第一版只做一个只读 hook,例如在 UserPromptSubmit 上检查 prompt 是否包含疑似 key。不修改文件,不运行复杂命令。
第二版再做 PreToolUse,只针对 Bash 或 apply_patch。matcher 要窄,不要全局匹配所有工具。
第三版再做 PostToolUse 或 Stop。这时你已经知道 hook 输入输出长什么样,也知道它对体验的影响。
不要一开始就把所有事件都挂上脚本。官方说明,同一个 event 上多个匹配 command hooks 会并发启动,一个 hook 不能阻止另一个匹配 hook 启动。
输出语义要写对
所有 command hook 都会从 stdin 收到一个 JSON 对象,常见字段包括 session id、当前 cwd、hook event name、模型、turn id 等。
UserPromptSubmit 可以输出额外 developer context,也可以 block prompt。
PostToolUse 发生在工具完成后,所以它不能撤销已经执行的 Bash 命令。它能把反馈传回 Codex,让后续处理从 hook 反馈继续。
Stop 的 block 不是拒绝本轮,而是让 Codex 继续,并把 reason 作为 continuation prompt。Stop 退出 0 时需要输出 JSON,plain text 对这个事件无效。
常见坑
- Hook 里做太多事:它应该短、小、可预测。
- matcher 太宽:每次操作都触发脚本,体验会变慢,也更容易误拦截。
- 忘记并发:多个匹配 hooks 会并发启动。
- 把 prompt、cwd、tool input、token 写进日志。
- 以为
PostToolUse能撤销命令。 - 忽略
Stop的 continuation 语义。 - 在不受信任项目里期待 project hook 生效。
验收清单
- 启动后没有 hooks 配置 warning。
- 目标事件确实触发。
- hook 能收到必要字段,但日志不保存敏感内容。
- 允许时不打断流程,拦截时给出人能理解的原因。
- 脚本异常、超时或输出非法 JSON 时,Codex 行为符合预期。
- 关闭 hook 后,相同任务能恢复正常,说明没有留下额外副作用。