Skip to content

The two-axis model - approval policy is orthogonal to the sandbox

You’re about to start a refactor on budgetcli’s money handling - the original author stored some amounts as floats, and you want them converted to integer cents across half a dozen files. It’s the kind of job where stopping to approve every single edit is friction you’ll resent by the third file. So your instinct is to reach for some “let it run” setting. Before you do, you need to know what you’re actually turning up, because in Codex that instinct splits into two separate questions - and conflating them is how people end up either babysitting work that’s safe or walking away from work that isn’t.

Think about what could go wrong when an agent works on your financial data, and you’ll notice the risks aren’t all the same kind:

  • It could do something you didn’t expect - delete a file, run a destructive command, rewrite something it shouldn’t have. The defence against that is making it ask you first.
  • It could reach somewhere it shouldn’t - read your .env, write outside the project, phone home to some endpoint with your data. The defence against that is fencing where it can go, independent of whether it asks.

A single trust slider can’t separate these. “More autonomous” on a one-dial tool means both more-without-asking and more-reach, bolted together - so to stop being interrupted on a safe refactor, you’d also have to widen the blast radius. That’s a bad trade, and it’s the trade Codex refuses to make you. It gives you two dials.

Before the flags, feel the judgment itself. Here are the same two questions stripped of any tool’s vocabulary - set them for the cents refactor, then toggle each one on its own. Notice they move independently: exactly the property a single slider can’t encode, and the reason Codex ships two axes instead of one:

Two questions decide how much leash a task earns - neither of them is “how hard is it.” Set both for the work in front of you and read the rung it lands on.

If the agent’s worst single action went wrong, undoing it would take…
…and its consequences would reach
  1. Run free, no fencedisposable environments onlyNothing pauses it and nothing contains it. No combination on this dial lands here - it belongs only where the whole environment is disposable: a throwaway container, an already-isolated CI runner.
  2. Run free inside a fencethis taskNo prompts; the boundary does the protecting. The agent grinds end to end inside a sandbox, container, or scratch worktree, and you review the whole batch once at the end.
  3. Auto-apply edits, gate the rest
  4. Ask before acting
  5. Read & propose only

A mechanical rename across your own repo is the canonical case: the worst outcome is a git diff you throw away. Prompting on every one of twenty-four identical edits doesn’t add safety - it teaches you to stop reading prompts, which is where real risk starts. Let it run inside the fence and review the batch once.

The rung names are generic on purpose - every tool spells its own versions of them, and most let you set different rungs for different categories of action. The judgment underneath is the same two questions, asked per task, never answered once for all time.

Axis one - how much it can do without asking

Section titled “Axis one - how much it can do without asking”

The approval policy controls when Codex pauses to get your y/n before it acts. You set it with --ask-for-approval (short form -a), and it takes three values:

-a untrusted pause for anything not on a known-safe list
-a on-request let the agent decide when to ask; it pauses for the riskier moves
-a never never pause - run end to end without interrupting you

That’s the whole first axis: from “check with me constantly” to “don’t interrupt me at all.” Notice what it does not say anything about - where the agent is allowed to read, write, or connect. Approval is purely about the interruptions.

The sandbox sets the agent’s default reach: what the execution environment lets it touch without an approval-mediated exception. You set it with --sandbox (short form -s), and it takes three common values:

-s read-only can read files; edits and blocked commands need approval
-s workspace-write can read and write inside the project; outside access and network need approval
-s danger-full-access no fence at all - whole filesystem, full network

The sandbox is enforced by the execution environment, not by the agent’s good behaviour, but it is not automatically an absolute wall: an interactive approval can allow an operation beyond the default boundary. That’s why the two axes are still useful: the sandbox defines the default capability boundary, while approval decides whether an exceptional request is allowed. If you need a non-mutating unattended audit, pair read-only with approval_policy = "never" so no escalation can be approved.

Because the two are orthogonal, you pick one value from each, and the pair defines the session. The whole model in one grid - approval policy down the left, sandbox across the top, each cell the session that pairing gives you:

┌─────────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┐
│ approval │ read-only │ workspace-write │ danger-full-access │
├─────────────┼─────────────────────────┼─────────────────────────┼─────────────────────────┤
│ untrusted │ look, ask to act │ refactor, ask on risk │ (rarely sensible) │
├─────────────┼─────────────────────────┼─────────────────────────┼─────────────────────────┤
│ on-request │ read & propose │ the daily driver │ power use, asks on risk │
├─────────────┼─────────────────────────┼─────────────────────────┼─────────────────────────┤
│ never │ silent read-only │ hands-off in the fence │ no guardrails at all │
└─────────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┘

Read that grid as two questions answered separately. The cell that fits today’s money refactor is on-request × workspace-write: let the agent edit freely inside the project and stop for genuinely risky moves, including requests to go beyond the default boundary. You get a productive default and a checkpoint for exceptions. If the work must never escalate, use never with the tightest sandbox that still permits the task.

A couple of things worth nailing down now, because they trip people up:

  • The flags are not the whole UX. The CLI exposes the --ask-for-approval × --sandbox axes, and current Codex surfaces can also expose named or custom permission profiles. You may see references to suggest, auto-edit, or full-auto presets; treat those as surface/version-specific. The deprecated --full-auto flag should not be the basis of a new workflow.
  • The default is deliberately cautious. Launch Codex with neither flag and it picks a safe pairing for you - closer to the top-left of that grid than the bottom-right. You loosen on purpose, per task, not by accident.

You’ll often set both dials persistently rather than typing flags every time - the config keys are approval_policy and sandbox_mode in config.toml, and they take the same values. We’ll bundle them into a named profile in the last lesson. The authoritative list of values and their precise behaviour lives in the Codex config reference; pin to that rather than trusting a fixed memory, since the granular options grow over time.

Now take each axis one at a time. Start with the wall, because it’s the one protecting your money - the three sandbox levels in depth.