Plan and Code
Permission is a single two-state Plan ↔ Code pill in the composer. There is no separate “Auto” toggle.
Code always means maximum permissions, for every provider. Picking Code does not ask you to trust the repo first — the per-repo trust prompt that used to gate it was removed. Plan never bypasses anything, on any provider. Cursor, the one provider with no plan mode of its own, is always on the Code pole and therefore always skips approvals.
The bypass flag itself is mid-session state held in memory. After an app restart or the inactivity sweep below, the approval policy a session spawns with is resolved from the pole the pill is showing, not from that volatile flag — so a session never comes back up silently auto-approving when the chip says Plan, and never comes back up asking for approvals when the chip says Code.
Daemon enforcement
Toggling the underlying flag over the wire (POST /sessions/:id/autopilot) is possible for any peer holding the bearer token, including your iPhone. The daemon layers three checks before it takes effect:
1
Idempotency
The request’s idempotency key is reconciled against the mobile command outbox, so a retried toggle replays the cached response instead of re-executing.
2
Swap throttle
The toggle counts as a swap and must pass the 1-per-5-second limit. A denial returns
HTTP 429.3
Code sessions only
A Chat session is rejected with
HTTP 400. There is nothing to auto-approve.Inactivity sweep
Skip-approvals does not stay on forever. The daemon ticks every 30 seconds and looks for sessions that have autopilot on and no agent message for 15 minutes. Each one is disabled, the session is paused, and a status event fires so every client clears its indicator. You resume explicitly to continue. This is the guardrail for the failure that actually happens: a session quietly stalls — waiting on a prompt nobody sees, or wedged mid-tool — while still holding permission to act unattended.Rate limits
The daemon throttles mid-session operations per session, as defense-in-depth against a misbehaving or compromised client:
Both return a structured
HTTP 429. The iOS command outbox treats 429 as transient — the envelope stays queued and retries with exponential backoff (1s, 4s, 15s, 60s, 5min, 30min) rather than surfacing a failure.
Running the repo’s own scripts
Skipping approvals and running a repo’s own scripts are two different grants, and only one of them was relaxed. The review pane’s Preview tab — and the same action reached from a paired device — resolves a repo’sconductor.json setup and run scripts, or a package.json dev script, and executes them through /bin/zsh -lc as you. That is arbitrary repo-authored code, so it stays gated on a per-repo execution trust list, persisted to:
Audit logs
Every sensitive write is recorded as hash-only JSONL — prompt text is SHA-256’d with a byte count, no plaintext, no PII — under an owner-only (0700) directory:
Each stream rotates at 1 MB or 7 days, whichever comes first; the rotated archive is timestamped (
<kind>.<iso8601>.jsonl). On daemon startup the last 256 entries of mobile-commands.jsonl — current file plus the most recent archive — are replayed to re-seed the idempotency cache, so retries still in flight from your phone are caught after a restart.
Diagnostics
Settings → Diagnostics has a segmented control with two surfaces:- Audit Log
- Wire Inspector
Browse the prompt-send, swap, and autopilot streams with a text and session-ID filter. Tap an entry to expand its raw JSONL. Support Bundle exports a redacted copy of the audit folder for sharing.