Explore, with the pen taken away
Read only exploration: letting an agent look without letting it touch
Ask a coding agent to work out how your auth path reaches the database and it will read files, run greps, open a test, and quite possibly rewrite something on the way. The rewrite happens during the deciding, not during the doing. By the time you read the result, the repository has already moved and reviewing it has turned into archaeology.
Disclosure: I build Ordewell, and a read only envelope is how its planner works. The interesting part is not the flag. It is what the flag does and does not promise, and there is one failure mode in this area that is worse than having no read only mode at all.
Exploration is the phase that surprises you
A build request is bounded. You asked for rate limiting on the public route, so a competent agent touches the limiter and maybe the config. An exploration request is unbounded by nature: to say how auth reaches the database, the agent has to decide which files are relevant, and that decision is made by looking. Looking invites edits, because the cheapest way to test a hypothesis about a codebase is to change it.
Three things go wrong in that window. Unrelated files pick up changes that look like yours. The agent's own summary of the codebase becomes the thing you are reviewing, and you cannot tell which parts are findings and which are inventions. And if the session is long enough, the work it eventually does rests on edits it made to its own context on the way. None of those are problems of model quality. They are a permission problem.
What read only means in each CLI
Read only is not a property of a model. It is a property of a process, and every coding CLI spells it differently. In Ordewell a planning session is started with the strongest form each harness exposes:
- Claude Code: its
defaultpermission mode, with every tool request answered by Ordewell rather than by Claude Code, and the edit tools and the shell withheld in--disallowedTools(Edit,Write,MultiEdit,NotebookEdit,Bash,PowerShell, and Claude Code's own plan mode switches). The shell is withheld because Claude Code's plan mode turned out to allow a shell write to its own plan file, and no list of forbidden commands covers every way to spell one. - OpenCode: its plan agent, under a permission policy Ordewell writes for it alone: its read tools run, its edit tools, shell and subagents are denied, and anything else is asked of Ordewell. Earlier versions left the plan agent its shell; that gap is closed.
- Codex:
--sandbox read-only, a sandbox with no network, and every request to run a command or change a file declined.
A planner still runs commands. It runs them through one tool on Ordewell's own server,
run_command, so the same classifier decides for every agent, and the shell
each harness ships with never sees them. The same goes for an MCP tool you have
configured, a web fetch, or a read outside the repository: the agent asks, and
Ordewell answers by the rules you set
(approvals and scopes).
The guarantee is enforced at spawn, not by asking the model politely in a prompt. That distinction holds up under pressure: when a planning session requests a write anyway, it gets a refusal rather than a permission dialog.
request Write(src/auth/session.ts)
deny The Ordewell planner is read-only: it changes no files.
Use run_command for commands; changes belong to the plan's tasks.
Read only never means the agent sits still. To explore anything it has to run
commands, and most of those are inspection: listings, grep, git
log, reading a test file. Those run unprompted, because prompting on a read is
how an agent turns into a dialogue box. Anything outside that read only surface is
classified before it runs: a write is refused outright, and anything else runs only
if your allowlist covers it or you approve it. The classifier has to understand the shell
it is in rather than pattern match a string, since dir under
cmd.exe and dir in a POSIX shell are not the same program.
The envelope is per task, not just per planner
The planner is the obvious place for a read only session. It is not the only one. A plan usually contains a step whose whole deliverable is understanding: measure the current query counts, confirm which module owns session refresh, list every caller before the signature changes. In Ordewell a read only task is defined by Ordewell, the same on every runner, not by the runner's own flags.
It keeps its runner's native read tools, because every runner is built around them.
Its only shell is Ordewell's own command tool: what the command rules would ask about
or refuse runs sealed, with the workspace read-only, the task's own worktree
writable, no network, no home directory, and nobody asked. That is what lets a review
run the test suite, add a failing test, or try a fix to see whether it holds. A sealed command
may run for ten minutes. The runner's own write and shell tools are withheld on every
runner, and its own web fetch and search are refused; the task's web reads go through
Ordewell's fetch and web_search instead, under the same
policy the planner reads by.
And it lands nothing. The worktree is thrown away when the task ends, so the review
cannot turn into a change that arrives unannounced: the result is the task's report, or
the patch it saved of its worktree with save_patch, one file captured
inside the seal, that a dependent change task applies with apply_patch and
resolves the conflicts it reports. Where the task's real output is a decision, say so in
the plan and the executor keeps its hands off.
ordewell task-mode 6 # prints the modes this runner exposes, current one starred
ordewell task-mode 6 plan # keep this task read-only when the plan runs
task-mode is a line in an artifact you read before execution, so an
analysis step cannot silently become a code change because the agent got ambitious
halfway through. It works only where the runner exposes a mode tagged read-only, and
plan is that mode on all eight supported runners. The portable control is
the planner's readOnly request on the task: mark it and Ordewell assigns
the runner's read-only mode wherever one exists, and refuses the task with the runners
that can take one where none does. A task marked research is a read-only task
whose report is addressed to the planner: its end wakes the planner at every
supervision level, Off included.
The failure mode that is worse than no sandbox
Here is the part worth knowing before you trust any read only setup, mine included. A read only session that cannot run commands does not stop and tell you. It answers from memory, plus whatever it can fetch from the web, and produces a confident plan about a codebase it never read.
A concrete instance, because this is not hypothetical: on Ubuntu 24.04, AppArmor restricts unprivileged user namespaces, so Codex's bubblewrap sandbox fails to start and every command the planner runs dies with an error about the network interface. The agent still replies. What it replies with is a guess shaped like a plan.
The repair is to find out which sandbox actually works on that machine instead of
assuming. Ordewell asks the binary rather than reading /proc or
/etc/apparmor.d, because it is the same question put to the thing that
has to answer it, and it costs one short process. If bubblewrap cannot start, Codex is
pointed at its earlier Landlock backend, which needs no namespace and still denies the
writes that make read only planning read only. If both fail, the honest reading is
that Codex cannot explore on this machine at all, and that is a different problem than
a plan you dislike.
What a read only envelope does not give you
- It is a guarantee on Linux and macOS, and a weaker statement on Windows. On Windows, Codex's own sandboxing is not the kernel enforced equivalent of Seatbelt or Landlock, so read only there may be honoured by the tool layer rather than by the operating system. Approvals are still off by construction, but I am not going to call that the same guarantee.
- It says nothing about correctness. A read only session can still be wrong. The envelope makes a wrong analysis safe to read, not right.
- It does not stop a test suite from mutating your working tree. Read only governs the agent's tool permissions. A build or test command you allowed can still write build output, caches and fixtures, which is why those commands are a separate decision from this one.
- It is not a security boundary against a hostile agent. It is a guardrail against the ordinary case: a capable model doing something reasonable that you did not ask for in a directory you care about.
- It costs you a round trip. An agent that can write explores by editing. An agent that cannot has to reason from what it reads, and some questions genuinely are faster to answer by trying.
Running it
The planner runs read only by default, and nothing in the plan executes until you say go, so exploring costs you nothing but the plan itself.
npm install -g ordewell
AI_PROVIDER=claude-code ordewell plan --goal "Map how request auth reaches the database layer"
ordewell task-mode 6 plan
ordewell run
If you want the wider argument for separating the thing that decides from the thing that writes, plan first orchestration covers when that shape wins, and assigning an executor per task is where the runner, model and mode decisions live. The verification side is the other half of the same question: an envelope controls what an agent may change, and its own report decides whether it actually did the job.