Permissions and the human in the loop
Allow, ask and deny rules evaluated against every call; each question to the human adds their thinking time to the run.
Loading the animation…
Concept
A harness that runs whatever the model asks for is as trustworthy as the model. Most harnesses therefore check every tool call against rules before running it. A rule names a tool and a pattern for its argument (a path, or a command line) and says allow, ask or deny. On an ask, the run stops until a person answers.
The simulator checks deny rules first, then the mode, then ask rules, then allow rules, then the mode's default; so an allow rule can never carve an exception out of a deny rule. That is the order Claude Code documents: "Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome" (Claude Code, permissions, accessed 2026-10-07).
The task is the failing test again, plus some tidying the scripted model decides to do: rm -rf build, then git status. Two rules are on offer: deny rm *, and allow pytest* without asking. Then four modes:
- auto: anything no rule stops runs. Fastest (10.5 s); without the deny rule,
rm -rf buildsimply runs. - default: reads run, writes and shell commands ask. With the rules, the human is asked 2 times and the run takes 23 s; without them, 5 times and 42.1 s, and the human, who approves everything here, lets
rm -rf buildthrough. - ask every time: every call asks, even reads; 6 questions and 48.9 s, of which 38.4 s is waiting for the human.
- read-only: no writes and no shell. Nothing can go wrong, and nothing gets done: 5 calls are refused, including the fix itself. The scripted model still ends by claiming the fix worked; the harness knows the edit never ran. Real models do this too (the recorded ReAct trace in chapter 1 declares success after changing nothing), which is why a harness, not the model, should decide when a task is done.
Every question costs the human's attention as well as the run's time: the simulated human takes 3 to 9 seconds per answer, and a real one, switching back from other work, usually takes longer. A rule that allows the safe, frequent calls (here, running the tests) removes most of the questions without loosening anything that matters.
Maths
Splitting a run's time into the model's calls, the tools' runs and the waits for a person,
the first two hardly change between the modes; the last is a count times a typical wait. With questions and a mean wait , asking costs about ; here = 6 s, so the 6 questions of the strictest mode add about 38.4 s, several times the work itself. Reducing with precise allow rules is worth more than making the model faster.
Code
The decision for one call, cut from the vendored engine (harness.ts):
if (hits.has("deny")) return ["deny", hits.get("deny")!];
if (mode === "read_only" && !spec.read_only) return ["deny", "mode: read-only"];
if (mode === "ask") return ["ask", "mode: ask every time"];
if (hits.has("ask")) return ["ask", hits.get("ask")!];
if (hits.has("allow")) return ["allow", hits.get("allow")!];
Modes in the public harnesses
| Harness | Modes and controls (from their docs, accessed 2026-10-07) |
|---|---|
| Claude Code | permission modes default (asks on first use of each tool), acceptEdits, plan (explores without editing), auto (a classifier reviews actions instead of a person), dontAsk and bypassPermissions; allow, ask and deny rules such as Bash(rm *) (permissions) |
| Codex CLI | approval policies such as on-request and never, combined with sandbox modes read-only, workspace-write (the default) and danger-full-access (approvals and security) |
The two take different routes to the same end. Rules decide per call; a sandbox limits what any call can reach, whatever the rules say. Chapter 7 (hooks and sandboxing) draws that boundary. The threats themselves are covered in depth on the Security site: sandboxing and egress (its chapter 5) and humans in the loop (chapter 8), which measures what approval prompts actually buy.