Permissions
The permission system controls which tools agents can use and under what conditions. It uses a layered rule evaluation model with project-level and agent-level overrides.
Permission Rules
A permission rule is a string in the format "ToolName(specifier)":
Bash(npm run *) — Allow any npm run command
Read(./.env) — Match reading .env file
WebFetch(domain:*.example.com) — Match fetching from example.com subdomains
Bash(rm -rf *) — Match rm -rf commands
Rule Format
| Component | Description |
|---|---|
| Tool name | Case-insensitive tool identifier (e.g., Bash, Read, Write) |
| Specifier | Optional pattern inside parentheses — glob/prefix matching for commands and paths |
Special specifier prefixes:
domain:— ForWebFetch, matches against the URL's host using glob patterns- No prefix — Matches against the tool's primary input (command for Bash, path for Read/Write)
If no specifier is provided (e.g., just "Bash"), the rule matches all invocations of that tool.
PermissionSet
A PermissionSet contains three ordered lists of rules:
{
"allow": ["Bash(npm run *)", "Read(*)"],
"ask": ["Bash(rm *)"],
"deny": ["Bash(curl *)"]
}
| List | Effect |
|---|---|
allow | Tool call is permitted without asking the user |
ask | Tool call requires user approval |
deny | Tool call is blocked outright |
Permission Modes
The PermissionMode enum defines 5 evaluation modes that change the default behavior:
| Mode | Description | Default Decision |
|---|---|---|
Default | Standard mode — explicit rules apply, unmatched calls require asking | Ask |
AcceptEdits | Automatically allow file edits (Write, Edit, NotebookEdit) | Ask (except edits) |
Plan | Read-only mode — denies all write/execute tools (Bash, Write, Edit, NotebookEdit) | Deny for writes |
DontAsk | Never prompt the user — unmatched calls are allowed | Allow |
BypassPermissions | All tool calls are allowed regardless of rules | Allow |
Evaluation Order
When a tool call is evaluated, the PermissionEvaluator follows this 6-step process:
Step 1: Mode Short-Circuit
BypassPermissions→ Allow immediatelyPlanmode and tool isbash,write,edit, ornotebookedit→ Deny immediately
Step 2: Agent-Specific Overrides
If the agent has its own permissions block in the config, evaluate those rules first:
- Check deny rules → Deny if matched
- Check ask rules → Ask if matched
- Check allow rules → Allow if matched
Step 3: Global Deny Rules
Check project-level deny rules → Deny if matched
Step 4: Global Ask Rules
Check project-level ask rules → Ask if matched
Step 5: Global Allow Rules
Check project-level allow rules → Allow if matched
Step 6: Mode Default
If no rule matched, apply the mode's default decision:
Default→ AskAcceptEdits→ Allow for edit tools, Ask for othersDontAsk→ AllowBypassPermissions→ Allow
Permission Decision
The evaluation returns one of three decisions:
| Decision | Behavior |
|---|---|
Allow | Tool call proceeds |
Ask | Tool call requires user approval (via TUI or hook) |
Deny | Tool call is blocked; error returned to the agent |
Configuration
Permissions are configured at two levels:
Project Level
{
"permissions": {
"allow": ["Bash(npm run *)", "Bash(cargo test *)"],
"ask": ["Bash(git push *)"],
"deny": ["Bash(rm -rf /)"],
"default_mode": "default"
}
}
Agent Level
{
"agents": [
{
"name": "reviewer",
"prompt": "...",
"permissions": {
"allow": ["Read(*)"],
"deny": ["Write(*)", "Edit(*)", "Bash(*)"]
}
}
]
}
Agent-level rules take precedence over project-level rules (evaluated first in the evaluation order).
Related
- Configuration — How permissions are configured
- Tools — The tools that permissions control
- Hooks — Hook-based permission decisions