User + Project = combined rules
Your User scope has allow: ["Read(./src/**)"]. Your Project scope has allow: ["Bash(npm run test *)"]. When both sources are loaded, both allow rules apply in that project.
Claude Code permissions guide
Understand allow, ask, and deny rules, scope merging, wildcard patterns, and how to verify active rules.
Before an applicable tool call runs, Claude Code compares it with the active permission rules and the current permission mode.
Bash(npm run lint), Read(./src/**).Bash(git push *).Read(./.env). A matching deny rule wins even if another loaded scope allows the same action.Claude Code checks matching rule categories in the order deny → ask → allow. The first matching category decides, and a more-specific rule does not change this order. If no rule matches, behavior falls back to the active permission mode: default or manual generally prompts, while other modes may approve or deny automatically.
Safe permissions starter
{
"permissions": {
"allow": [
"Bash(npm run test *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)"
]
}
}
The permission example approves one narrow test command and denies common secret locations. Keep your initial set minimal and expand only when you can name the exact command or path you need.
Array-valued permission rules concatenate and deduplicate across loaded scopes instead of being replaced by a single winner. General source precedence is Managed → command-line → Local → Project → User.
Your User scope has allow: ["Read(./src/**)"]. Your Project scope has allow: ["Bash(npm run test *)"]. When both sources are loaded, both allow rules apply in that project.
A deny rule in any loaded scope blocks a matching action even if another scope has an allow rule. This follows permission category order rather than choosing the most-specific rule.
If your User scope has allow: ["Bash(rm *)"] and your Project scope has ask: ["Bash(rm *)"], the matching ask rule prompts because ask is checked before allow. Specificity does not change that order.
/permissions shows the resolved rules and the settings file that contributed each rule. Run it after changing any scope to confirm that the loaded result matches your intention.
Inspect the resolved rules after every change, then test the specific action you intended to control.
Review the resolved allow, ask, and deny rules and the settings file that contributed each rule.
Rules are evaluated deny → ask → allow, and the first matching category decides. If you see an unexpected result, look for a match in an earlier category.
Run a single Bash command or Read action and observe whether Claude Code prompts, approves, or blocks. Compare the result with your intended rule and active permission mode.
/permissions shows the source settings file for each rule. This reveals whether a rule from an unexpected scope is affecting the result.
Test in terminal, VS Code, and JetBrains if you use multiple surfaces. The same settings may be available, but the working directory and environment context can differ.
Local diagnostic
The browser-only checker can flag JSON syntax errors, exact allow/deny conflicts, and likely path, scope, or precedence causes. It does not replace Claude Code's /permissions view or the official settings schema.
Allow removes the approval prompt. Ask keeps an explicit approval point. Deny blocks the action. Claude Code checks matching rule categories in deny, ask, allow order, so the first matching category decides. More-specific rules do not change that order. If no rule matches, behavior falls back to the active permission mode: default or manual generally prompts, while other modes may approve or deny automatically.
Array-valued permission rules are concatenated and deduplicated across loaded scopes. General source precedence is Managed, command-line, Local, Project, User, but a deny rule in any loaded scope still wins over ask or allow for a matching action. Use /permissions to see the resolved rules and their source settings files.
Run /permissions inside Claude Code. It shows the resolved allow, ask, and deny rules along with the settings file that contributed each rule.
Start with an exact command or path, such as Bash(npm run lint) or Read(./src/**). Use trailing wildcards deliberately: Bash(npm run test *) matches that command prefix plus arguments, and the space before * creates a word boundary. Keep sensitive paths in deny and verify the result with /permissions.
Sources last reviewed August 11, 2026.