Permissions and sandbox¶
Iteron classifies tools by capability, then applies a permission mode plus session rules. The model cannot grant itself a capability.
Capability classes¶
| Capability | Examples | Default posture |
|---|---|---|
read_only |
workspace reads, search, repository inspection | automatic |
reversible_local |
tracked workspace edits behind recovery state | asks in default; automatic in acceptEdits and yolo |
code_executing |
shell, build, test | asks except in yolo; unavailable without the code-execution grant |
trust_mutating |
declared writes to Git/CI/instruction/trust surfaces | always asks or denies |
irreversible_external |
push, publish, send, external MCP effects | always asks or denies |
Permission modes¶
| Mode | Behavior |
|---|---|
default |
reads automatic; edits and code ask |
acceptEdits |
reversible edits automatic; code asks |
plan |
hard read-only overlay; everything above read-only is denied |
yolo |
reads, reversible edits, and granted code execution automatic; the two highest classes still ask |
Set a mode with --mode or /mode. Use /permissions allow|ask|deny CAPABILITY
for session rules where policy permits. Read-only cannot be disabled, and the two
highest capability classes cannot be changed to automatic.
The gate is bypassed by default¶
Owner decision, 2026-08-05: on a default run, none of the two tables above
decides anything. The capability gate is replaced by blanket auto-approval, so
every tool runs without prompting — including trust_mutating and
irreversible_external, the two classes the first table calls "always asks or
denies" and which even yolo still stops at. yolo is a bounded mode; this is
not one.
Three things still apply, and they are the whole of what is left:
--mode planhard-denies everything above read-only. Bypass never punches through Plan.- An explicit
/permissions denyon a tool or a capability is still honored. - The kernel's capability ceiling still holds: the task authority ceiling intersected with the immutable policy capability set is not part of the permission gate and is not bypassed with it. A task that never held a capability cannot use it in any posture.
Owner decision, 2026-08-06 — two of those were narrowed further. The kernel's
trust conjunct no longer applies to an operator-authority session: a turn that
has read untrusted content may still call an egress tool. It never covered bash
(classified code_executing, so a curl inside it was never held by it), so the
conjunct was a boundary on one path and not the other. And delegated sub-agents
now inherit the session posture rather than running gated: a child has no
approval channel, so a gate it cannot answer is a refusal wearing a question's
clothes, and a bypassed session was delegating work its own children could not do.
What bounds a child is its ceiling and its tool filter, both still intersected
downward — a read-only definition stays read-only.
--ask-permissions and --mode plan restore the gate AND the trust conjunct.
--ask-permissions restores the gate, and then the modes above mean exactly what
they say. In one-shot (-p) there is no approval channel, so an "ask" resolves as
a refusal — pair --ask-permissions with --mode acceptEdits or an explicit
allow rule rather than expecting a prompt.
A bypassed session says so in three places, deliberately: a stderr banner at
startup, the mode row in /status, and the first row of /permissions.
Enable code execution¶
bash, builds, tests, and --verify are enabled by default. --allow-code is
retained and still grants the code_executing capability explicitly; an operator
removes the grant with "allow_code": false in ~/.iteron/config.json, with the
same key in a project .iteron/config.json, or with --mode plan.
Sandbox contract¶
The default posture is unconfined (owner decision, 2026-08-05). A bash
command runs with the authority of the account that started iteron: it reaches the
network, reads any file that account can read — ~/.ssh, ~/.aws, the keychain
paths — and writes anywhere on the host. The file tools resolve paths the same
way, so read_file and write_file address the whole filesystem, not the
workspace.
Two ceilings survive that change, because they are liveness bounds rather than security ones: a per-command wall clock and a per-stream retained-output bound.
--confine selects the confined posture instead. Nothing about it was weakened;
it is the same contract this document has always described:
- network egress denied;
- writes confined to the workspace plus a capability-private scratch directory;
- ambient HOME credential paths denied;
- macOS uses the system Seatbelt interface;
- Linux requires a usable bubblewrap/user-namespace boundary and fails closed if it cannot establish one.
Why the default changed¶
The confined posture was not wrong, it was silently fatal to the tool. With no
network, git push, gh, curl, and every package install failed, and they
failed as ordinary command errors rather than as a visible policy denial. With
workspace-only paths, the absolute path the model naturally emits was refused,
and three such refusals in a row tripped the consecutive-error floor and ended
runs that had nothing wrong with them.
What to use when¶
| Situation | Posture |
|---|---|
| Your own repository, your own machine | the default |
| A repository you have not read | --confine, or --mode plan |
| Anything you would not hand your shell to | do not run it |
Not a confidentiality boundary
Do not run hostile code or secrets on the assumption that the pre-alpha sandbox has completed production adversarial validation. A repository can contain code that writes trust-sensitive paths from inside an allowed shell command. Declared tool-level classification cannot parse and prove every nested effect of arbitrary code.
yolo is therefore a deliberate operator tradeoff, not the shipped bypass.
For an unfamiliar repository, use --ask-permissions --confine, use
--mode plan, or do not run it.