Permissions
Control which tools can execute automatically, require confirmation, or are blocked entirely.
Overview
Permissions provide fine-grained control over tool execution. You can configure which tools are auto-approved (run without asking), which require user confirmation, and which are completely blocked.
Permissions are evaluated in this order: **Deny → Allow → Ask**. Deny patterns take priority, then allow patterns, and anything else defaults to asking for user confirmation.
Configuration
agents:
root:
model: openai/gpt-4o
description: Agent with permission controls
instruction: You are a helpful assistant.
permissions:
# Auto-approve these tools (no confirmation needed)
allow:
- "read_file"
- "read_*" # Glob patterns
- "shell:cmd=ls*" # With argument matching
# Block these tools entirely
deny:
- "shell:cmd=sudo*"
- "shell:cmd=rm*-rf*"
- "dangerous_tool"
Pattern Syntax
Permissions support glob-style patterns with optional argument matching:
Simple Patterns
| Pattern | Matches |
|---|---|
shell |
Exact match for shell tool |
read_* |
Any tool starting with read_ |
mcp:github:* |
Any GitHub MCP tool |
* |
All tools |
Argument Matching
You can match tools based on their argument values using tool:arg=pattern syntax:
permissions:
allow:
# Allow shell only when cmd starts with "ls" or "cat"
- "shell:cmd=ls*"
- "shell:cmd=cat*"
# Allow edit_file only in specific directory
- "edit_file:path=/home/user/safe/*"
deny:
# Block shell with sudo
- "shell:cmd=sudo*"
# Block writes to system directories
- "write_file:path=/etc/*"
- "write_file:path=/usr/*"
Multiple Argument Conditions
Chain multiple argument conditions with colons. All conditions must match:
permissions:
allow:
# Allow shell with ls in current directory
- "shell:cmd=ls*:cwd=."
deny:
# Block shell with rm -rf anywhere
- "shell:cmd=rm*:cmd=*-rf*"
Glob Pattern Rules
Patterns follow filepath.Match semantics with some extensions:
*— matches any sequence of characters (including spaces)?— matches any single character[abc]— matches any character in the set[a-z]— matches any character in the range
Matching is case-insensitive.
Trailing wildcards like sudo* match any characters including spaces, so sudo* matches sudo rm -rf /.
Decision Types
| Decision | Behavior |
|---|---|
| Allow | Tool executes immediately without user confirmation |
| Ask | User must confirm before tool executes (default) |
| Deny | Tool is blocked and returns an error to the agent |
Examples
Read-Only Agent
Allow all read operations, block all writes:
permissions:
allow:
- "read_file"
- "read_multiple_files"
- "list_directory"
- "directory_tree"
- "search_files_content"
deny:
- "write_file"
- "edit_file"
- "shell"
Safe Shell Agent
Allow specific safe commands, block dangerous ones:
permissions:
allow:
- "shell:cmd=ls*"
- "shell:cmd=cat*"
- "shell:cmd=grep*"
- "shell:cmd=find*"
- "shell:cmd=head*"
- "shell:cmd=tail*"
- "shell:cmd=wc*"
deny:
- "shell:cmd=sudo*"
- "shell:cmd=rm*"
- "shell:cmd=mv*"
- "shell:cmd=chmod*"
- "shell:cmd=chown*"
MCP Tool Permissions
Control MCP tools by their qualified names:
permissions:
allow:
# Allow all GitHub read operations
- "mcp:github:get_*"
- "mcp:github:list_*"
- "mcp:github:search_*"
deny:
# Block destructive GitHub operations
- "mcp:github:delete_*"
- "mcp:github:close_*"
Combining with Hooks
Permissions work alongside hooks. The evaluation order is:
- Check deny patterns — if matched, tool is blocked
- Check allow patterns — if matched, tool is auto-approved
- Run pre_tool_use hooks — hooks can allow, deny, or ask
- If no decision, ask user for confirmation
Hooks can override allow decisions but cannot override deny decisions.
Permissions are enforced client-side. They help prevent accidental operations but should not be relied upon as a security boundary for untrusted agents. For stronger isolation, use sandbox mode.