The Codex CLI control model, explained
Codex CLI used to be easy to summarize: strong sandbox, coarse approvals, no way to extend it. That summary is now wrong on every point. Through spring and summer 2026 OpenAI shipped a full hooks system (on by default, compatible with Claude Code’s), fine-grained permission profiles, an enterprise constraints file, a native Windows sandbox, and in 0.147 a reviewer agent that approves on your behalf.
This page is the current reference. Several widely repeated facts about Codex are out of date, and we flag each one. Current to 0.147.
This page covers Codex CLI’s own controls. To wire ACP into Codex, see the install guide.
Approvals: three policies and a Guardian
The approval policy is one of:
untrusted: prompt for anything not known-safe.on-request: the agent escalates when it needs more than its sandbox allows. This is the default pairing in the standard “Auto” preset with a workspace-write sandbox.never: no prompts.
Out-of-date fact #1: on-failure was removed in 0.143. Many 2025 writeups still list it. The /approvals slash command is gone too, replaced by /permissions.
Approval answers include a design we’d like others to copy: approved_with_amendment. It approves the call and saves a prefix rule to ~/.codex/rules/default.rules, so the approval becomes standing policy you can review instead of invisible session memory. Enterprises can limit what those rules say: managed prefix rules can only prompt or forbid, never auto-allow.
The Guardian (0.147) is the big addition. --approve-for-me (alias: --not-so-yolo) sends sandbox escalations, blocked-network requests, and side-effecting calls to a reviewer agent. It checks for exfiltration, credential probing, persistence, and destruction. Critical findings are denied outright, high-risk ones go to the human, and if the reviewer itself fails, the call is denied.
With Claude Code’s auto mode and Cursor’s Auto-review, all three major harnesses now put a model where the human prompt used to be. The pattern and its gaps apply to all three.
The rules and profiles
Config is layered TOML, from highest to lowest: CLI flags, project .codex/config.toml (trusted projects only: untrusted projects skip all .codex/ layers, and 0.147 requires explicit trust for unfamiliar ones), a profile file, ~/.codex/config.toml, system, managed.
Out-of-date fact #2: profiles are now separate files selected with --profile. [profiles.x] blocks inside config.toml have been rejected since 0.134.
Permission profiles (beta) are the new fine-grained layer. A named profile maps filesystem paths to read, write or deny (deny beats write beats read, and globs work, such as "**/*.env" = "deny") and sets per-domain network allow and deny. It is declarative resource policy instead of command patterns.
For command patterns, the exec-policy docs state the limits clearly. A compound bash -lc script is split into subcommands that rules can check only for linear &&, ||, ; and | chains of plain words. Redirections, command substitution, env-var assignments, wildcards, or control flow turn splitting off entirely. Then the rule matches the whole string or nothing. Every string-matching permission system has this limit, and Codex says so.
Enterprise: requirements.toml (from the filesystem, MDM, or the ChatGPT workspace) sets hard constraints. It controls which approval policies, sandbox modes, reviewers, and permission profiles can be selected, plus network allowlists and allow_managed_hooks_only. That is real fleet policy, for this one harness. It can carry ACP’s hook to every seat: see the Codex enterprise rollout.
The sandbox
Three modes: read-only, workspace-write (network off inside it by default), and danger-full-access. Subprocesses inherit the boundary.
Two more out-of-date facts. Linux is now bubblewrap plus seccomp, with Landlock as the fallback. Windows has a native sandbox as the default (low-privilege sandbox users, ACLs, firewall rules; elevated and unelevated variants) instead of “use WSL.” The old codex debug seatbelt and landlock subcommands are gone. codex sandbox runs any command under the policy, which is a good way to test what your profile allows before an agent finds out for you.
The hooks
Out-of-date fact #3, and the biggest: Codex ships a native hooks system, stable and on by default from 0.145.0. The earlier codex_hooks flag was off by default. It is now a deprecated alias that warns on launch.
Hooks have their own page. hooks.json, every event, the PreToolUse deny and rewrite contract, exit code 2, trust review, async hooks, and troubleshooting: the Codex CLI hooks reference. That page is kept current as Codex moves; this one keeps only what the hooks mean for the control model.
Three things about hooks affect the control model more than the mechanics.
- Trust. A non-managed hook does not run until a person reviews and trusts its exact definition. The trust is recorded against the hook’s hash, so an edited hook goes back to review.
- Fleet.
requirements.tomlcan setallow_managed_hooks_only = true, which skips user, project, session, and plugin hooks and runs only managed ones. The enterprise rollout page has the file. - Limits. OpenAI’s docs call tool hooks “a useful guardrail, not a complete enforcement boundary.” Every hooks page should carry that sentence.
The record
Codex keeps session rollouts as JSONL under $CODEX_HOME/sessions/ with a local state DB, resume/fork/archive, and opt-in OTel. It also has ways to leave no record: codex exec --ephemeral skips persistence, history.persistence = "none", and codex delete is permanent. That suits privacy, but it matters when you ask what evidence will exist later. There is no independent decision ledger. The rollout is the run’s own account.
Escape hatches and the empty chair
The hatches are explicit and come in tiers:
--sandbox danger-full-accessdrops the boundary and keeps approvals.--yolodrops both.--approve-for-mekeeps the sandbox and hands approvals to the Guardian.--dangerously-bypass-hook-trustskips hook review for one invocation.
--full-auto was deprecated and removed from codex exec in 0.147.
Headless, Codex handles the empty chair well. codex exec defaults to a read-only sandbox and never prompts. A blocked action fails back to the model as an error it can adapt to, so every would-be ask becomes deny-and-continue. That is what the empty-chair test asks for.
The risk is in the flags. An unattended job is one --yolo in a cron entry away from no controls, and Codex keeps no separate record that the flag was set.
Where the native model ends
In about six months Codex went from coarse approvals to profiles, the Guardian, native hooks, and fleet constraints. The gaps that remain:
- Reviewer opacity. Like any classifier gate, the Guardian gives verdicts without a queryable rationale trail. Failing closed is the right default, but you can’t ask it why.
- Per-harness fleet policy.
requirements.tomlis real enterprise control, for Codex only. The other harnesses on the same laptops have no equivalent, and each vendor’s channel carries a different file: what the four admin channels share. - The record is the run’s own, local, and deletable by design.
- String rules stop at the documented line. Past it, enforcement has to live in the sandbox, a profile, or a hook.
What we’d do: keep the sandbox, keep exec’s deny-and-continue posture, and put workspace policy on the hook seam. Codex now speaks the Claude Code hook contract, so it is the same seam we use on other harnesses.
Our integration carries the same workspace rules to Codex, with two limits you should know. Coverage is Bash today, with file edits through the MCP supplement. And Codex has no way to show an ask, so an ask is blocked with an approval link, which you approve on the console or by email before the call is retried.
Every decision goes to a ledger off the machine, along with the permission mode the session reported (codex exec reports bypass). The hook fails open if the gateway can’t be reached, unless you set ACP_FAIL_MODE=closed or put closed in ~/.acp/failmode on that machine.
Frequently asked questions
What are Codex CLI's approval modes?
Three approval policies as of 0.143: untrusted (prompt for anything not known-safe), on-request (the default pairing with the workspace-write sandbox, where the agent escalates when it needs more than the sandbox allows), and never. The old on-failure policy was removed in 0.143. Since 0.147 there’s also a Guardian reviewer: –approve-for-me routes escalations to a reviewer agent that checks for exfiltration, credential probing, persistence, and destruction. Critical findings deny, high-risk ones escalate to the human, and failures fail closed.
Does Codex CLI have hooks?
Yes. They are native, on by default since 0.145, with a schema deliberately compatible with Claude Code’s. The config file, the events, the deny and rewrite contract, trust review, and troubleshooting are all in the Codex CLI hooks reference at /blog/codex-cli-hooks-reference. This page covers the controls around the hooks: approval policies, the Guardian reviewer, permission profiles, the sandbox, and requirements.toml.
How does the Codex sandbox work on each platform?
Three modes: read-only, workspace-write (network off inside it by default), and danger-full-access. Seatbelt enforces them on macOS. Linux uses bubblewrap plus seccomp, with Landlock now the fallback. Windows has a native sandbox (low-privilege sandbox users with ACLs and firewall rules) that replaced the WSL recommendation. Subprocesses inherit the boundary.
What happens when Codex runs headless and something needs approval?
codex exec defaults to a read-only sandbox and never prompts. A blocked action fails back to the model as an error it can adapt to, so every would-be ask becomes deny-and-continue. That is the right unattended posture. The escape hatches are explicit: –sandbox danger-full-access, or –yolo to drop both sandbox and approvals.
Running Codex? One command adds a hook for shell, apply_patch and MCP calls. Each call is recorded, and a force-push, destructive SQL or curl | sh is blocked until you approve it on the console or from the email.
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
irm https://agenticcontrolplane.com/install.ps1 | iex
What the installer writes · Codex guide · free up to 5 agents