Safe, explicit permission configuration for real production codebases.
The .claude/settings.json file controls what Claude Code can and cannot do in your project. Get this right and you have a powerful, safe operator. Get it wrong and you have either an overly restricted Claude that asks permission for everything, or an unrestricted Claude that can cause real damage.
⬡ What you'll build
Claude Code evaluates every tool call against your permission rules before running it. The evaluation order:
The pattern syntax uses glob-style matching:
Bash(git *) # any git command
Bash(npm run *) # any npm run command
Bash(rm -rf *) # any rm -rf (commonly denied)
Bash(sudo *) # any sudo (commonly denied)
Read(**/*.ts) # read any TypeScript file
Write(src/**) # write anything under src/This is the starting configuration for a Next.js/Node.js project. Adapt from here:
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git checkout *)",
"Bash(git branch *)",
"Bash(git stash *)",
"Bash(node *)",
"Bash(npm run *)",
"Bash(npx *)",
"Bash(cat *)",
"Bash(ls *)",
"Bash(mkdir -p *)",
"Bash(cp *)",
"Bash(mv *)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)",
"Bash(git push --force*)",
"Bash(git reset --hard *)",
"Bash(chmod *)",
"Bash(chown *)",
"Bash(curl * | bash)",
"Bash(wget * | bash)"
]
}
}⚠rm -rf is always denied
Even on your own machine, denying rm -rf * in Claude's permissions is the right call. If Claude needs to delete something, it should be specific: rm specificfile.json, not a recursive glob. The deny rule forces specificity.
The allow list isn't about trust — it's about reducing friction for safe operations. Commands you allow skip the confirmation prompt entirely, which matters in long agentic sessions where Claude is running dozens of tool calls.
Allow freely: reading, searching, safe git operations, running your own build scripts, running tests.
Always deny: recursive deletion, sudo, force-push, piping remote content to a shell, anything that modifies system configuration.
Leave at "ask": anything specific to your project that isn't covered above — Claude will prompt and you can decide in context.
Settings can live at two levels:
Settings file locations
~/.claude/settings.jsonGlobal settings — apply to every project on this machine.
.claude/settings.jsonProject settings — override global settings for this repo. Commit this file.
.claude/settings.local.jsonLocal overrides — not committed to git. Use for personal preferences that shouldn't be shared.
Recommended pattern: Keep restrictive global settings (deny the dangerous stuff), and use project settings to expand what's allowed for that specific project's commands.
Don't guess whether your permissions are correct. Test them explicitly:
If Claude asks for permission on something you intended to allow, check:
* for wildcards, not ** for single-argument matching)Python automation project:
{
"permissions": {
"allow": [
"Bash(python *)",
"Bash(python3 *)",
"Bash(pip show *)",
"Bash(pytest *)",
"Bash(git *)"
],
"deny": [
"Bash(pip install *)",
"Bash(sudo *)",
"Bash(rm -rf *)"
]
}
}WordPress automation project:
{
"permissions": {
"allow": [
"Bash(python *)",
"Bash(curl -X GET *)",
"Bash(curl -X POST *)",
"Bash(git *)",
"Bash(cat *)",
"Bash(ls *)"
],
"deny": [
"Bash(curl -X DELETE *)",
"Bash(sudo *)",
"Bash(rm -rf *)",
"Bash(mysql *)"
]
}
}Note: denying curl -X DELETE doesn't prevent Claude from deleting via your Python scripts — it only prevents direct curl DELETE calls. Your automation layer handles deletion with its own safety checks.
Failure Pattern — Deny list too broad
✕ Before (broken pattern)
"deny": [ "Bash(*)" ] // Claude asks for permission before every single // command. Agentic tasks become unusable.
✓ After (production pattern)
"deny": [ "Bash(rm -rf *)", "Bash(sudo *)", "Bash(git push --force*)" ] // Only genuinely dangerous patterns are blocked. // Everything else either auto-runs or asks once.
Lesson: Over-restricting permissions doesn't make you safer — it makes agentic tasks unusable. Block the dangerous patterns specifically.
Permissions are correctly configured when:
Claude Code Settings Reference
Complete reference for all settings.json options, permission patterns, and file locations.