Rules: fine-grained control on top of modes
Modes set the overall dial. Rules carve out precise exceptions: always allow pnpm test, always ask before git push, never read .env.
{
"permissions": {
"allow": [
"Bash(pnpm test *)",
"Bash(git status *)",
"Bash(git diff *)",
"WebFetch(domain:docs.stripe.com)"
],
"ask": ["Bash(git push *)", "Bash(npm publish *)"],
"deny": ["Read(./.env)", "Read(./.env.*)", "Edit(./migrations/applied/**)", "Bash(rm -rf *)"]
}
}Rule syntax cheat sheet
| Rule | Matches |
|---|---|
Bash | Every shell command |
Bash(npm run test *) | Commands starting with npm run test |
Read(./.env) | Reading .env in the project root |
Edit(./src/**) | Edits anywhere under src/ |
WebFetch(domain:example.com) | Fetching pages from that domain |
mcp__github__* | Every tool from the github MCP server |
Skill(deploy) / Agent(Explore) | A specific skill or subagent type |
Bash(git diff *) matches git diff followed by arguments. Bash(git diff*) also matches git diff-index and anything else that starts with those letters. Include the space unless you really mean a prefix.
How rules combine
- Deny beats ask beats allow. If anything denies, it's denied.
- Rules from all settings scopes are combined.
- Deny rules hold in every permission mode.
pnpm test and pnpm lint, run dozens of times a day.git push to the remote..env or the secrets/ folder.terraform apply against production.Managing rules interactively
/permissions lists every active rule, shows which settings file it came from, and lets you add or remove rules. When you choose "Yes, don't ask again" at a prompt, Claude Code writes the matching allow rule for you.
If you're approving the same safe command over and over, add an allow rule for exactly that command pattern. Allow Bash(pnpm test *), not Bash.
Sandboxing: limits enforced by the OS
Rules decide whether a command runs. Sandboxing limits what a command can touch once it's running. With /sandbox enabled, Bash commands run inside an OS-level sandbox that restricts:
- Filesystem: writes are limited to your working directories.
- Network: outbound connections are limited to hosts you approve.
That means even if a command is allowed, it can't scribble outside your project or phone home to an unapproved server. Sandboxing and rules work best together: rules for intent, sandbox for blast radius.
Write a permission rule that blocks reading the .env file in the project root
Check your understanding
Which rule pre-approves only test commands that start with pnpm test?
What's the order of precedence for rules?
What does sandboxing add on top of permission rules?
Why is Bash(git diff*) riskier than Bash(git diff *)?