OpenCode's permission system is used to control which operations can run automatically, which require manual approval from you, and which will be blocked outright. Properly configuring permissions allows the AI to efficiently complete tasks while preventing accidental operations that could damage code or leak sensitive files.
Starting from v1.1.1, the old `tools` boolean configuration has been deprecated and merged into `permission`. The old configuration is still supported for backward compatibility, but it is recommended to migrate to the new `permission` syntax.
Three Permission Actions
Each permission rule ultimately resolves to one of the following three actions:
| Action | Effect | Use Case |
|---|---|---|
"allow" |
No approval needed, runs automatically | Low-risk, high-frequency operations like reading files or running tests |
"ask" |
Pops up an approval prompt for you to decide whether to allow | Operations with some risk, such as writing files or executing scripts |
"deny" |
Blocks outright, neither executes nor prompts | Clearly disallowed dangerous operations, such as deleting files or pushing code |
Basic Configuration
Permission configurations are written in the opencode.json file located at the root of your repository (or user config directory) using the permission field.
1. Set All Permissions Globally
The simplest way: set all operation permissions with a single string. Suitable for quick start or temporary debugging:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": "allow" // All operations run automatically without any prompts (suitable for local development or when fully trusting the AI)
}
2. Configure by Tool Name
Using object notation allows specifying permissions for different tools separately. "*" is a wildcard matching all operations, typically used as a fallback default:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"*": "ask", // Fallback rule: all unconfigured tools default to prompting
"bash": "allow", // bash (executing shell commands): directly allowed, no prompt
"edit": "deny" // edit (modifying files): blocked outright
}
}
Fine-Grained Rules (Object Syntax)
For most permissions, besides setting a uniform action, you can also use the object syntax to apply different rules based on specific input content of the tool. For example, for the bash tool, you can distinguish which commands are allowed, which need approval, and which are denied outright:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"*": "ask", // Fallback: all bash commands default to requiring approval
"git *": "allow", // Commands starting with git (e.g., git status, git log) allowed directly
"npm *": "allow", // Commands starting with npm (e.g., npm install, npm run build) allowed directly
"grep *": "allow", // Grep search commands allowed directly
"rm *": "deny" // rm delete commands blocked outright (to prevent accidental file deletion)
},
"edit": {
"*": "deny", // Default to blocking all file edits
"packages/web/src/content/docs/*.mdx": "allow" // Only allow editing .mdx files under docs directory
}
}
}
Rule Matching Order: Last matched rule takes precedence. It is recommended to place the wildcard
"*"rule first as a default value, with more specific rules placed later to override it. This way, more specific rules take higher priority, making logic clear and less error-prone.
Wildcard Rules
Permission patterns support simple wildcard matching with the following rules:
| Wildcard | Meaning | Example |
|---|---|---|
* |
Matches zero or more arbitrary characters (not crossing directories) | git * matches git status, git log --oneline, etc. |
** |
Matches arbitrary paths across directories | ~/projects/** matches all files and subdirectories under projects |
? |
Matches exactly one arbitrary character | file?.txt matches file1.txt, fileA.txt |
| Other Characters | Match literally | git status only matches git status, not variants with parameters |
Note: For commands with parameters, always add
*at the end. For example,"grep *"matchesgrep pattern file.txt, while just writing"grep"only matches the bare command without parameters, which rarely matches in practice.
Home Directory Expansion
In patterns, you can use ~ or $HOME at the beginning to reference the current user's home directory. OpenCode will automatically expand it to the full path:
Example
// The following three forms have the same effect, all expanding to /Users/username/projects/* (path varies by system)
"~/projects/*"
"$HOME/projects/*"
"/Users/username/projects/*" // Absolute paths work too, but not recommended (less portable)
External Directory Permissions (external_directory)
By default, OpenCode only allows tools to access the working directory where it was started and its subdirectories. If you need to access paths outside the project directory (e.g., another project or shared config directory), you must explicitly authorize via external_directory.
Home directory expansion (
~/...) is merely a shorthand for path writing and does not automatically grant access to that path. Paths outside the working directory still require explicit allowance throughexternal_directory.
1. Allow Access to External Directories
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"external_directory": {
"~/projects/personal/**": "allow" // Allow access to all files and subdirectories under ~/projects/personal/
// ** matches arbitrary nested subpaths
}
}
}
2. Allow Reading but Deny Editing
Directories authorized by external_directory inherit the default permissions of the current workspace. Since read defaults to "allow", files under these directories can be read after authorization. To further restrict certain operations (e.g., allow reading but prohibit editing), additional rules can be layered:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"external_directory": {
"~/projects/personal/**": "allow" // Step 1: Authorize access to the external directory
},
"edit": {
"~/projects/personal/**": "deny" // Step 2: Overlay rules on this directory to allow reading but block editing
}
}
}
All Available Permission Items
OpenCodeβs permissions are keyed by tool names, covering all types including file operations, command execution, network access, etc.:
| Permission Item | Controlled Operations | Pattern Matching Content | Default Value |
|---|---|---|---|
read |
Reading file contents | File paths (e.g., src/index.js) |
allow (except .env files) |
edit |
All file modifications, including edit, write, patch, multiedit | File paths | allow |
glob |
File wildcard searches (e.g., find all .ts files) |
Wildcard patterns (e.g., **/*.ts) |
allow |
grep |
Search text within file contents | Regular expression patterns | allow |
list |
List files in a directory | Directory paths | allow |
bash |
Run shell commands | Parsed full command (e.g., git status --porcelain) |
allow |
task |
Launch sub-agents | Sub-agent type names | allow |
skill |
Load skills | Skill names | allow |
lsp |
Run LSP language service queries | Currently not configurable granularly | allow |
webfetch |
Fetch content from URLs | Full URL (e.g., https://example.com/api) |
allow |
websearch |
Web search | Search query strings | allow |
codesearch |
Code search | Search query strings | allow |
external_directory |
Access paths outside the working directory | External directory paths | ask |
doom_loop |
Triggered when the same tool is called with identical input 3 times (prevents AI infinite loops) | β | ask |
Default Permission Explanation
If you do not configure any permissions, OpenCode uses the following built-in defaults:
- Most tool permissions default to
"allow", meaning they run automatically without prompts doom_loopandexternal_directorydefault to"ask", requiring manual approvalreadallows reading all files by default, but includes built-in protection for.env-related files:
Example
// Built-in read default rules in OpenCode (no need to configure manually, for reference only)
{
"permission": {
"read": {
"*": "allow", // Default to allowing reading all files
"*.env": "deny", // Block reading .env files (to prevent leaking database passwords, API keys, etc.)
"*.env.*": "deny", // Block reading .env.local, .env.production, etc.
"*.env.example": "allow" // Allow reading .env.example (example file, no real secrets)
}
}
}
Three Options for Approval Prompts
When an operation's permission is set to "ask", OpenCode will pop up an approval prompt offering the following three choices:
| Option | Effect | Use Case |
|---|---|---|
| once (Just Once) | Approve only this request; next time the same operation will prompt again | Temporarily allow an operation without permanently opening it |
| always (Always Allow) | Adds the matching pattern of this operation to the whitelist, no more prompts for the rest of the session | Confirm a class of operations is safe and want them to auto-pass in this session |
| reject (Reject) | Reject this request, operation won't execute | Detect risk in the operation and clearly donβt want it executed |
After choosing always, OpenCode will automatically suggest a whitelist pattern (e.g., after approving git status, it usually adds git status* to the whitelist). The whitelist is only valid for the current session and resets upon restarting OpenCode.
Configuring Permissions Separately for Agents
If your workflow uses multiple agents, you can override permission configurations for each agent individually. Agent permissions merge with global settings, and agent rules take precedence over global rules.
1. Configure Agent Permissions in opencode.json
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
// Global permissions: git operations allowed, but commit and push denied
"bash": {
"*": "ask",
"git *": "allow",
"git commit *": "deny",
"git push *": "deny",
"grep *": "allow"
}
},
"agent": {
"build": { // Agent named build
"permission": {
"bash": {
"*": "ask",
"git *": "allow",
"git commit *": "ask", // Override global: build agent allows commit but requires approval
"git push *": "deny", // Inherit global: still denies push
"grep *": "allow"
}
}
}
}
}
2. Configure Agent Permissions in Markdown Files
Agents can also be configured via Markdown files, with permissions written in the YAML Front Matter at the top of the file (between ---):
Example
# File Path: ~/.config/opencode/agents/review.md
---
description: Code review agent (only analyzes code, makes no modifications)
mode: subagent
permission:
edit: deny # Prohibit all file edits
bash: ask # Bash commands require approval
webfetch: deny # Prohibit accessing external URLs
---
Only analyze code and suggest changes.
# Below are the system prompts for this agent, describing its responsibilities and behavior norms
Practical Configuration Examples
Example 1: Conservative Mode (All Operations Require Approval)
Suitable for first-time users of OpenCode or working on important projects, where all operations require manual confirmation:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"*": "ask" // Prompt for approval for all operations of all tools
}
}
Example 2: Development Common Configuration (Read Allowed, Write Approved)
Suitable for daily development: allow AI to freely read and search code, but confirm before modifying files or executing commands:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"*": "ask", // Fallback: unconfigured tools default to prompting
"read": "allow", // Reading files: allowed directly
"glob": "allow", // File wildcard search: allowed directly
"grep": "allow", // Content search: allowed directly
"list": "allow", // List directories: allowed directly
"bash": {
"*": "ask", // Bash commands default to prompting
"git status *": "allow", // Check git status: allowed
"git log *": "allow", // Check git logs: allowed
"git diff *": "allow", // Check git diffs: allowed
"npm run *": "allow", // Run npm scripts: allowed
"npm test *": "allow", // Run tests: allowed
"rm *": "deny" // Delete files: blocked outright
}
}
}
Example 3: Allow Access to Multiple Project Directories
When AI needs to work across multiple project directories, authorize access to external directories:
Example
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"external_directory": {
"~/projects/personal/**": "allow", // Allow access to personal project directory
"~/projects/work/**": "allow", // Allow access to work project directory
"~/dotfiles/**": "allow" // Allow access to config directory
},
"edit": {
"~/dotfiles/**": "deny" // Even if allowed access to dotfiles, prohibit editing (read-only)
}
}
}
YouTip