/permissions - Control What Tools Claude Code Can Use
Allow, deny, or gate specific tools and commands in Claude Code. Set boundaries per project so Claude works the way you want.
What is it
Claude Code comes with a bunch of built-in tools: it can read files, edit code, run shell commands, fetch web pages, and more. /permissions lets you control which of those tools Claude can use, and how. You can allow things automatically (no prompts), require approval every time, or block them entirely.
Think of it as a bouncer list for Claude's toolbox. You decide who gets in, who gets checked at the door, and who's banned.
What problems it solves
You're working on a project with a production database config sitting in .env. Claude keeps asking to read it, and every time you have to say no. You want to just block it once so Claude stops trying.
Or you've got a team of developers using Claude Code, and you don't want anyone's Claude accidentally running git push --force or rm -rf on a shared repo. You need guardrails that apply to everyone, checked into version control.
Or you trust Claude to run your test suite and linter without asking every single time, but you still want a prompt before it touches anything else. Right now you're clicking "Yes" on npm test thirty times a day.
How to use it
Type /permissions in Claude Code to see the interactive UI. It shows all your current rules and where they come from.
Rules come in three flavors:
- Allow: Claude uses the tool without asking. No prompt.
- Ask: Claude asks for your approval each time. This is the default for most tools.
- Deny: Claude can't use the tool at all. Blocked.
Rules are checked in order: deny wins over ask, ask wins over allow. If something is denied anywhere, nothing else can override it.
Quick setup via settings.json
The fastest way to set up rules is in your project's .claude/settings.json. This gets checked into version control so the whole team gets the same guardrails:
{
"permissions": {
"allow": [
"Bash(npm test *)",
"Bash(npm run lint)",
"Bash(git status)",
"Bash(git diff *)"
],
"deny": [
"Bash(git push --force *)",
"Bash(rm -rf *)",
"Read(./.env)"
]
}
}Rule syntax
Rules follow the format Tool or Tool(specifier):
Bash # All shell commands
Bash(npm run build) # Exact command
Bash(npm run *) # Wildcard, anything starting with "npm run "
Read(./.env) # Specific file
Edit(/src/**/*.ts) # All TypeScript files under src/
WebFetch(domain:example.com) # Web requests to a specific domainThe wildcard * works like you'd expect. Bash(npm *) matches npm test, npm run build, etc. A space before the * matters: Bash(ls *) matches ls -la but not lsof.
Read(./.env) blocks Claude's Read tool but doesn't stop cat .env in Bash. If you need OS-level file protection, look into Claude Code's sandboxing feature.Permission modes
You can also change Claude's overall permission mode with Shift+Tab during a session:
- Default: prompts for file edits and commands
- Accept Edits: auto-approves file edits, still asks for commands
- Plan Mode: read-only, Claude can analyze but not change anything
- Auto: evaluates actions with background safety checks (research preview)
Pro tips
When you approve a command with "Yes, don't ask again," it saves a permanent allow rule for that specific command in your project. These pile up over time. Run /permissions occasionally to audit what's been auto-allowed and clean up anything you don't want there anymore.
The dontAsk permission mode is great for CI/CD pipelines. It auto-denies everything except what you've explicitly allowed, so Claude can only run pre-approved commands. No human in the loop needed, and no surprise tool calls.