**适合谁读:**已经用 Codex 处理代码修改、测试和发布,希望把“禁止危险命令”“修改后必须检查”从口头提醒变成自动化机制的开发者。核心结论是:Hooks 适合在 Codex 生命周期的固定节点运行确定性脚本;最值得先做的是轻量、可审查的 PreToolUse 检查,但它是护栏,不是权限系统的替代品。

**本文更新:2026 年 7 月 31 日。**文中配置与行为依据当日 OpenAI 官方文档整理,不涉及套餐、价格或未公开功能。

为什么有了 AGENTS.md 还需要 Hooks

AGENTS.md 擅长告诉 Codex“这个项目应该怎么做”,例如测试命令、代码风格和交付要求。但说明依赖模型理解,遇到长任务、上下文压缩或多层规则时,仍可能漏掉机械性的检查。

Hooks 解决的是另一类问题:在会话开始、提交提示词、调用工具前后、上下文压缩或任务停止等固定节点,自动运行你自己的脚本。它适合处理可以被程序明确判断的规则,例如扫描命令中是否出现递归删除、提醒修改了生成文件、或在任务结束前检查关键测试是否执行。

一个实用分工是:业务判断和项目约定写进 AGENTS.md,可重复、确定性的检查交给 Hooks,真正的权限限制仍交给 Codex 沙箱、审批策略和操作系统权限。

先选配置范围

Codex 可以从 hooks.jsonconfig.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 会进入每次任务的关键路径,规则过宽可能让正常工作全部停摆。建议按三步启用:

  1. **只记录:**先让脚本把判定写入临时诊断结果,不拒绝工具调用。
  2. **只提醒:**通过 additionalContextsystemMessage 提醒 Codex,但保留正常流程。
  3. **再阻断:**只对证据充分、误报成本可控的规则返回 deny

每次修改 Hook 后,用一组固定样例回归:明显安全的只读命令、应该拒绝的危险命令、包含相似文字但不执行的命令,以及从仓库子目录启动 Codex 的情况。仓库脚本路径应从 Git 根目录解析,不要假设当前工作目录永远是项目根。

四个容易踩中的边界

第一,多个文件中匹配的 Hooks 会全部运行;同一事件的多个命令 Hook 还可能并发启动,不能依赖它们按顺序互相拦截。

第二,官方文档明确说明,部分专用工具路径可能不走默认 Hook 链路,托管的 Web Search 等工具也不在 PreToolUse/PostToolUse 覆盖范围内。因此 Hooks 是有价值的防线,但不是完整强制边界。

第三,Hook 输出会进入模型上下文,过长内容可能降低任务质量;超限内容还可能写入临时文件。输出应保持简短,并且绝不能打印令牌、密钥或完整环境变量。

第四,不要为了“方便”使用绕过 Hook 信任检查的启动选项作为日常配置。正常团队流程应审查脚本 Diff、重新确认变更后的 Hook,并保留可禁用与回滚路径。

一份可执行的落地清单

开始使用前,逐项确认:

  1. 规则能用程序稳定判断,而不是模糊业务意见;
  2. 用户级与项目级范围选择正确;
  3. 一个配置层只使用一种 Hooks 表达方式;
  4. 脚本路径从仓库根目录或绝对受控目录解析;
  5. PreToolUse 负责执行前阻断,PostToolUse 只做事后反馈;
  6. 允许、拒绝、误报和子目录场景都有测试;
  7. 输出不包含凭据、个人路径或完整环境信息;
  8. 沙箱、审批和系统权限仍然保留,没有被 Hooks 替代。

最好的第一个 Hook 往往不是“自动完成所有验收”,而是拦住团队最害怕、又最容易被明确识别的一类操作。把范围做窄、证据做实、误报做低,再逐步增加提醒和验证,才能让自动化护栏真正提高可靠性,而不是变成新的故障源。

参考资料