Skip to main content
Claude Code supports fine-grained permissions so that you can specify exactly what the agent is allowed to do and what it can’t. You can check permission settings into version control to share them with every developer in your organization, and each developer can customize their own.

Permission system

Claude Code uses a tiered permission system to balance power and safety. The table shows, for each tool type, whether Manual mode asks before the action runs. The other permission modes change which of these ask you; in auto mode a classifier reviews actions instead of you, and how the classifier evaluates actions lists which ones it sees. When you choose “Yes, and don’t ask again” and the approval saves permanently, such as for a Bash command or a WebFetch domain, Claude Code saves the rule to .claude/settings.local.json at the root of the git repository, resolved through worktrees to the main checkout. The rule applies to future sessions anywhere in that repository, including sessions started in subdirectories and in worktrees. A file-modification approval isn’t saved to the file: as the table shows, it lasts until the session ends. Outside a git repository, and when the repository root is your home directory, Claude Code saves the rule in the directory you started it from. Before v2.1.211, Claude Code always saved the rule in the starting directory, so an approval granted in a worktree or subdirectory didn’t apply to the rest of the repository. Rules that earlier versions saved in a subdirectory or worktree still apply to sessions started there. On a Bash or PowerShell permission prompt, press Ctrl+E to show an explanation of the command: what it does, why Claude is running it, and what could go wrong, labeled Low risk, Med risk, or High risk. Claude Code sends the command and Claude’s own description of the call to the model to generate the explanation only when you press Ctrl+E, not on every prompt. Showing the explanation doesn’t run the command; press Ctrl+E again to hide it. To turn the shortcut off, set permissionExplainerEnabled to false in ~/.claude.json.

Manage permissions

You can view and manage Claude Code’s tool permissions with /permissions. The dialog lists all permission rules and the settings.json file each rule comes from. You can open the dialog while Claude is working: when you add or remove a rule, Claude Code applies the change starting with Claude’s next tool call in the same turn. Before v2.1.234, Claude Code queued the command until the turn finished.
  • Allow rules let Claude Code use the specified tool without manual approval.
  • Ask rules prompt for confirmation whenever Claude Code tries to use the specified tool.
  • Deny rules prevent Claude Code from using the specified tool.
Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn’t change the order. A broad deny rule like Bash(aws *) blocks every matching call, including calls that also match a narrower allow rule like Bash(aws s3 ls), so a deny rule can’t carry allowlist exceptions. The same precedence applies between ask and allow: a matching ask rule prompts even when a more specific allow rule also matches the same call. Deny rules behave differently depending on whether they name a tool or scope a pattern within one. A bare tool name like Bash removes the tool from Claude’s context entirely, so Claude never sees it. Bare-name removal applies to every tool except EndConversation: a deny rule can’t remove it while any other tool remains, and an ask rule never prompts for it. A scoped rule like Bash(rm *) leaves the tool available and blocks matching calls when Claude attempts them.
Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or CLAUDE.md shape what Claude tries to do, but they don’t change what Claude Code allows. To grant or revoke access, use /permissions, the rules described here, a permission mode, or a PreToolUse hook.

Permission modes

Claude Code supports several permission modes that control how it approves tool calls. See Permission modes for when to use each one. To change the mode sessions start in, set defaultMode in your settings files. Which mode a session starts in covers the built-in default for each plan and what the VS Code extension reads.
bypassPermissions mode skips permission prompts, including for writes to protected paths such as .git and .claude. The cross-session messaging safeguards still apply. Only use this mode in isolated environments like containers or VMs where Claude Code can’t cause damage.
To prevent bypassPermissions or auto mode from being used, set permissions.disableBypassPermissionsMode or permissions.disableAutoMode to "disable" in any settings file. These are most useful in managed settings where they can’t be overridden.

Permission rule syntax

Permission rules follow the format Tool or Tool(specifier).

Match all uses of a tool

To match all uses of a tool, use only the tool name without parentheses: Bash(*) is equivalent to Bash and matches all Bash commands. As a deny rule, both forms remove the tool from Claude’s context.

Use specifiers for fine-grained control

Add a specifier in parentheses to match specific tool uses:

Match by input parameter

Deny and ask rules can match a top-level input parameter on any tool with Tool(param:value). The rule matches when Claude calls the tool with that parameter set to that exact value. An allow rule for one parameter value wouldn’t establish that the call is safe overall, so allow rules continue to use each tool’s own specifier syntax. This works for any scalar parameter the tool accepts: Parameter matching follows these rules:
  • The parameter name must be a direct field of the tool’s input, such as model on the Agent tool. Fields nested inside an object or array are not matchable
  • Each rule names one parameter. To gate on both model and isolation, write two rules, Agent(model:opus) and Agent(isolation:worktree), rather than combining them in one rule
  • The value supports * as a wildcard that matches any sequence of characters, so Agent(isolation:*) matches any explicit isolation value. Without * the match is exact
  • A parameter the model omits is never matched, so Agent(model:*) doesn’t match a call that leaves model unset
  • The value is compared against the literal input Claude sends, before any normalization. Agent(model:opus) matches the alias opus but not a full model ID. Run with --verbose to see the exact parameter names and values in each tool call
  • Whitespace around the colon is ignored
You can’t match a tool’s primary content field this way: command for Bash and PowerShell, file_path for Read, Edit, and Write, path for Grep and Glob, notebook_path for NotebookEdit, and url for WebFetch. A rule like Bash(command:rm *) would be bypassable by a compound command, so Claude Code ignores it and emits a startup warning. Use Bash(rm *), Read(./path), or WebFetch(domain:host) instead.

Wildcard patterns

Bash rules support glob patterns with *. This configuration allows npm and git commit commands while blocking git push: