Permission modes
What it shows
Section titled “What it shows”A permission mode says how much pi may do before it asks you. Each thread has one mode at a time, and you can change it while the thread is open. Every mode but default is a preset Enso lays over your permission policy for that thread; the modes follow Claude Code’s:
| Mode | What changes |
|---|---|
default |
The policy in permissions.json, as written. |
acceptEdits |
Edits and writes inside the project run without asking. |
plan |
Read and explore; the edit and write tools are denied. |
bypassPermissions |
Everything runs without asking, except what your own rules deny or ask. |
auto |
Edits run as in acceptEdits; a classifier model answers what would ask. |
When pi needs to ask, the question appears in the chat. See Questions and dialogs.
Your permission policy lives in ~/.enso/permissions.json (ENSO_HOME/permissions.json). Its permission block names each tool or surface and what happens to it: allow, ask or deny, or a map from pattern to one of those in which the last matching pattern wins, for example "bash": { "*": "ask", "npm publish*": "deny" }. A deny rule denies in every mode. A new ENSO_HOME starts with Enso’s default policy: read, grep, find, ls, ask_user and web_search run without asking; edits and writes ask; shell commands ask, except 29 read-only ones such as git status and ls; no git commit --no-verify, no git commit -n and no git push --delete; *.env and *.env.* files are denied to every tool; anything outside the project asks. The launch log says which file was used.
In auto, a question pi would ask you goes first to a classifier: the thread’s own model, asked whether the action stays within what you asked for. It allows the action or refuses it with a reason pi reads. When it cannot answer (no model, no credentials, no reply within 10 seconds, a reply it cannot read) you are asked instead. A rule you wrote to ask, such as "git push*": "ask", always reaches you, and so does a file path or a directory outside the project that the classifier would allow.
How to open it
Section titled “How to open it”- The mode selector sits above the composer. Pick a mode to change it.
- Or type
/modein the chat to choose from a list, or/mode <name>./default,/acceptEdits,/plan,/bypassPermissionsand/autoswitch directly. - A new thread’s mode is picked in Start a session.
What it looks like
Section titled “What it looks like”To see it: open a thread from the rail.

- The mode, as a line in the chat. Every change adds one, so the transcript shows when each mode started.
- The mode selector. It lists the modes this thread offers.
What to look for
Section titled “What to look for”Read the mode lines with the tool calls around them. A run of edits that went through without a question is expected under acceptEdits, and worth a look under default.
A change you make is not applied by the click. The server asks the thread to change, and the new mode arrives back on the thread’s feed like any other event. So the selector always shows the mode pi is actually in, and a change refused because the thread is busy leaves it as it was.
A new thread shows the mode as unknown until its first prompt has run. It starts in default.
What it doesn’t do
Section titled “What it doesn’t do”- A mode is not a guard. The guards apply in every mode,
bypassPermissionsincluded. See Guards and receipts. bypassPermissionsstill asks for a command run through a wrapper (bash -c,sudo,eval) and for one the permission engine cannot parse.- A shell command the policy allows may redirect its output into a file inside the project (
cat a > b) without asking. Writes outside the project still ask. - The terminal’s print variant (
bun run enso -p "…") has no permission modes. There is nobody to ask, so the permission engine would refuse every ask. Only Enso’s guards apply there, andbashis not confined. - Enso does not read Claude Code’s permission rules (
~/.claude/settings.json). Copy the ones you want intopermissions.jsonyourself. - An
ENSO_HOMEfrom before #496 held its rules asallow,denyandasklists. The first launch after moves that file aside aspermissions.json.picc-backupand seeds the default policy; the old rules are not carried over. - An edit to
permissions.jsonapplies at the next tool call, in running threads too. A file that is not plain JSON stops the launch, and the error names the file; comments are not allowed. Break it while a thread runs and that thread reads an empty policy: every call asks, and the deny rules are gone until the file is fixed. - A trusted project’s own
.pi/settings for the permission engine, and its.pi/agents/files, are read over your policy and can loosen it. In the web app every project counts as trusted; in the terminal, pi’s own trust question decides. - A mode the thread does not offer is refused, and so is a change while the thread is running.
Go deeper
Section titled “Go deeper”- Permission mode seam: how a mode is set and read, the policy file,
auto, and the known gaps. - Boot and launchers: the print variant.
- Terminal.
