raunen

Modes

tab cycles three modes, shown at the left of the status bar. Start in plan if you would rather it proposed than acted.

ModeBehaviour
autoevery tool runs immediately
accept editsread-only tools run freely; anything that changes state asks first
plananything that changes state is refused, so the model investigates and proposes

In accept edits a prompt takes over the status row and the agent is blocked until answered:

approval
? run write main.go   y approve  ยท  n decline

The mode is also written into the system prompt, so the model knows the rules instead of learning them by collecting refusals.

How "changes state" is decided

read and list never do; write and edit always do. bash is the awkward one: it can do anything, so it counts as mutating unless the command matches a conservative allowlist โ€” ls, cat, grep, rg, find, git status|log|diff|show and similar.

Redirection, command substitution, env-var prefixes, absolute paths and anything unrecognised all count as mutating.

That is an allowlist, not a denylist, deliberately. There is no way to enumerate every way a shell can change something, and a wrong "this is safe" writes to your disk. The cost is that plan mode sometimes refuses a harmless command it does not recognise.

Permission rules

Modes are a blunt instrument. accept edits asks about every change, and the twentieth identical prompt gets approved without being read. What is missing is the middle: this is fine, that never is. So a tool maps either to one decision for every call โ€” "write": "ask" โ€” or to patterns with their own:

config.json
  "permissions": {
    "bash": { "git *": "allow", "git push *": "deny" },
    "edit": { "docs/*": "allow" },
    "write": "ask"
  }
DecisionMeaning
allowruns without asking, even in accept edits
denyrefused, in every mode
askprompts โ€” the default when nothing matches

* is the only wildcard and it spans everything, separators included โ€” a rule about docs/ means the whole of docs/. A deny holds everywhere, auto included, because "never push" is not advice about one mode. Rules refine modes rather than replace them, so plan mode still refuses every change whatever an allow says.

The most specific rule wins โ€” measured by how much of the pattern is not a wildcard, so git push * beats git *. Where two equally specific rules disagree, the denial wins, because if the config contradicts itself, refusing is the safe reading. A malformed rule is reported and dropped, not fatal โ€” and dropping fails closed, back to asking.

For the moment only: press a at an approval prompt to approve and stop asking for calls like that one, for the rest of the session. The grant is deliberately narrow โ€” a command grants the verb, a path grants that file alone โ€” and is never written to disk. /permissions lists what is in force.