Skip to content
Agentic Control Plane

The Codex CLI control model, explained

Codex CLI’s control story used to be easy to summarize: strong sandbox, coarse approvals, no extension surface. That summary is now wrong in every clause. Through spring and summer 2026 OpenAI shipped a full hooks system (on by default, Claude Code-compatible), 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, and several widely-repeated facts about Codex are stale; we flag each. Current to 0.147.

This page covers Codex CLI’s own controls. For wiring 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 — the default pairing in the standard “Auto” preset with a workspace-write sandbox), or never. Stale-fact flag #1: on-failure was removed in 0.143 — a lot of 2025-era writeups still list it. The /approvals slash command is likewise gone, replaced by /permissions.

Approval answers include a design we’d like others to copy: approved_with_amendment — approve and persist a prefix rule to ~/.codex/rules/default.rules, so the approval becomes reviewable standing policy instead of invisible session memory. Enterprises can constrain what those rules may say (managed prefix rules can only prompt or forbid, never auto-allow).

The Guardian (0.147) is the headline: --approve-for-me (honest alias: --not-so-yolo) routes sandbox escalations, blocked-network requests, and side-effecting calls to a reviewer agent that checks for exfiltration, credential probing, persistence, and destruction. Critical findings deny outright; high-risk ones escalate to the human; reviewer failures fail closed. With Claude Code’s auto mode and Cursor’s Auto-review, that’s all three major harnesses replacing the human prompt with a model in the same season — the pattern and its gaps apply to all three.

The rules and profiles

Config is layered TOML: CLI flags → project .codex/config.toml (trusted projects only — untrusted projects skip all .codex/ layers, and 0.147 requires explicit trust for unfamiliar ones) → profile file → ~/.codex/config.toml → system → managed. Stale-fact flag #2: profiles are now separate files selected with --profile; [profiles.x] blocks inside config.toml are rejected since 0.134.

Permission profiles (beta) are the new fine-grained layer: named profiles with filesystem path→read|write|deny maps (deny beats write beats read; glob deny-reads like "**/*.env" = "deny") and per-domain network allow/deny — declarative resource policy rather than command patterns.

For command patterns, the exec-policy docs deserve credit for stating the limits precisely: compound bash -lc scripts are only split into rule-checkable subcommands for linear &&/||/;/| chains of plain words — redirections, command substitution, env-var assignments, wildcards, or control flow disable splitting entirely, and the rule matches the whole blob or nothing. That’s the honest version of the caveat every string-matching permission system carries.

Enterprise: requirements.toml (filesystem, MDM, or cloud-delivered from the ChatGPT workspace) sets hard constraints — which approval policies, sandbox modes, reviewers, and permission profiles are even selectable, network allowlists, and allow_managed_hooks_only. This is real fleet policy — for this one harness.

The sandbox

Three modes: read-only, workspace-write (network off inside it by default), danger-full-access. Subprocesses inherit the boundary. Platform mechanics — both stale-fact flags: Linux is now bubblewrap + seccomp with Landlock demoted to fallback, and Windows has a native sandbox as the default (low-privilege sandbox users, ACLs, firewall rules; elevated and unelevated variants) rather than “use WSL.” The old codex debug seatbelt/landlock subcommands are gone; codex sandbox runs arbitrary commands under the policy, which is a genuinely useful way to test what your profile allows before an agent finds out for you.

The hooks — no longer a footnote

Stale-fact flag #3, and the biggest one: Codex now ships a full hooks system, enabled by default. Events include PreToolUse, PermissionRequest, PostToolUse, compaction, prompt-submit, and session/subagent lifecycle. PreToolUse can deny (permissionDecision: "deny") or allow with rewritten input; any denying PermissionRequest hook wins; exit code 2 blocks. The schema is deliberately Claude Code-compatible, and codex /import (0.145) migrates Claude Code and Cursor hooks, settings, and MCP servers wholesale — the strongest evidence yet that the PreToolUse contract is becoming the ecosystem’s POSIX.

Trust mechanics are thought through: non-managed hooks require a one-time interactive review (hash-recorded, re-prompted on change), project hooks only load from trusted projects, and enterprises can ignore everything non-managed. And the docs include the sentence every hooks page should: hooks are “a useful guardrail, not a complete enforcement boundary.”

The record

Session rollouts as JSONL under $CODEX_HOME/sessions/ with a local state DB, resume/fork/archive, and opt-in OTel. Deliberate anti-records exist too: codex exec --ephemeral skips persistence, history.persistence = "none", and codex delete is permanent — fine for privacy, worth knowing when you’re reasoning about what evidence will exist later. No independent decision ledger; the rollout is the run’s own account.

Escape hatches and the empty chair

The hatches are explicit and tiered: --sandbox danger-full-access (drops the boundary, keeps approvals), --yolo (drops both), --approve-for-me (keeps the sandbox, delegates approvals to the Guardian), --dangerously-bypass-hook-trust (one invocation’s hook review). --full-auto was deprecated and removed from codex exec in 0.147.

Headless, Codex gets the empty chair right: codex exec defaults to a read-only sandbox and never prompts — blocked actions fail back to the model as errors it can adapt to. Every would-be ask resolves to deny-and-continue, which is exactly what the empty-chair test asks for. The risk profile is therefore concentrated in the flags: an unattended invocation is one --yolo in a cron job away from no controls at all, and nothing records that the flag was set.

Where the native model ends

Codex’s 2026 arc is the fastest control-surface improvement of any harness — from coarse approvals to profiles, Guardian, native hooks, and fleet constraints in about six months. The structural edges that remain:

  • Reviewer opacity. The Guardian’s verdicts, like every classifier gate, are judgment without a queryable rationale trail. Fail-closed is the right default; explainability isn’t there yet.
  • Per-harness fleet policy. requirements.toml is real enterprise control — for Codex. The same constraints don’t exist for the other harnesses on the same laptops.
  • The record is the run’s own, local, and deliberately deletable.
  • String rules stop at the documented line. The exec-policy splitting rules are honest about exactly where pattern matching gives up; past that line, enforcement has to live in the sandbox, a profile, or a hook.

The composition: keep the sandbox (it’s excellent), keep exec’s deny-and-continue posture, and put workspace policy on the hook seam — which, now that Codex speaks the Claude Code hook contract natively, is the same seam we already stand on everywhere else. Our integration carries the same rules across Codex, Claude Code, and the rest, with every decision — including which escape-hatch flags a session ran under — in a ledger off the machine.