Skip to the page
Conch
DocsGitHub

Decisions

0100 — Permission modes that mean the same with every provider

Status: accepted · 2026-10-07

Context

Conch offered five modes: Ask first, Auto, Edit freely, Plan only and Full trust. An audit found that they didn't mean one thing:

  • Auto was Claude Code's alone. Only a Claude Code model with its own auto-mode classifier offered it, so the chat's picker usually didn't show it, and every other provider fell back to Ask first.
  • Full trust still asked a lot. Codex CLI ran sealed with no network even in Full trust, so git push and npm install failed with nothing to ask. A Gmail draft, a Slack message or a calendar change always showed its preview card. A browser upload always asked.
  • The modes weren't a ladder. Auto and Edit freely each let different things through, so a task's "never more than its chat" had two incomparable answers.
  • The words lived in two places. The chat apps' /mode menu had its own copy, and Settings → Models was a plain radio list unlike the chat's picker.

People asked for two things. Full trust should be what every agent calls YOLO: it never stops, except for a tiny, justified list. Auto should be very permissive and never ask about routine work, yet notice something serious and stop for that alone.

Decision

The ladder

One definition, MODE_WORDS in @conch/protocol (modes.ts): the chat's picker, Settings → Models (Nacre ModeChoice), the chat apps' /mode, the documentation and the restore preview all read it, with the same icons from features/models/catalog.tsx. From the least the assistant does alone to the most (MODE_POWER):

ModeGoes ahead without askingStops for
Plan onlyReading and planningEverything that changes something is refused; Start ends planning
Ask firstReadingEvery change, command and app write
Edit freelyChanging files in the work folderCommands, app writes, files elsewhere
AutoRoutine work: edits, commands, installs, pushes, app actionsSomething serious (the risk policy), and the ways out once the chat read something
Full trustEverythingOnly the circuit breaker and what no mode lifts (below)

It maps onto what other agents offer: Claude Code's default / acceptEdits / plan / auto / bypassPermissions; Gemini CLI's plan < default < autoEdit < yolo; Codex's read-only, auto (workspace) and full access; VS Code's Manual, Assisted (an LLM judge) and Allow all. A task's mode is never more than its chat's, now on one ladder (noMoreThan).

Auto: a risk policy, scored

conversations/risk.ts reads each step — a command (inside bash -c, $(…), sudo, env, chains and pipes), a file path, an app's tool — and finds what it could do at its worst. Each rule has a harm (severe: your keys, someone else's systems, a disk, production, code from a stranger; moderate: data leaving, a new dependency) and says whether it is lasting (Conch can't put it back). Undo (ADR 0030) puts back anything a file tool changed and anything in the work folder, so those aren't lasting; a push, a message, a deletion elsewhere, a secret read, are. The chat adds provenance: whether it read something untrusted (ADR 0028).

score = harm (severe 2, moderate 1) + lasting (1) + untrusted (1). Three or more asks.

So something severe that can't be put back always asks; severe-but-undoable and moderate-but-lasting ask only once the chat read something; the rest never asks.

Severe and lasting: always asksAsks only after reading something
Running downloaded or decoded code (curl … | sh, iex (iwr …), base64 -d | sh), installing from an addressPushing; a new dependency (npm i x, pip install x, npx x)
Reading keys and sign-ins (~/.ssh/id_*, ~/.aws/credentials, the keychain, gh auth token, cloud metadata)Sending data out (curl -d, scp, rsync host:, ssh host, a script with requests)
Drop boxes (webhook.site, ngrok, pastebin…), reverse shellsThrowing away uncommitted work (git reset --hard, git clean -fdx)
Deleting outside the work folder; force-pushing or deleting a shared branchShell start-up files, LaunchAgents, cron, systemd; git hooks, CI workflows
sudo, setuid, adding users, authorized_keys, sudoersApplying or deploying to non-production infrastructure
Turning off Gatekeeper, SIP, quarantine, SELinux, the firewall, DefenderTunnels to this computer; another agent with its checks off
Destroying infrastructure, production deploys and migrations, granting IAM, secrets and DNS, wiping databasesChanging an assistant's own permission files
Publishing a package or a release, making a repository public; an app's tool that deletes

Built from Claude Code's auto-mode defaults (what its classifier blocks and allows), Codex's sandbox presets, Gemini CLI's policy engine, VS Code's terminal auto-approve rules, Cursor's auto-run lists, and the OWASP Top 10 for LLM applications (LLM01 prompt injection, LLM02 sensitive information disclosure, LLM06 excessive agency) and its agentic threats (tool misuse, privilege compromise). Two places differ from Claude Code on purpose: pushing to the default branch is fine (Claude Code agrees since v2.1.211), and throwing away uncommitted work asks only after reading, because Conch's Undo can put the work folder back.

risk.test.ts measures it against a corpus (test/riskCorpus.ts): over 200 everyday steps of a coding and personal assistant must pass silently before and after reading the web (false positives: 0.0%, asserted), over 40 classic ways out must pass before reading and ask after, and over 100 serious steps must ask either way. A list is a careful reader, not a boundary ("obfuscated commands can evade matching", as VS Code says of its own): it only ever adds a question. The sealed box, protected paths and Conch's own powers hold whatever it says.

After reading, in Auto (a person here, only things read in the chat), the guard after reading asks for what the risk policy marks, plus an app's write and an address that could carry what was read; it doesn't ask for every command any more. Commands stay sealed (no network, no secrets) from the first read, so a routine one is safe to run. With someone else's words in the chat, or nobody there (a routine, a chat app), Auto checks every way out as before.

Where Auto is decided. In Conch's layer, so it holds for every provider: the guard (mustAsk) asks for anything serious in every mode but Full trust, with the reason on the card and no "Always allow"; requestPermission and Conch's own tools (hostAsk) let the rest through in Auto. An app tool the person set to Ask in Apps keeps asking in Auto (Full trust skips it); an app tool that deletes asks unless the person set it to Allow, or the app to Don't ask. Leaving the sealed box is free in Auto until the chat reads something.

Full trust: never asks, but for what no mode lifts

Full trust lets everything through — commands, the sealed box, app approvals, the words going to other people (Gmail, Slack, Calendar), a paid picture, a browser download or upload — with every provider. The only things left are irreducible, each because the person's trust can't reach it:

  1. The circuit breaker. Deleting a whole folder like your home, the work folder or a disk (rm -rf ~, rm -rf ., rm -rf "$DIR"/*, diskutil eraseDisk) asks. One slip there can't be put back by anyone. Claude Code asks for these in bypass mode too (its "critical paths").
  2. Conch's own keys and powers are refused, not asked: Passwords, Conch's keys and sign-ins (protected paths), and changing who may reach Conch or whose skills it trusts (runsConchPower). The agent can't raise its own privileges (AGENTS.md).
  3. Tools turned Off in Apps stay off.
  4. Someone else's words. A message from someone who isn't you (a group, a chat app's guest) can't borrow your trust: its steps ask you.
  5. Nobody there after reading. A routine or a chat-app chat that read something untrusted asks you, by notification, because no one is watching.
  6. A skill's list. A chat held to a skill (ADR 0031, ADR 0047) asks for what the skill didn't say it needs; the skill's author isn't you.
  7. Paying or deleting on a website (high-stakes in the browser), and each site in your own signed-in Chrome (ADR 0080).

Spending limits (ADR 0079) stop a reply; they never ask.

Per provider

Every provider now offers all five modes (ALL_MODES); honouredMode still turns one a provider can't do into its first.

ProviderPlan onlyAsk first / Edit freelyAutoFull trust
Claude Codeplandefault / acceptEditsIts own auto (classifier) where the model has it, plus Conch's risk policy in the PreToolUse hook; otherwise default, with Conch answering each question. When its classifier wants a person (escalated), the person answersbypassPermissions; the hook keeps the irreducible list; commands sealed, leaving the box free
Codex CLI (its own tools)approvals declinedapprovals asked / changes acceptedapprovals accepted after the guard; its sandbox: the work folder with the network until the chat reads somethingapprovals accepted after the guard; its sandbox: your folders and the network (reach: 'open'), Conch's keys denied
Codex, Copilot, Gemini CLI, Grok (ACP), model APIs, local modelsConch's tools refuse changesConch's tools ask (authorizeTool)Conch's tools go ahead after the guard; commands leave the box for the network until the chat reads somethingConch's tools go ahead; commands needing the network or your folders run unsealed
Tasks and helperstheir chat's mode, never more (ADR 0033)
Chat apps/mode lists the ladder; a raise asks to savethe owner answers in Conch or by notificationas in Conch; someone else's words check every way outits own warning before saving; the restore preview names it

ACP programs' own tools are declined in every mode, as before: the door's tools do the work, under these rules, so every ACP program behaves the same. Codex CLI's sandbox is set once per turn (TurnInput.reach); a mode picked mid-turn changes what's asked from the next step, and its reach from the next message. Codex never gets more than its profile, in any mode (ADR 0066), which in Full trust is only Conch's own keys.

Settings and the restore preview

Settings → Models shows the choice as ModeChoice: the chat picker's options, as calm cards with their icons, Plan only to Full trust, Full trust confirmed in place. Auto as the default is a power a backup brings back (chats-go-ahead), named in the restore preview like Full trust.

Consequences

  • Auto is in every chat, with every provider, and asks about one thing in dozens.
  • Full trust is what people expect from YOLO. The security checkup still warns about it and offers Ask first or Auto.
  • The risk policy's lists need care as tools change. A step it misses is still sealed, still undoable and still behind protected paths; one it flags wrongly is a single question with its reason. The corpus test keeps both honest.
  • Codex CLI in Full trust can read your SSH keys, as you can (a push needs them); Conch's own keys stay denied.

Sources

Read 2026-10-07: