[Feature] Mode-specific permissions: Separate command allowlists for read-only vs normal modes
(Like #1946 but with 20/20 hindsight and 🤖 Claude Code's architectural review -
turns out "read-only" meant more than we initially explained 🔍)
Problem Statement
Currently, Claude Code's permission system has a single allowlist/denylist that applies across all operational modes. This creates a fundamental limitation: users cannot specify different sets of allowed commands for different modes (e.g., plan mode vs normal mode).
This is particularly problematic because:
- In plan mode, users want Claude to explore and understand the codebase WITHOUT making changes
- Some commands are safe for exploration (
ls,cat,grep) while others have side effects (rm,git commit,npm install) - There's no way to allow a command in normal mode but restrict it in plan mode
Current Behavior
{
"permissions": {
"allow": ["Bash(ls:*)", "Bash(cat:*)", "Bash(rm:*)", "Bash(git:*)", "Read", "Write"], // Applies to ALL modes
"deny": ["Bash(sudo:*)"]
}
}
In plan mode, Claude can still run rm or git commit if they're in the allowlist, which defeats the purpose of a read-only planning phase.
Proposed Solution
Introduce mode-specific permission configurations:
{
"permissions": {
"allow": ["Bash(ls:*)", "Bash(cat:*)", "Bash(grep:*)", "Bash(git:*)", "Bash(npm:*)", "Bash(rm:*)", "Bash(mv:*)", "Read", "Write", "Edit"], // Normal mode
"allowReadonly": ["Bash(ls:*)", "Bash(cat:*)", "Bash(grep:*)", "Bash(git status:*)", "Bash(git log:*)", "Bash(find:*)", "Read", "Grep", "Glob", "LS"], // Plan mode & future read-only modes
"deny": ["Bash(sudo:*)"] // Always denied
}
}
Implementation Details
- Backwards Compatibility: If
allowReadonlyis not specified, fall back to current behavior (useallowfor all modes)
- Mode Detection:
- Plan mode: Use
allowReadonlylist - Normal mode: Use
allowlist - Future
/askmode: UseallowReadonlylist
- Command Matching: Support both exact matches and prefix matches:
"Bash(git:*)"allows all git subcommands"Bash(git status:*)"allows only that specific git subcommand
- Precedence Rules:
denylist always takes precedence- In read-only modes: only commands in
allowReadonlyare permitted - In normal mode: only commands in
alloware permitted
Use Cases
- Safe Exploration: Users can freely explore codebases in plan mode without risk of modifications
- Granular Control: Power users can fine-tune which git subcommands are available in each mode
- Security: Reduces risk of accidental destructive operations during planning phases
Example Configuration
{
"permissions": {
"allow": [
"Bash(ls:*)", "Bash(cat:*)", "Bash(grep:*)", "Bash(find:*)", "Bash(rg:*)", // Read operations
"Bash(git:*)", "Bash(npm:*)", "Bash(yarn:*)", "Bash(make:*)", // Build/version control
"Bash(rm:*)", "Bash(mv:*)", "Bash(cp:*)", "Bash(mkdir:*)", // File operations
"Bash(python:*)", "Bash(node:*)", "Bash(cargo:*)", // Execution
"Read", "Write", "Edit", "MultiEdit", "Grep", "Glob", "LS" // Claude Code tools
],
"allowReadonly": [
"Bash(ls:*)", "Bash(cat:*)", "Bash(grep:*)", "Bash(find:*)", "Bash(rg:*)", // Read operations only
"Bash(git status:*)", "Bash(git log:*)", "Bash(git diff:*)", "Bash(git branch:*)", // Read-only git commands
"Bash(npm list:*)", "Bash(yarn list:*)", "Bash(cargo tree:*)", // Read-only package commands
"Bash(which:*)", "Bash(pwd)", "Bash(echo:*)", "Bash(env:*)", // Safe system commands
"Read", "Grep", "Glob", "LS", // Read-only Claude Code tools
"WebFetch", "WebSearch", "NotebookRead" // Information gathering
],
"deny": ["Bash(sudo:*)", "Bash(chmod:*)", "Bash(chown:*)"]
}
}
Related Issues
- #1946 - Original proposal that may have appeared to focus primarily on adding an
/askcommand, but was actually trying to address this deeper architectural need: allowing Claude Code to work agentically with different sets of tools/commands marked as safe for read-only operations vs. normal operations
To Think About (Future Considerations)
While out of scope for this issue, this concept could extend to MCP (Model Context Protocol) integrations:
- MCP servers could declare which of their operations are read-only
- Users should be able to override these declarations for security reasons
- Similar
allowReadonlyvsallowpatterns could apply to MCP tools
However, this issue focuses specifically on the command allowlist in Claude Code's core permission system.
Benefits
- Safety: Clear separation between exploration and modification commands
- Flexibility: Users can customize their workflow based on their risk tolerance
- Future-proof: Enables implementation of additional read-only modes (
/ask,/review, etc.) - Intuitive: Aligns with user expectations that "plan mode" shouldn't modify files
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗