Skip to content

Permission Precedence

Claude Code uses a layered permission system. Understanding how these layers interact prevents unexpected behavior when combining allow, ask, and deny rules.

Permissions are defined at three levels:

LayerLocationScope
Tool-levelpermissions.allow, permissions.ask, permissions.denyEntire tool (e.g., Bash)
Content-levelpermissions.allow, permissions.ask, permissions.denySpecific tool invocations (e.g., Bash(rm *))
Skill frontmatterallowed-tools: in SKILL.mdTools available within a skill

Content-level rules override tool-level rules. More specific patterns take priority over less specific ones.

The evaluation order is:

1. deny (content-level) ← highest priority
2. ask (content-level)
3. allow (content-level)
4. deny (tool-level)
5. ask (tool-level)
6. allow (tool-level) ← lowest priority

Consider this configuration in .claude/settings.json:

{
"permissions": {
"allow": ["Bash"],
"ask": ["Bash(rm *)"]
}
}

Behavior: All Bash commands run without prompting, except commands matching rm *, which trigger a permission prompt.

CommandRule MatchedResult
Bash(ls -la)allow: ["Bash"] (tool-level)Runs automatically
Bash(npm test)allow: ["Bash"] (tool-level)Runs automatically
Bash(rm -rf dist/)ask: ["Bash(rm *)"] (content-level)Prompts for approval
Bash(rm temp.txt)ask: ["Bash(rm *)"] (content-level)Prompts for approval

The content-level ask for Bash(rm *) overrides the tool-level allow for Bash because content-level rules are more specific.

Note: Prior to Claude Code v2.1.27, allow: ["Bash"] would allow all Bash commands regardless of content-level ask rules. This was fixed so that content-level rules always take precedence.

FileApplies ToManaged By
~/.claude/settings.jsonAll projects (user-level)User
.claude/settings.jsonThis projectsequant (package-managed)
.claude/.local/settings.jsonThis project (overrides)User
SKILL.md frontmatterWithin a specific skillSkill author
{
"permissions": {
"deny": ["Read(./.entire/metadata/**)"]
}
}
---
allowed-tools:
- Bash(npm run deploy:*)
- Bash(gh workflow run:*)
---

Skill allowed-tools restrict which tools a skill can use. They do not override project or user-level deny rules.

Allow a tool but restrict dangerous operations

Section titled “Allow a tool but restrict dangerous operations”
{
"permissions": {
"allow": ["Bash"],
"ask": ["Bash(rm *)", "Bash(git push *)"],
"deny": ["Bash(rm -rf /)"]
}
}
{
"permissions": {
"deny": ["Read(.env)", "Read(.env.local)", "Read(**/credentials.*)"]
}
}