**适合谁读:**已经用 Codex 处理代码修改、测试和发布,希望把“禁止危险命令”“修改后必须检查”从口头提醒变成自动化机制的开发者。核心结论是:Hooks 适合在 Codex 生命周期的固定节点运行确定性脚本;最值得先做的是轻量、可审查的
PreToolUse检查,但它是护栏,不是权限系统的替代品。
**本文更新:2026 年 7 月 31 日。**文中配置与行为依据当日 OpenAI 官方文档整理,不涉及套餐、价格或未公开功能。
为什么有了 AGENTS.md 还需要 Hooks
AGENTS.md 擅长告诉 Codex“这个项目应该怎么做”,例如测试命令、代码风格和交付要求。但说明依赖模型理解,遇到长任务、上下文压缩或多层规则时,仍可能漏掉机械性的检查。
Hooks 解决的是另一类问题:在会话开始、提交提示词、调用工具前后、上下文压缩或任务停止等固定节点,自动运行你自己的脚本。它适合处理可以被程序明确判断的规则,例如扫描命令中是否出现递归删除、提醒修改了生成文件、或在任务结束前检查关键测试是否执行。
一个实用分工是:业务判断和项目约定写进 AGENTS.md,可重复、确定性的检查交给 Hooks,真正的权限限制仍交给 Codex 沙箱、审批策略和操作系统权限。
先选配置范围
Codex 可以从 hooks.json 或 config.toml 的 [hooks] 表读取 Hooks。常见位置有四个:
~/.codex/hooks.json
~/.codex/config.toml
<repo>/.codex/hooks.json
<repo>/.codex/config.toml个人跨项目规则放在用户级目录,仓库专属策略放在项目的 .codex/ 中。项目级 Hooks 只有在该配置层受信任时才会加载;非托管命令 Hook 在首次运行或定义变化后也需要重新审查。CLI 中可以用 /hooks 查看来源、信任或禁用具体 Hook。
同一层不要同时维护 hooks.json 和内联 [hooks]。Codex 会合并二者并给出警告,长期维护时很容易出现“以为只改了一处,实际两套规则都在跑”的问题。
一个最小的命令检查 Hook
下面用 PreToolUse 在 Bash 工具执行前调用检查脚本。配置只负责匹配与调度,判断逻辑放进可测试的 Python 文件:
{
"description": "Repository command guardrails",
"hooks": {
"PreToolUse": [
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/check_command.py\"",
"timeout": 10,
"statusMessage": "Checking command policy"
}
]
}
]
}
}Hook 从标准输入收到 JSON,其中包含事件名、工作目录、工具名和工具参数。检查脚本可以读取 tool_input.command,命中明确的禁止规则时返回拒绝决定:
#!/usr/bin/env python3
import json
import re
import sys
event = json.load(sys.stdin)
command = event.get("tool_input", {}).get("command", "")
blocked = [
r"(^|\s)rm\s+-rf\s+(/|~|\$HOME)(\s|$)",
r"(^|\s)git\s+reset\s+--hard(\s|$)",
]
if any(re.search(pattern, command) for pattern in blocked):
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Command blocked by repository policy."
}
}))这只是教学起点,不应把两个正则当成完整安全策略。真实脚本应为每条规则准备允许、拒绝和边界测试,并尽量判断结构化参数,避免简单字符串匹配被引号、换行或不同命令写法绕过。
PreToolUse 与 PostToolUse 不可互换
PreToolUse 在受支持的本地工具运行前触发,可以拒绝或改写调用;PostToolUse 在工具已经产生结果后触发,适合附加反馈、要求复查或把结果摘要补充给模型。后者不能撤销已经发生的文件修改、网络请求或命令副作用。
因此,高风险动作必须在执行前判断。执行后检查更适合这些场景:
- 命令非零退出时补充项目专属排查建议;
- 文件修改后提示运行格式化或目标测试;
- 检测输出是否出现凭据、个人路径或内部地址;
- 将生成文件变更标记为需要人工审查。
不要让 PostToolUse 自动执行大范围修复,更不要把“发现问题后提示模型”描述成阻止了原操作。
上线前先做影子运行
Hooks 会进入每次任务的关键路径,规则过宽可能让正常工作全部停摆。建议按三步启用:
- **只记录:**先让脚本把判定写入临时诊断结果,不拒绝工具调用。
- **只提醒:**通过
additionalContext或systemMessage提醒 Codex,但保留正常流程。 - **再阻断:**只对证据充分、误报成本可控的规则返回
deny。
每次修改 Hook 后,用一组固定样例回归:明显安全的只读命令、应该拒绝的危险命令、包含相似文字但不执行的命令,以及从仓库子目录启动 Codex 的情况。仓库脚本路径应从 Git 根目录解析,不要假设当前工作目录永远是项目根。
四个容易踩中的边界
第一,多个文件中匹配的 Hooks 会全部运行;同一事件的多个命令 Hook 还可能并发启动,不能依赖它们按顺序互相拦截。
第二,官方文档明确说明,部分专用工具路径可能不走默认 Hook 链路,托管的 Web Search 等工具也不在 PreToolUse/PostToolUse 覆盖范围内。因此 Hooks 是有价值的防线,但不是完整强制边界。
第三,Hook 输出会进入模型上下文,过长内容可能降低任务质量;超限内容还可能写入临时文件。输出应保持简短,并且绝不能打印令牌、密钥或完整环境变量。
第四,不要为了“方便”使用绕过 Hook 信任检查的启动选项作为日常配置。正常团队流程应审查脚本 Diff、重新确认变更后的 Hook,并保留可禁用与回滚路径。
一份可执行的落地清单
开始使用前,逐项确认:
- 规则能用程序稳定判断,而不是模糊业务意见;
- 用户级与项目级范围选择正确;
- 一个配置层只使用一种 Hooks 表达方式;
- 脚本路径从仓库根目录或绝对受控目录解析;
PreToolUse负责执行前阻断,PostToolUse只做事后反馈;- 允许、拒绝、误报和子目录场景都有测试;
- 输出不包含凭据、个人路径或完整环境信息;
- 沙箱、审批和系统权限仍然保留,没有被 Hooks 替代。
最好的第一个 Hook 往往不是“自动完成所有验收”,而是拦住团队最害怕、又最容易被明确识别的一类操作。把范围做窄、证据做实、误报做低,再逐步增加提醒和验证,才能让自动化护栏真正提高可靠性,而不是变成新的故障源。