本页解决什么问题
Rules 和 Hooks 都能把重复要求变成可执行配置,但职责不同:- **Rules(规则)**判断命令是否允许执行,以及是否需要审批。
- **Hooks(钩子)**在会话或工具生命周期的固定节点运行脚本。
codex --help、相关子命令帮助和官方文档。
本页包含:
.rules、prefix_rule、命令前缀和allow/prompt/forbidden;- 复合命令评估与
codex execpolicy check; - Hooks 的事件、
matcher、配置层级和信任; stdinJSON、stdoutJSON、stderr 和退出码;- 事前阻断、事后反馈、
Stop续轮的区别; - 格式化、日志、危险命令检查和会话上下文示例;
- 日志调试、失败策略、回滚和安全边界。
开始前检查
第一次实验建议使用临时 Git 仓库,不要在生产目录、主目录或包含客户资料的目录中测试:.env 内容或完整会话记录。命令 Hook 可能以当前用户权限运行,因此先读懂脚本,再在 /hooks 中信任项目配置。
第一部分:Rules
1. Rules 的职责
Rules 针对 Codex 准备执行的命令,按参数前缀匹配后给出决策:
Rules 适合稳定、可审查的政策,例如允许只读的
git status,对 gh pr merge 保留确认,或禁止 git push --force。Rules 不负责格式化、记录日志或读取会话上下文。
沙箱、审批和 Rules 是不同层次:沙箱限制文件系统和网络,审批决定何时暂停,Rules 对命令给出更细的政策。一个 allow 不能突破其他安全层。
2. 规则文件位置
常见用户级规则文件:.codex/ 范围内。用户级规则影响多个项目;项目级规则只服务一个仓库,但其加载受项目可信状态和版本实现影响。不要把个人路径、用户名、令牌或机器专属地址提交到项目规则。
Rules 属于实验性能力时,目录、文件名和语法可能变化。先运行本机帮助确认加载方式,并在改动后重启或重新加载 Codex。
3. prefix_rule 基本写法
下面的规则要求匹配 gh pr view 前缀时询问:
pattern 是按参数拆开的列表,不是任意文本搜索。它可以匹配:
match 和 not_match 写加载时的示例断言:
某些版本允许参数位置使用多个候选值。嵌套语法以当前 Rules 文档为准,优先选择窄前缀。
4. 如何选择决策
allow
只对你理解且副作用可控的窄命令使用:
bash、sh、脚本解释器或任意 git 前缀设置 allow。后续参数可能改变副作用。
prompt
适合访问网络、改变远端状态或目标需要人工确认的命令:
forbidden
适合组织或项目明确禁止的固定前缀:
allow 不应绕过更具体的 forbidden。冲突要用检查命令验证,不要靠真实危险操作试错。
5. 复合命令的边界
对于可安全解析的简单线性命令链,Codex 可以拆分子命令分别评估,并采用更严格的结果:git status 不代表后面的删除动作会被允许。Shell 包装也不能成为夹带危险命令的方式。
复杂 Shell 可能包含重定向、管道、命令替换、变量赋值、通配符、函数、循环或嵌套脚本:
6. 用 execpolicy check 预检
改完 Rules 后先检查:
- 应当
allow的正常命令; - 应当
prompt的外部写操作; - 应当
forbidden的危险命令; - 前缀顺序、短参数和复合命令边界;
- 命中的规则及其
justification。
git diff 只包含预期配置。
第二部分:Hooks
7. Hooks 的职责和生命周期
Hook 在固定事件发生时启动命令处理器。常见流程如下:
事件名称和字段可能变化。第一次使用只选一个事件,先确认触发,再增加其他处理器。
Pre、Post 和 Stop
PreToolUse在工具前运行,适合拒绝;PostToolUse在工具后运行,适合格式化、检查和反馈;PostToolUse的阻断不能撤销已写入、删除、上传或执行的结果;Stop的继续信号表示再处理一轮,不是回滚上一轮。
PreToolUse。想表达“执行完成后检查”,使用 PostToolUse。
8. 配置位置和信任
常见位置:
项目级
.codex/ 通常只在项目可信时加载。项目 Hook 会随仓库传播,但它本质上是可执行代码,不能因为它位于 Git 仓库就自动信任。用户级配置也会叠加影响当前项目。
同一层同时使用 hooks.json 和内联 [hooks] 可能合并并产生警告。每一层最好选择一种写法,避免重复注册和顺序误判。
配置后在 Codex 中打开:
--dangerously-bypass-hook-trust。只有在来源已由构建系统审查且运行环境隔离时才考虑使用,不能用它掩盖“钩子不触发”的问题。
9. hooks.json 结构
最小的 PostToolUse 配置:
// 注释。
内联 TOML 写法:
命令工作目录通常是会话
cwd。相对路径依赖错误 cwd 时会失败;项目脚本可从 Git 根计算绝对路径,但 Windows、非 Git 目录和特殊 Shell 必须单独测试。
10. matcher 匹配规则
工具事件中的 matcher 通常是工具名称的正则表达式,而不是 glob:
优先使用
^ 和 $。文件修改工具可能显示为 apply_patch、Edit 或 Write,以实际 stdin 的 tool_name 为准,不要凭按钮名称猜测。
不同事件的 matcher 目标可能不同:SessionStart 可能匹配 startup、resume、clear 或 compact;SubagentStop 可能匹配代理类型;Stop 和 UserPromptSubmit 没有工具名,不能按 Bash 规则理解。
PreToolUse 不是覆盖所有执行路径的强制边界。复杂 Shell、特殊执行器、网页工具或其他 MCP 路径可能不经过你的 matcher。高风险命令仍需沙箱和审批。
同一事件匹配多个 Hook 时,不要依赖配置顺序或假设串行执行。共享文件要有锁和幂等设计;需要严格顺序时合并到一个脚本中。
第三部分:Hook 协议
11. stdin:事件 JSON
Codex 将事件 JSON 写入脚本的标准输入:
Bash 的命令通常是
tool_input.command,其他工具结构可能不同。健壮的读取方式:
cwd,避免二次 Shell 解析。
12. stdout、stderr 和退出码
一般可按以下方式理解:
在
PreToolUse 或某些提示提交事件中,exit 2 配合 stderr 理由通常表示拒绝:
PostToolUse、Stop 或 SubagentStop 中,动作已经完成或到了结束节点,exit 2 不能撤销副作用,通常表示反馈给模型重看或继续一轮。
结构化拒绝示例:
decision: "block" 和 reason 等旧结构。不要把其他客户端的字段照抄进 Codex;按当前事件文档验证。
不要将调试文字写入要求 JSON 的 stdout。SessionStart 或 UserPromptSubmit 的纯文本在部分实现中会成为上下文,但 Stop、SubagentStop 可能要求严格 JSON。日志统一写 stderr 或独立文件。
13. 阻断的准确含义
“阻断”有三种不同情况:- 事前拒绝:工具尚未运行,
PreToolUse拒绝调用。 - 事后反馈:工具已运行,
PostToolUse把检查结果交回模型。 - 阻止结束:
Stop要求 Codex 再处理一轮。
- 在
PostToolUse打印“禁止执行”; - 在
PreToolUse只打印普通 stdout 文本; - 使用当前版本不支持的
continue: false; - 只拦 Bash 却假设其他工具路径也会被拦;
- 只依赖 Hook 而没有沙箱、审批和操作系统权限边界。
forbidden Rules;需要判断工作目录、完整 JSON 或多个条件时才增加 PreToolUse。
第四部分:三个示例
14. 示例一:PostToolUse 记录 Bash
脚本.codex/hooks/log_bash.py:
/hooks 中信任后,让 Codex 执行无害的 pwd 或 git status,检查日志是否生成。日志可能含路径或命令参数,不要提交到公共仓库,也不要默认记录完整提示词和工具输出。
15. 示例二:PostToolUse 自动格式化
格式化属于工具完成后的后处理:16. 示例三:PreToolUse 检查危险命令
固定前缀优先使用 Rules。需要脚本判断时可以这样演示:2,安全样例为 0。这个正则不是 Shell 解析器,不能覆盖变量、别名、脚本文件、命令替换和所有执行工具,不能宣传为完整防护。
第五部分:信任、调试与安全
17. 为什么 Hook 配了却不运行
命令 Hook 可读取工作区之外的文件、联网或删除内容,因此非托管项目 Hook 通常需要人工信任。首次配置的流程是:- 写脚本和配置;
- 重启或重新加载 Codex;
- 打开
/hooks; - 阅读实际命令、解释器、参数和路径;
- 确认来源和风险后信任;
- 用无害操作触发并检查日志。
- 是否调用远程脚本、未知二进制、PowerShell、
curl或wget; - 是否读取
.env、SSH、浏览器凭据或完整 transcript; - 是否联网上传 stdin、工作区或错误输出;
- 是否删除、覆盖、提权或修改系统设置;
- 相对路径是否可能在错误 cwd 中执行。
18. 排查顺序
Hook 不触发时按顺序检查:[features]是否关闭了 Hooks;- 配置文件位置、文件名和 JSON/TOML 语法;
- Codex 是否已重启;
/hooks是否显示、信任状态是否正常;- 事件名是否写对;
- matcher 是否匹配真实
tool_name; - 解释器、依赖、cwd 和脚本路径是否可用;
- timeout 是否太短;
- stdout 是否混入调试文字;
- 多个配置层是否重复加载同一 Hook。
19. 最小调试 Hook
先确认事件是否到达,再加入业务判断:0、缺失字段可处理、违规输入返回 2、错误进入 stderr、stdout 仍是合法协议。调试日志必须脱敏,不要写完整命令、提示词或秘密。
20. 安全边界、失败策略与回滚
Rules 和 Hooks 是纵深防御的一层,不是唯一安全边界:- 用沙箱限制文件和网络范围;
- 用审批策略控制出圈操作;
- 用 Rules 固定命令政策;
- 用 Hooks 做审计、检查和自动化;
- 对高风险任务使用容器、虚拟机和最小权限账户。
.. 越界、空路径和符号链接逃逸;网络请求需有超时和域名白名单。
每个 Hook 都要明确失败策略:
- 停止当前 Codex 会话;
- 保存错误输出和配置副本;
- 从
hooks.json或config.toml删除对应事件块; - 确认脚本没有被其他项目使用后再移除;
- 重启 Codex,在
/hooks确认状态; - 检查工作区、日志和外部系统的既有副作用。
21. 最终验收清单
- 已判断需求属于命令政策还是生命周期自动化。
- 配置放在正确的用户级或受信任项目级位置。
- Rules 的
pattern是窄的参数前缀,并测试了match/not_match。 - Rules 已用
codex execpolicy check验证正常、边界和危险命令。 - Hook 事件和 matcher 匹配实际输入,不是界面猜测。
- 脚本能从 stdin 解析 JSON,并处理缺失字段。
- stdout 保持协议格式,调试信息写 stderr 或脱敏日志。
-
PreToolUse使用当前版本支持的拒绝信号。 - 没有把
PostToolUse或Stop当成回滚机制。 - Hook 已在
/hooks中审阅和信任。 - 已用无害命令验证触发、放行、拒绝和失败路径。
- timeout 有限,脚本不会无限等待网络或交互。
-
git diff --check通过,日志、缓存、密钥和临时产物未进入提交。
小结
- Rules 用
.rules中的prefix_rule对命令前缀作allow、prompt、forbidden决策;更严格的结果优先,并可用execpolicy check预检。 - Hooks 用事件、
matcher和命令处理器连接生命周期;PreToolUse适合事前拒绝,PostToolUse适合事后检查,Stop的阻断通常表示继续一轮。 - 脚本从
stdin读取 JSON,用退出码表达粗粒度结果,用stdoutJSON 表达结构化控制;日志应放 stderr 或独立脱敏文件。 - 项目 Hook 是可执行代码,必须检查来源、权限、路径、网络和信任状态。
- 沙箱、审批、操作系统权限、隔离环境和人工审查仍是主要安全边界。
参考/codex/24-hooks.md、参考/codex/15-permissions.md、参考/codex/18-config.md。动态字段、事件和命令行为以本机 Codex 版本及官方文档为准。