Your First Permission Rule
By default, Claude asks for your approval before editing files, running commands, or fetching URLs. Permission rules let you pre-approve (or permanently block) specific actions so Claude can work without interrupting you every time.
The two-minute setup
Section titled “The two-minute setup”-
Open (or create)
.claude/settings.jsonin your project root. -
Add your allow rules:
{"permissions": {"allow": ["Write(src/**)","Bash(npm run *)"]}} -
Claude now works without interrupting you.
Any file under
src/can be edited silently. Anynpm runscript can be executed without a prompt.
Before and after
Section titled “Before and after”Before (no rules): Every time Claude wants to edit a file, you see:
Claude wants to edit src/utils/format.ts[Allow once] [Allow for this session] [Allow always] [Deny]After (with Write(src/**) in allow): Claude edits the file silently. You stay in flow.
How permission evaluation works
Section titled “How permission evaluation works”Rules are checked in this order — the first matching condition wins:
- Hard block? — Is this a hardcoded dangerous pattern (e.g.
rm -rf /)? If yes → blocked with no override possible. - Hook block? — Does a
PreToolUsehook return exit2? If yes → blocked by hook. - Deny rule match? — Does a
denyrule in settings match this tool call? If yes → denied. - Allow rule match? — Does an
allowrule match? If yes → allowed silently, no prompt shown. - Default mode fallback (no rule matched):
| Mode | What happens |
|---|---|
auto | Classifier decides: safe actions auto-approved, risky ones prompt you |
default | Ask you every time |
bypassPermissions or dontAsk | Allowed silently |
Rule syntax
Section titled “Rule syntax”Rules follow the pattern Tool(pattern). The pattern depends on the tool:
| Tool | Pattern | Example |
|---|---|---|
Write | File glob | Write(src/**) — any file under src/ |
Read | File glob | Read(~/.zshrc) — your zshrc file |
Edit | File glob | Edit(**/*.ts) — any TypeScript file |
Bash | Command prefix | Bash(npm *) — any npm command |
Bash | Exact command | Bash(npm run test) — exactly this command |
WebFetch | Domain | WebFetch(domain:anthropic.com) — this domain and subdomains |
WebSearch | (none) | WebSearch — all web searches |
Glob patterns for file rules
Section titled “Glob patterns for file rules”src/** → any file anywhere under src/src/*.ts → .ts files directly in src/ (not subdirectories)**/*.test.ts → any .test.ts file anywhere~/.zshrc → your home directory zshrcBash patterns
Section titled “Bash patterns”Bash(npm *) → any npm command (npm install, npm run test, etc.)Bash(npm run *) → any npm run script, but not npm installBash(git status) → exactly "git status", nothing elseBash(* install) → any install command (npm install, pip install, etc.)allow vs. deny
Section titled “allow vs. deny”{ "permissions": { "allow": [ "Write(src/**)" ], "deny": [ "Write(src/secrets/**)", "Bash(rm *)" ] }}allow— Claude proceeds without askingdeny— Claude is blocked entirely (can’t even ask you)
Deny rules are evaluated first. In this example, Write(src/secrets/**) would be blocked even though Write(src/**) allows the parent directory.
Permission modes
Section titled “Permission modes”For bigger changes to Claude’s default behavior, use defaultMode:
{ "permissions": { "defaultMode": "auto" }}| Mode | Behavior |
|---|---|
default | Ask for everything not explicitly allowed (safest) |
auto | Use heuristics to auto-approve “safe” actions; ask for risky ones |
acceptEdits | Auto-approve file edits; ask for shell commands |
dontAsk | Never ask — approve everything not explicitly denied |
bypassPermissions | Skip all permission checks (use only in trusted automation) |
plan | Claude plans actions but never executes them |
Recommendation for most junior developers: Start with default (the default). Add specific allow rules for things you approve of often. Only switch to auto once you’ve used Claude enough to trust its judgment in your project.
Where to put settings.json
Section titled “Where to put settings.json”| Location | Scope | Notes |
|---|---|---|
.claude/settings.json | Project only | Checked into git. Shared with your team. |
~/.claude/settings.json | All your projects | Personal preferences. Never checked in. |
.claude/settings.local.json | Project only | Personal overrides. Add to .gitignore. |
For permission rules that apply to one project, use .claude/settings.json.
Troubleshooting
Section titled “Troubleshooting”Claude still asks even with an allow rule
- Check the rule syntax —
Write(src/**)notWrite(src/*)for recursive match - Make sure your file is at
.claude/settings.json(notclaude/settings.json) - Check that the JSON is valid (no trailing commas, correct quotes)
Claude was blocked by a deny rule I didn’t expect
- Deny rules check the full path — if you deny
Write(/tmp/*)and allowWrite(src/**), a file in/tmp/is still denied - Check for rules in
~/.claude/settings.json(your global settings might have deny rules)
Next steps
Section titled “Next steps”- Permissions/rule-grammar.md — full rule syntax reference
- Permissions/permission-modes.md — all 6 modes explained
- Permissions/rule-scopes.md — how managed/project/user rules interact
- Settings/permissions-security.md — all permission-related settings keys