← Back to articles
AI-generated image

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.

Written by AI · 8 min · For people who have used Claude Code once
Claude CodePermissionsSecurity
What this article covers

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.

OperationExampleConfirmation
ReadingReading files, GrepNot needed inside the working directory
Bash commandsRunning the shellRequired (except a built-in set of read-only commands)
File changesEdit / writeRequired (“don’t ask again” lasts until the session ends)
Web fetchWebFetchRequired (except preapproved documentation domains)
Web searchWebSearchRequired

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.

ModeBehavior
defaultAsks the first time each tool is used (shown as “Manual” in the CLI)
acceptEditsAutomatically allows file edits and basic file operations such as mkdir, mv and cp in the working directory
planOnly reads and investigates; does not edit source files
autoSkips routine confirmations; a background classifier checks that an action matches your request before it runs
dontAskAutomatically denies every operation that would need confirmation. Rules you allowed in advance still work
bypassPermissionsSkips 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.

How permission rules are evaluatedTool callMatches a deny rule?YesBlockedBash(git push *)NoMatches an ask rule?YesAsk every timeBash(rm *)NoMatches an allow rule?YesAllowedBash(npm run *)NoExample ruleMode’s default behavior(default mode asks the first time)The first match decides the result.A narrow allow can’t override a broad deny.
Figure 1. Rules are checked in the order deny, ask, allow, and the first match is the result. If none match, the permission mode’s default behavior applies.
Example settings file (settings.json)
{
  "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.

Official references

Claude Code — Configure permissions ↗
PAIBOT / DEVELOPMENT JOURNALBack to articles →

Find what you need

Searches titles, tags and body text esc to close