| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- ---
- title: "Permissions"
- description: ""
- ---
- Permissions control whether an agent may perform an action on a resource. V2
- configuration uses the `permissions` field and an ordered array of rules.
- <Warning>
- The V1 object syntax uses different field and action names. Do not use
- `permission`, `bash`, or `task` in V2 configuration; use `permissions`,
- `shell`, and `subagent`.
- </Warning>
- ## Rule schema
- Each rule has three required string fields:
- ```jsonc
- {
- "$schema": "https://opencode.ai/config.json",
- "permissions": [
- { "action": "*", "resource": "*", "effect": "ask" },
- { "action": "read", "resource": "*", "effect": "allow" },
- { "action": "read", "resource": "*.env", "effect": "deny" },
- { "action": "shell", "resource": "git status *", "effect": "allow" },
- { "action": "shell", "resource": "git push *", "effect": "deny" },
- { "action": "edit", "resource": "packages/docs/*.mdx", "effect": "allow" }
- ]
- }
- ```
- - `action` matches a tool permission action.
- - `resource` matches the value the tool is trying to use, such as a path,
- command, URL, query, or agent ID.
- - `effect` is `"allow"`, `"deny"`, or `"ask"`.
- `allow` proceeds without prompting, `deny` blocks the operation, and `ask`
- waits for a user decision. If no rule matches, the result is `ask`.
- ## Matching and order
- Both `action` and `resource` support simple wildcards:
- - `*` matches zero or more characters, including `/`.
- - `?` matches exactly one character.
- - All other characters are literal.
- Matches cover the entire value. Slashes are normalized, and matching is
- case-insensitive on Windows. For shell convenience, a pattern ending in
- `" *"` also matches the command without arguments: `"git status *"` matches
- both `git status` and `git status --short`.
- The **last matching rule wins**. Put broad rules first and exceptions later.
- Rules from lower-priority configuration files are loaded first. OpenCode then
- appends all global rules before agent-specific rules, so a matching agent rule
- overrides a global rule.
- Some operations check several resources at once, such as a patch touching
- multiple files. OpenCode denies the operation if any resource resolves to
- `deny`; otherwise it asks if any resolves to `ask`; otherwise it allows it.
- ## Actions and resources
- V2 action names are strings, so plugins may introduce additional actions. The
- current built-in actions use these resources:
- | Action | Resource matched |
- | --- | --- |
- | `read` | Location-relative path for an internal file or directory; canonical absolute path for an external target |
- | `edit` | Target path for `edit`, `write`, and `patch`; all three tools share this action |
- | `glob` | The requested glob pattern |
- | `grep` | The requested regular expression, not the search path |
- | `shell` | The complete raw shell command string |
- | `subagent` | The target agent ID |
- | `skill` | The skill ID |
- | `question` | `*` |
- | `webfetch` | The requested URL |
- | `websearch` | The search query |
- | `external_directory` | A canonical external directory boundary, normally ending in `/*` |
- | `<server>_<tool>` | `*` for an MCP tool; unsupported characters in both names become `_` |
- | `execute` | `*`; controls availability of the Code Mode dispatcher, while each nested tool still enforces its own permission |
- Built-in agent policy also reserves `plan_enter` and `plan_exit` for plan-mode
- transitions. `doom_loop` and `lsp` are not current V2 Core permission actions.
- ## External directories
- An external path requires a separate `external_directory` decision before the
- tool's own `read` or `edit` decision. This applies to external paths used by
- `read`, `edit`, `write`, and `patch`, and to an external `shell` working
- directory.
- ```jsonc
- {
- "$schema": "https://opencode.ai/config.json",
- "permissions": [
- {
- "action": "external_directory",
- "resource": "~/projects/reference/*",
- "effect": "allow"
- },
- {
- "action": "read",
- "resource": "~/projects/reference/*",
- "effect": "allow"
- },
- {
- "action": "edit",
- "resource": "~/projects/reference/*",
- "effect": "deny"
- }
- ]
- }
- ```
- For `external_directory`, `read`, and `edit` resources, a leading `~`, `~/`,
- `$HOME`, or `$HOME/` is expanded when configuration loads. Shell resources are
- raw command text and are **not** home-expanded.
- <Warning>
- `shell` runs with the host user's filesystem, process, and network authority.
- Its resource is raw text, not a parsed command. External command arguments
- produce only best-effort warnings; `external_directory` is enforced for the
- working directory, not every path embedded in a command. Prefer a narrow
- shell allowlist over patterns intended to identify every dangerous command.
- </Warning>
- Relative mutation paths cannot escape the active Location, and symlink escapes
- from inside it are rejected. Explicit external paths are canonicalized before
- matching, so authorize only trusted directory boundaries.
- ## Defaults
- The evaluator's fallback is `ask`, but shipped agents include ordered defaults:
- | Agent | Effective default policy |
- | --- | --- |
- | `build` | Allows most actions; asks for external directories and `.env` reads; allows questions and entering plan mode; denies exiting plan mode |
- | `plan` | Uses the same base, allows questions and exiting plan mode, and denies edits except OpenCode plan files |
- | `general` | Uses the base policy but cannot launch another subagent; questions and plan transitions remain denied |
- | `explore` | Denies everything except `read`, `glob`, `grep`, `webfetch`, and `websearch`; cannot launch subagents and asks for external directories |
- | Hidden maintenance agents | Deny all actions |
- The base read rules are ordered as follows:
- ```jsonc
- [
- { "action": "read", "resource": "*", "effect": "allow" },
- { "action": "read", "resource": "*.env", "effect": "ask" },
- { "action": "read", "resource": "*.env.*", "effect": "ask" },
- { "action": "read", "resource": "*.env.example", "effect": "allow" }
- ]
- ```
- OpenCode also permits its managed tool-output and temporary directories where
- needed. These exceptions do not grant general external-directory access.
- ## Agent overrides
- Configure shared policy at the top level and append narrower rules to a named
- agent under `agents.<id>.permissions`:
- ```jsonc
- {
- "$schema": "https://opencode.ai/config.json",
- "permissions": [
- { "action": "shell", "resource": "*", "effect": "ask" },
- { "action": "shell", "resource": "git diff *", "effect": "allow" },
- { "action": "shell", "resource": "git status *", "effect": "allow" }
- ],
- "agents": {
- "reviewer": {
- "description": "Review code without changing it",
- "mode": "subagent",
- "permissions": [
- { "action": "edit", "resource": "*", "effect": "deny" },
- { "action": "shell", "resource": "git diff *", "effect": "allow" },
- { "action": "shell", "resource": "git status *", "effect": "allow" }
- ]
- }
- }
- }
- ```
- Agent rules do not replace the global array; they are appended after it. A
- custom subagent executes with its own permissions, not a permission subset
- derived from the parent agent.
- ## Approval choices
- When an `ask` rule matches, clients can reply with:
- - **Allow once** (`once`): approve only the pending request.
- - **Allow always** (`always`): approve this request and save the patterns
- proposed by the tool for the current project.
- - **Reject** (`reject`): reject the request. Rejecting also rejects other
- pending permission requests in the same session; clients may attach feedback.
- Saved approvals are durable and project-scoped. They are additional `allow`
- rules, but they can never override a configured `deny`. The proposed saved
- pattern may be broader than the displayed resource: several tools propose `*`,
- shell proposes the exact command text, and skills and subagents propose their
- IDs. Review the confirmation carefully and remove saved approvals that are no
- longer needed.
- For non-interactive runs, `opencode2 run --auto` replies `once` to permission
- requests. It does not save approvals, and explicit `deny` rules remain enforced.
- Without `--auto`, a non-interactive run rejects permission requests.
|