Who this is for and what you will be able to do
This guide is for developers who want to decide which actions Claude Code runs without asking, which ones need approval, and which ones it must never run. When you finish, you will be able to write a permissions configuration, explain the order in which allow, ask, and deny rules are checked, and tell whether a rule will actually block the command you have in mind.[1]
How the permission layers work
Claude Code uses a tiered permission system. Read-only operations, such as file reads and Grep, need no approval inside the working directory and additional directories. Bash commands, file edits, WebFetch, and WebSearch need approval, except for a built-in set of read-only commands.[1]
Permission rules can be checked into version control, so every developer on a team shares the same baseline. Each developer can still customize their own settings.[1]
What "Yes, and don't ask again" does
When you choose "Yes, and don't ask again" for a Bash command or a WebFetch domain, Claude Code saves a permanent rule to .claude/settings.local.json at the root of the git repository. The rule then applies to future sessions anywhere in that repository.[1]
If you approve a compound command such as git status && npm test, Claude Code does not save one rule for the whole string. It saves a separate rule for each subcommand that needed approval, so npm test is recognized in future.[1]
Some prompts offer only a one-time approval, with no "don't ask again" option. Claude Code offers the persistent options only when the prompt can show everything they would allow. For those prompts, approve the action once each time.[1]
Allow, ask, and deny
An allow rule lets Claude Code use a tool without manual approval. An ask rule prompts for confirmation every time. A deny rule prevents the tool from being used.[1]
Rules are evaluated in the order deny, then ask, then allow. The first match decides the outcome, and how specific a rule is does not change that order.[1]
A broad deny rule therefore beats a narrower allow rule. For example, Bash(aws *) blocks every aws command, including the ones that also match an allow rule such as Bash(aws s3 ls). An allow rule cannot carve an exception out of a deny rule, and the same holds between ask and allow.[1]
If you write a bare tool name in a deny rule, such as Bash, the tool is removed from Claude's context entirely, so Claude never sees it.[1]
Permission rules are enforced by Claude Code, not by the model. Instructions in a prompt or in CLAUDE.md shape what Claude tries to do, but they do not change what Claude Code allows. To grant or revoke access, use /permissions, the rules, a permission mode, or a PreToolUse hook.[1]
How to write rules
A rule has the form Tool or Tool(specifier). Writing Bash or Bash(*) matches every Bash command. A specifier in parentheses narrows the rule. Bash(npm run build) matches one exact command, and Read(./.env) matches one file.[1]
In a Bash rule, * matches any text, including spaces. A rule with no * matches exactly one command.[1]
Put the * after the subcommand. Claude Code matches everything before the first * as written, so Bash(git log *) limits the rule to git log, while a rule that starts with git * would cover every git subcommand.[1]
A trailing * with a space before it also matches the bare command. Bash(ls *) matches both ls and ls -la, but it does not match lsof. Removing the space, as in Bash(ls*), makes it match lsof too.[1]
Compound commands and the limits of Bash rules
A compound command runs without a prompt only when every subcommand is allowed. A rule such as Bash(safe-cmd *) does not approve safe-cmd && other-cmd. The separators Claude Code recognizes are &&, ||, ;, |, |&, &, and newlines.[1]
Deny and ask rules apply when any subcommand matches, including a command nested in a subshell or a command substitution.[1]
Bash rules match the command text Claude writes, and they are not a security boundary. Bash(curl *) stops curl https://example.com, but it does not stop /usr/bin/curl or sh -c 'curl ...'.[1]
A starter configuration
The configuration below lets npm run and git commit run without a prompt, and it denies git push outright:
``json { "permissions": { "allow": [ "Bash(npm run *)", "Bash(git commit *)" ], "deny": [ "Bash(git push *)" ] } } ``[1]
The git push * rule refuses commands that begin with git push. A push written another way, such as git -C . push, does not match it, so treat the rule as a guardrail rather than a hard boundary.[1]
Path patterns for Read and Edit
Read and Edit rules use gitignore-style patterns. //path is an absolute path from the filesystem root. ~/path starts at your home directory. /path is relative to the settings source. path or ./path is relative to the current directory.[1]
Watch out for absolute paths. A pattern like /Users/alice/file is not absolute, because the single leading slash anchors at the settings source. Write //Users/alice/file instead.[1]
A Read(path) deny rule also blocks the Edit and Write tools on the same path, including creating a new file there.[1]
Working directories, MCP servers, and subagents
By default Claude can reach files in the directory where you launched it. To extend that, pass --add-dir at startup, run /add-dir during a session, or set additionalDirectories in a settings file.[1]
For MCP tools, mcp__<server>__* matches every tool from a server, and mcp__<server>__<tool> matches one tool. Subagents can be controlled too: Agent(Explore) and Agent(Plan) match those subagents.[1]
Project rules and workspace trust
permissions.allow rules and additionalDirectories in a project's .claude/settings.json grant real capability, so Claude Code applies them only after you accept the workspace trust dialog for that folder. When you clone someone else's repository, read its allow rules before you accept.[1]
Managed settings and precedence
Administrators can deploy managed settings that user and project settings cannot override. Managed settings have the highest precedence. No other level, including command line arguments, can override a managed permission rule.[1]
If a tool is denied at any level, no other level can allow it. For example, a managed settings deny cannot be overridden by --allowedTools.[1]
To make managed settings the only source of permission rules, set allowManagedPermissionRulesOnly. Other settings sources are then ignored for permission rules.[1]
Common questions
With bypassPermissions mode, Claude Code skips permission prompts, including for writes to protected paths such as .git and .claude. Use it only in isolated environments. To block it, set permissions.disableBypassPermissionsMode to "disable" in a settings file; to block auto mode, set permissions.disableAutoMode. These settings are most useful in managed settings.[1]
The /permissions dialog lists all rules and the settings.json file each one comes from. You can open it while Claude is working, and changes apply from Claude's next tool call.[1]
Next steps
For the full rule syntax, the tool-specific rules, and how administrators deploy managed settings, read the permissions page in Claude Code's official documentation.[1]
Sources
- 1Configure permissionsAnthropic Claude Code docs
Cite this page: Claude Code permissions: allow, ask, and deny rules. TellWorld, https://www.tellworld.net/practice/practice-claude-code-permissions. Updated 2026-11-14