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:

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.

a write request from the planner
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.

bash
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

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.

bash
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.