
Permissions and modes: deciding what to hand over to Claude Code
Permission modes that set how often it asks, the evaluation order of allow/ask/deny rules, and the wildcard pitfall.
Modes and rules let you move step by step from “confirm every time” to “hand it over.” What can be enforced is the rules, not your instructions; that is the key point.
What gets confirmed by default
Claude Code decides whether to ask for confirmation by the kind of operation. Reading alone needs no confirmation inside the working directory. Running commands and changing files generally ask first. How long a “don’t ask again” choice lasts also depends on the operation.
| Operation | Example | Confirmation |
|---|---|---|
| Reading | Reading files, Grep | Not needed inside the working directory |
| Bash commands | Running the shell | Required (except a built-in set of read-only commands) |
| File changes | Edit / write | Required (“don’t ask again” lasts until the session ends) |
| Web fetch | WebFetch | Required (except preapproved documentation domains) |
| Web search | WebSearch | Required |
Permission modes
A mode switches how much confirmation is skipped. Switch with Shift+Tab during a session, or specify it at startup, such as claude --permission-mode plan. To always start in the same mode, set defaultMode in a settings file.
| Mode | Behavior |
|---|---|
| default | Asks the first time each tool is used (shown as “Manual” in the CLI) |
| acceptEdits | Automatically allows file edits and basic file operations such as mkdir, mv and cp in the working directory |
| plan | Only reads and investigates; does not edit source files |
| auto | Skips routine confirmations; a background classifier checks that an action matches your request before it runs |
| dontAsk | Automatically denies every operation that would need confirmation. Rules you allowed in advance still work |
| bypassPermissions | Skips confirmation (see the warning below) |
allow, ask and deny rules
To decide more finely than modes allow, write rules. allow permits without confirmation, ask confirms every time, and deny forbids. /permissions lists all rules and which settings file each one comes from. Evaluation runs deny, then ask, then allow, and the first match is the result. So you cannot carve an exception out of a broad deny with a narrower allow.
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)",
"Read(./.env)"
]
}
}The wildcard pitfall
In a Bash rule, * matches any text, including spaces. Put the * after the subcommand. Bash(git log *) allows only git log, but Bash(git *) allows every git command. An allow rule with * before the subcommand (for example Bash(git * main)) triggers a warning at startup. Also, a rule matches the text of the command Claude wrote. So even with a deny rule (Bash(git push *)), a different spelling such as git -C . push does not match.
- Bash(npm run build) matches only npm run build (it does not match once you add --watch)
- Bash(npm run *) matches npm run build and npm run test --watch, but not npm install
- For operations that must never run, don’t rely on deny alone; also protect them with something like a PreToolUse hook
Settings precedence
Permission rules follow the same precedence as other settings, and managed settings distributed by an organization are the strongest. An operation denied at any level can’t be allowed at another. Even if user settings allow something, project settings that deny it block it. Conversely, a deny in user settings is stronger than an allow in project settings.
Instructions don’t change permissions
Permission rules are enforced by Claude Code, not by the model. Writing “don’t run this command” in a prompt or CLAUDE.md affects what Claude tries, but not what Claude Code allows. To change what is allowed or forbidden reliably, use /permissions, rules, a permission mode, or a PreToolUse hook.
This distinction connects to the CLAUDE.md section of the previous article: requests go in CLAUDE.md, prohibitions go in permission rules.
Use bypassPermissions only in isolated environments
In bypassPermissions mode, all confirmation is skipped, including writes to protected paths such as .git and .claude. Use it only in environments where it doesn’t matter if Claude Code breaks things, such as containers or VMs. To stop this mode or auto mode from being used, set permissions.disableBypassPermissionsMode or permissions.disableAutoMode to "disable". Put in managed settings, they can’t be overridden by users.