opencode-map
← guides/

Permissions in opencode: allow, ask, deny

IntermediateLast updated: Oct 21, 2026

Every action opencode takes — reading a file, editing code, running a shell command — resolves to one of three outcomes: run it, ask first, or block it. The permission config controls which is which. Since v1.1.1 the legacy boolean tools config is deprecated and merged into permission (still accepted for backwards compatibility).

Actions

Each rule resolves to "allow" (run without approval), "ask" (prompt for approval in the TUI), or "deny" (block the action).

Configure

Set a global default with "*", then override per tool:

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "*": "ask",
    "shell": "allow",
    "edit": "deny"
  }
}

Or set everything at once: "permission": "allow".

Granular rules

Most permissions take an object mapping input patterns to actions. The last matching rule wins — put the catch-all "*" first and more specific patterns after it:

{
  "$schema": "https://opencode.ai/config.json",
  "permission": {
    "shell": {
      "*": "ask",
      "git *": "allow",
      "git push *": "deny",
      "grep *": "allow"
    },
    "edit": {
      "*": "deny",
      "packages/web/src/content/docs/*.mdx": "allow"
    },
    "webfetch": {
      "*": "ask",
      "https://en.wikipedia.org/*": "allow"
    }
  }
}

Wildcards are simple: * matches zero or more characters, ? matches exactly one, everything else is literal. ~ or $HOME at the start of a pattern expands to your home directory. Patterns match the tool input — file paths for read/edit, the glob for glob, the regex for grep, the URL for webfetch, and the parsed command for shell. Match full commands, not just the binary: "grep *" allows grep pattern file.txt, while "grep" alone blocks it once arguments are passed.

Available permissions

Key Matches
read File path
edit File path — covers edit, write, patch
glob Glob pattern
grep Regex pattern
list Directory path — the ls tool
shell Parsed commands (e.g. git status --porcelain)
task Subagent type
skill Skill name
lsp LSP queries (non-granular)
question Asking you questions mid-run
webfetch URL
websearch Web search
external_directory Tools touching paths outside the working directory
doom_loop The same tool call repeated 3x with identical input

Defaults are permissive: most keys are allow, while the two safety guards external_directory and doom_loop default to ask. read allows everything except .env files (*.env and *.env.* denied, *.env.example allowed).

external_directory gates any tool call that touches paths outside where opencode started. Allow trusted roots explicitly:

{
  "permission": {
    "external_directory": { "~/projects/personal/**": "allow" },
    "edit": { "~/projects/personal/**": "deny" }
  }
}

Allowed directories inherit workspace defaults — since read defaults to allow, reads just work; layer deny rules where you want restrictions.

What “ask” does

The approval prompt offers three outcomes:

  • once — approve just this request
  • always — approve future requests matching the tool’s suggested patterns for the rest of the session (shell approvals typically suggest a safe prefix like git status*)
  • reject — deny the request

Auto mode approves anything not explicitly denied: launch with opencode --auto or opencode run --auto "…", or toggle it from the command palette (Enable auto-approve permissions). Deny rules are still enforced. A muted auto indicator shows next to the agent name while it’s active.

Per-agent overrides

Agents get their own permission block, merged with the global config — agent rules take precedence:

{
  "agent": {
    "plan": {
      "permission": {
        "edit": { "*": "deny", "~/.opencode/plan/*": "allow" },
        "shell": "ask"
      }
    }
  }
}

The built-in plan agent already denies edits outside ~/.opencode/plan/ by default (refused without prompting) and allows the question tool — but it leaves shell commands to your permission config. Watch the ordering: plan’s defaults apply before your top-level permission, so a global "edit": "allow" re-enables edits — pin agent.plan.permission explicitly to keep plan read-only. Markdown-defined agents (~/.config/opencode/agents/*.md) take the same permission: block in frontmatter.

v2 differences

v2 replaces the whole surface: permissions (plural) is an ordered array of { "action", "resource", "effect" } rules — last match wins — instead of the v1 permission object, and config files are opencode.jsonc. Actions rename bash→shell and task→subagent; doom_loop and lsp are not v2 actions. Defaults also shift: v2 asks on .env reads rather than denying them. This guide covers the v1 config.

Further reading