使用 Codex 处理 Git 提交、查看 Pull Request 或推送分支时,经常会遇到同一种打断:任务本身已经明确,命令也重复执行过很多次,但每次离开沙箱仍要重新确认。
Codex Rules 可以按命令前缀决定这类请求是自动允许、继续询问还是直接禁止。不过,Rules 不是简单的命令白名单。它只负责“命令级审批决策”,不会理解用户是否真的授权了这次提交,也不会替代 Sandbox、approval_policy 或 AGENTS.md。
如果想先横向了解 Claude Code、Codex 与 OpenCode 的权限模型,可以配合 AI 编程 CLI 的权限怎么配 一起阅读。本文只讨论 Codex Rules 的配置、验证与安全边界。
写在前面
这篇文章来自一次真实的配置过程。目标很简单:让 Codex 在已经获得用户明确授权后,可以顺畅完成下面这些常规操作,而不是每一步都再次弹出权限请求。
- 显式暂存指定文件
- 创建普通 Git 提交
- 推送
main或master - 使用
gh pr view、gh run view等命令读取 GitHub 状态
最初很容易把问题理解成“把这些命令都设为 allow 就行”。实际验证后会发现,prefix_rule 匹配的是参数前缀,而不是一条带结束边界的完整命令。规则写得过宽,尾随的 --force、--amend 或其他参数也可能一起被放行。
本文示例使用 codex-cli 0.144.1 验证。OpenAI 官方目前仍将 Rules 标记为实验性功能,后续版本可能调整语法或加载行为,正式使用前应再次核对 Codex Rules 官方文档。
先说结论
写 Codex Rules 时,建议先记住下面几条:
allow、prompt和forbidden控制的是命令申请在沙箱外执行时的处理方式。- Rules 不会扩大 Sandbox 的文件系统或网络权限,也不会替代
approval_policy。 pattern是参数列表的精确前缀,不是 Shell 字符串,也没有“匹配到命令结尾”的含义。match和not_match是规则加载时执行的内联测试,不是运行时的允许和拒绝列表。- 多条规则同时匹配时,最严格的结果生效:
forbidden > prompt > allow。 - 只读、作用明确的命令更适合
allow;写操作需要结合AGENTS.md、Skill 或包装脚本约束调用条件。 - 不要宽泛放行
bash、python、git、gh这类可以承载大量不同操作的命令前缀。
Rules 在 Codex 权限体系中的位置
Codex 本地权限不是由一份规则文件单独决定的,而是由多个层次共同形成边界。
| 控制层 | 解决的问题 | 常见配置 |
|---|---|---|
| Sandbox | 命令在技术上可以读写哪些路径、能否访问网络 | sandbox_mode = "workspace-write" |
| Approval policy | 哪些类型的操作需要暂停并申请批准 | approval_policy = "on-request" |
| Rules | 某个命令前缀离开沙箱时应允许、询问还是禁止 | prefix_rule(... decision = "allow") |
AGENTS.md / Skill | 什么条件下应该执行命令,以及执行前后要做哪些检查 | “用户明确要求后才能提交或推送” |
OpenAI 官方将 Sandbox 和 Approval policy 定义为两个协同工作的安全层:前者限制“技术上能做什么”,后者决定“什么时候需要询问”。Rules 则进一步处理命令级别的审批结果,详见 Agent approvals & security。
这里最容易忽略的是:Rules 不理解对话中的业务意图。
假设存在下面的规则:
| |
它表达的是:当 Codex 申请在沙箱外运行以这组参数开头的命令时,不再弹出批准请求。它并没有表达“只有用户刚刚说了推送才能执行”。
因此,更完整的职责划分应该是:
AGENTS.md规定“没有用户明确要求,不主动提交或推送”。- Git Skill 负责检查工作区、提交身份、待提交 diff 和上游状态。
- Rules 只负责在这些前置条件已经满足时减少重复批准。
justification 也只是可展示给用户的说明文字,不是 Codex 在运行时执行的条件判断。
创建 Rules 文件
用户级规则通常放在:
| |
也可以拆成多个职责更清晰的文件:
| |
项目级规则可以放在:
| |
Codex 会在启动时扫描活动配置层旁边的 rules/ 目录。项目级 .codex/ 配置层只有在项目被信任后才会加载;用户级和系统级配置仍可正常生效。配置层关系可以参考 Codex Config basics。
新增或修改 .rules 后,需要重新启动 Codex。通过 TUI 把命令加入允许列表时,Codex 默认会把生成的规则写入:
| |
.rules 使用 Starlark 语法。它看起来接近 Python,但规则引擎会以无副作用的方式执行,不允许规则代码随意读写文件或调用外部程序。
从一条最小规则开始
下面的规则表示:当 Codex 想在沙箱外执行 gh pr view 时,每次仍然询问用户。
| |
prefix_rule() 当前支持下面这些字段:
| 字段 | 是否必填 | 作用 |
|---|---|---|
pattern | 是 | 定义需要匹配的命令参数前缀 |
decision | 否 | 匹配后的决策,默认是 allow |
justification | 否 | 给人阅读的规则理由,可能显示在批准或拒绝信息中 |
match | 否 | 应该命中当前规则的测试命令 |
not_match | 否 | 不应该命中当前规则的测试命令 |
建议始终显式写出 decision。虽然它默认为 allow,但权限规则不适合依赖不明显的默认值。
allow、prompt 和 forbidden 的区别
| decision | 匹配后的行为 | 适用场景 |
|---|---|---|
allow | 允许命令在沙箱外执行,不再请求批准 | 风险边界清晰、参数稳定的重复操作 |
prompt | 每次匹配仍请求批准 | 有副作用、需要保留人工判断的命令 |
forbidden | 直接阻止,不再询问 | 明确不希望 Agent 执行的危险操作 |
例如,可以允许只读的仓库信息查询:
| |
对推送操作采用更保守的策略:
| |
明确禁止常见的破坏性恢复操作:
| |
如果一条命令同时命中多条规则,Codex 不按文件顺序选择最后一条,而是采用最严格的结果:
| |
因此,可以在已有 allow 旁边增加更具体的 prompt 或 forbidden。不过,这仍然受参数位置和前缀匹配能力限制,不能把它当成完整的命令语法解析器。
pattern 匹配的是参数前缀
执行下面的命令时:
| |
Codex 会按照类似 execvp(3) 的方式,把它理解为参数列表:
| |
因此,下面的规则可以匹配它:
| |
但参数位置发生变化后就不能匹配:
| |
因为它的前三个参数已经变成:
| |
pattern 中的嵌套列表表示某个参数位置可以选择多个字面值:
| |
它可以匹配:
| |
但不会匹配:
| |
尾随参数是最容易忽略的风险
前缀匹配不要求命令在 pattern 结束的位置终止。下面这条规则:
| |
不仅会命中:
| |
在 codex-cli 0.144.1 中,它也会命中:
| |
同样,下面的规则:
| |
会同时匹配:
| |
这说明 Rules 当前没有“只允许这些参数,而且命令必须在这里结束”的表达方式。not_match 也不能补上这个缺口,因为它只是规则加载测试,不参与运行时拒绝。
面对这种情况,可以根据风险要求选择三种方案:
- 接受前缀边界,并通过
AGENTS.md和 Git Skill 约束 Codex 只能在用户明确授权、完成预检后调用。 - 把带副作用的原生命令设为
prompt,保留最后一次人工确认。 - 编写参数受限的包装脚本,由脚本验证分支、参数和工作区状态,再只允许调用该脚本。
如果无法接受尾随参数被一并匹配,就不应该直接把原始 git push 或 git commit 前缀设为 allow。
match 和 not_match 只是内联测试
一条完整规则最好同时提供正常样例和反例:
| |
Codex 加载文件时会验证:
match中的命令必须命中当前规则。not_match中的命令不能命中当前规则。
如果测试与 pattern 冲突,规则文件会加载失败,从而尽早暴露配置错误。
需要注意,下面这种写法并不会在运行时禁止强推:
| |
它只验证“这条命令不会命中当前这一个 prefix_rule”。如果它命中了另一个 allow,或者没有匹配任何规则,后续仍由其他 Rules、审批策略和 Sandbox 决定。
使用 execpolicy check 验证规则
不要只靠肉眼审阅 .rules。Codex 提供了 execpolicy check,可以查看命令最终命中了哪些规则。
| |
匹配成功时,输出会包含最终决策、命中的前缀和 justification。例如:
| |
多个文件可以重复传入 --rules:
| |
每条规则至少应该测试:
- 最短的预期命令
- 带常用参数的预期命令
- 容易混淆的相邻子命令
- 参数位置发生变化的命令
- 在规则前缀后追加高风险参数的命令
没有匹配到规则不等于 forbidden。这只表示当前传入的 Rules 没有给出决策,实际执行时还会继续受其他配置层、审批策略和 Sandbox 影响。
Shell 包装与复合命令如何匹配
Agent 执行命令时,外层工具有时会把多个操作包装成:
| |
对于只包含普通单词,并使用 &&、||、; 或 | 连接的线性命令,Codex 会尝试拆分后逐个应用 Rules。上面的脚本会被分别检查为:
| |
整个调用采用最严格的决策。因此,即使 git add 是 allow,后面的命令仍可能让整体请求变成 prompt 或 forbidden。
如果脚本包含下面这些高级 Shell 特性,Codex 不会尝试拆分:
- 输出或输入重定向:
>、>>、< - 命令替换:
$(...)或反引号 - 环境变量赋值或展开
*、?等通配符if、for等控制流
这时 Rules 看到的可能只是:
| |
因此不要设置下面这种宽泛规则:
| |
它会让任意复杂 Shell 脚本都有机会绕过逐条命令确认。官方对拆分条件和保守回退行为有更完整的说明,可以参考 Shell wrappers and compound commands。
实际案例:GitHub CLI 只读规则
只读、子命令明确的 GitHub CLI 操作比较适合自动允许:
| |
不建议直接允许:
| |
因为 gh 除了读取信息,还可以创建、合并、关闭、删除、触发工作流,甚至通过 gh api 发起自定义 API 请求。
实际案例:Git 提交流程怎样取舍
Git 写操作比 GitHub 只读查询更难定义安全边界。下面是一种以效率为优先的配置:
| |
它能显著减少常规提交流程中的重复确认,但 Rules 本身无法保证这些文字条件真的成立,而且还存在尾随参数问题。因此只有同时满足下面的约束时,才适合采用这种配置:
AGENTS.md明确规定不主动提交和推送。- Git Skill 要求先检查工作区、提交内容、作者邮箱和上游状态。
- Skill 使用显式文件路径暂存,不使用
git add .或git add -A。 - 不自动
--amend、重写历史或强推。 - 用户理解 Rules 是对 Agent 工作流的信任,不是命令级的绝对隔离。
如果更看重严格边界,可以把 commit 和 push 改为 prompt,或者只允许一个经过参数校验的包装脚本。
常见的破坏性操作可以保留为 forbidden,但要知道前缀规则很难覆盖所有参数排列:
| |
不要直接使用:
| |
否则普通查询、提交、配置修改、历史重写和强推都会落入同一个宽泛规则。
哪些命令不适合整类 allow
下面这些前缀能够承载任意代码、复杂脚本或大量外部副作用,通常不应该只按第一个参数自动允许:
| |
这不是说它们永远不能配置,而是应该继续细分到稳定的子命令和参数位置。例如允许 gh repo view,而不是允许整个 gh;允许固定的检查脚本,而不是允许整个 python。
把 Rules 同步到另一台电脑
用户级 Rules 默认位于 ~/.codex/rules/,不适合直接把整个 ~/.codex 加入版本控制,因为其中还可能包含认证、日志、历史和状态数据库。
一种更清晰的做法是建立自己的私有配置仓库。下面使用 agent-toolkit 作为本地目录示意,它不是一个可供读者直接克隆的公开模板仓库:
| |
再从 Codex 的实际加载目录创建软链接:
| |
先在自己使用的 Git 托管平台创建私有仓库,再在另一台已经配置访问权限的电脑上克隆并运行安装器:
| |
这里的仓库地址、目录结构和 install.py 都只是实现思路。读者需要根据自己的 Codex Rules、Skills 和 Claude Code 配置编写对应的私有仓库与安装脚本,不能假设存在一个公开的 agent-toolkit 项目可以直接安装。
这样可以同时获得:
- Git 版本历史和代码审阅
- Codex 与 Claude Code 共用的 Skills
- Codex 专属 Rules
- 冲突检测和可重复安装
- 多电脑一致的目录结构
即使仓库是私有的,也只应保存规则、Skill、脚本和不含敏感信息的说明,不应提交 Token、Cookie、认证文件或运行时状态。私有仓库能降低意外公开的概率,但不能替代凭证管理和提交前检查。
常见误区
把 not_match 当成 deny
not_match 只验证当前规则不应该命中某条命令。真正阻止命令必须使用 decision = "forbidden",或者依靠审批策略和 Sandbox。
认为 justification 会限制执行条件
justification = "仅在用户授权后推送" 不会让 Codex 自动检查用户是否说过这句话。语义条件应该写进 AGENTS.md 或 Skill。
认为 pattern 会匹配到命令结尾
["git", "push", "origin", "main"] 仍可能匹配后面带有额外参数的命令。为所有 allow 样例追加高风险参数进行测试,是 Rules 审阅中不可省略的一步。
认为没有匹配就是禁止
execpolicy check 没有返回匹配规则,只代表当前规则文件没有决策。实际执行还会继续经过其他配置层、审批策略和 Sandbox。
修改规则后不重启 Codex
Codex 在启动时扫描 Rules。修改文件后,应新开会话再观察真实审批行为,不能只依赖旧会话。
在未信任项目中依赖项目级规则
未信任项目会跳过项目内的 .codex/ 配置层,包括项目级 Rules。需要跨仓库稳定生效的个人规则更适合放在用户级配置层。
总结
Codex Rules 最适合解决“命令稳定、频繁执行、每次批准价值很低”的重复授权问题。它的优势是语法简单、可以内置测试,并能与用户级、项目级和团队配置层结合。
但 prefix_rule 只是参数前缀匹配器,不是完整的命令安全策略。allow 既不会理解用户意图,也不会自动拒绝尾随的危险参数。真正可靠的实践应该把职责拆开:
- Sandbox 限制命令技术上能访问的资源。
- Approval policy 决定哪些操作需要批准。
- Rules 减少稳定命令的重复询问。
AGENTS.md规定什么时候可以执行。- Skill 或包装脚本负责提交前检查和参数约束。
先用 codex execpolicy check 验证每一条正常与异常命令,再逐步扩大 allow 范围,比一次性放行整个工具更安全,也更容易维护。