← All posts

Claude Code Permissions: Allow, Deny and Ask Rules Guide

Claude Code asks before it runs shell commands or edits files. Rules in settings.json decide what it can do unprompted and what it can never touch. Syntax, pitfalls and a working config.

November 10, 2026 8 min read Guide
Quick answer

Add a permissions block to .claude/settings.json with allow, ask and deny lists. Rules look like Bash(npm run *) or Read(./.env). Claude Code checks deny first, then ask, then allow, and the first match wins, so an allow rule can never cut an exception out of a deny rule. Run /permissions to see every active rule and the file it came from. Rules are enforced by Claude Code, not by the model, so a line in CLAUDE.md cannot grant or revoke access.

Why does Claude Code keep asking for permission?

Out of the box, Claude Code in Manual mode asks before any action that could change something. The permissions docs sort tools like this:

Tool typeAsks first?"Yes, and don't ask again" lasts
File reads, GrepNo, inside the working directoryn/a
Bash commandsYes, except a built-in read-only setPermanently, per repository and command
File edits and writesYesUntil the session ends
WebFetchYes, except preapproved documentation domainsPermanently, per repository and domain
WebSearchYesPermanently, per repository

Each time you pick "Yes, and don't ask again" for a Bash command, Claude Code writes an allow rule into .claude/settings.local.json. Writing rules yourself is faster and gives you the deny side too.

How do allow, ask and deny rules work together?

Evaluation order is deny, then ask, then allow. The first match decides, and specificity does not change that. If you deny Bash(aws *), then Bash(aws s3 ls) in the allow list never runs, because the deny matched first. The same holds between ask and allow: a matching ask rule prompts even when a narrower allow rule exists.

Deny rules also behave differently depending on shape. A bare Bash deny removes the tool from Claude's context entirely. A scoped one such as Bash(rm *) keeps the tool and blocks matching calls.

What is the rule syntax?

A rule is Tool or Tool(specifier). With no parentheses it covers every use of the tool. With a specifier it narrows down: Bash(npm run build) matches that exact command, Read(./.env) matches the .env in the current directory, and WebFetch(domain:example.com) matches requests to that domain.

In Bash rules, * matches any text, including spaces. Put it after the subcommand, because everything before the first * is matched as written:

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)"
    ]
  }
}

With this file Claude runs npm scripts and commits without asking, and refuses commands that begin with git push. Three matching details cause most confusion:

You writeMatchesDoes not match
Bash(npm run build)npm run buildnpm run build --watch
Bash(ls *)ls -la, lslsof
Bash(ls*)ls -la, lsof

The space before a trailing * is part of the rule, so ls * does not match lsof. A trailing * also matches the bare command. The Bash(ls:*) form means the same as Bash(ls *), but only at the end of a pattern.

Claude Code understands shell operators. Bash(safe-cmd *) does not approve safe-cmd && other-cmd, because every subcommand must be allowed. It also strips a fixed set of wrappers (timeout, time, nice, nohup, stdbuf) before matching, so Bash(npm test *) covers timeout 30 npm test. Runners like npx and docker exec are not stripped, so write rules that name both the runner and the inner command.

How do I stop Claude from reading my .env file?

Add Read deny rules. This is the example from the settings docs, and it also shows an allow list:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Bash(npm run lint)",
      "Bash(npm run test *)"
    ],
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)"
    ]
  }
}

Read and Edit rules use gitignore-style patterns with four anchors:

PatternMeaningExample
//pathAbsolute path from the filesystem rootRead(//Users/alice/secrets/**)
~/pathFrom your home directoryRead(~/Documents/*.pdf)
/pathRelative to the settings sourceEdit(/src/**/*.ts)
path or ./pathRelative to the current directoryRead(*.env)

The one that trips people up: /Users/alice/file is not an absolute path. A single leading slash anchors at the settings source, so use //Users/alice/file. In user settings, /path resolves under ~/.claude, not in your project, so use // or ~/ there.

Other facts worth knowing:

Where do I put the rules?

FileWho it affects
~/.claude/settings.jsonYou, in every project
.claude/settings.jsonEveryone in the repo, if committed
.claude/settings.local.jsonYou, in this project only
Managed settingsEveryone your organization deploys to

Precedence, highest first: managed, command line (--settings), project local, shared project, user. List keys such as permissions.allow merge across files instead of overriding, so each file adds entries. Two catches: allow rules in a committed .claude/settings.json only apply after each teammate trusts the folder, while deny and ask rules apply immediately. Edits to permissions reload without a restart, so you can tune rules mid-session.

Which permission mode should I use?

ModeWhat runs without asking
default (shown as Manual)Reads only
acceptEditsFile edits and common filesystem commands such as mkdir, touch, mv, cp in the working directory
planReads and read-only exploration; no source edits
autoActions run after a background classifier checks them
dontAskOnly pre-approved tools; everything else is denied
bypassPermissionsEverything except a short list no mode approves

Switch with Shift+Tab, start with a flag, or set a default:

claude --permission-mode plan
claude --permission-mode acceptEdits

# settings.json
{ "permissions": { "defaultMode": "acceptEdits" } }

dontAsk suits locked-down CI runs, because the session never waits for input. bypassPermissions is for containers and VMs only: allow rules have no effect there, deny rules still block, and the docs warn it offers no protection against prompt injection. Setting defaultMode to auto or bypassPermissions in a project file is ignored. Put it in user settings or pass the flag. To forbid these modes for a whole team, set permissions.disableBypassPermissionsMode or permissions.disableAutoMode to "disable" in managed settings.

What can permission rules not stop?

A Bash rule matches the command text Claude writes. It is not a wall around the program. The docs give these examples of what a deny rule misses:

Deny ruleStopsDoes not stop
Bash(curl *)curl https://example.com/usr/bin/curl ..., sh -c 'curl ...'
Bash(git push *)git push origin maingit -C . push origin main

Treat rules as guardrails for normal behavior. For hard limits use the sandbox, which enforces filesystem and network access at the OS level, or a PreToolUse hook that inspects the full command. A hook's deny holds even in bypassPermissions.

How do I check which rules are active?

  1. /permissions lists every rule and the settings file behind it. You can add or remove rules there, and changes apply from Claude's next tool call.
  2. /status shows which settings files loaded (the Setting sources line).
  3. claude doctor lists entries Claude Code rejected, such as a malformed rule. It is the first place to look when a rule seems ignored.

Settings files are strict JSON. A comment or trailing comma makes Claude Code skip the file, so validate after every edit.

FAQ

Does "Yes, and don't ask again" carry over to other projects?

No. For Bash commands it is saved per repository and command, in that project's local settings file.

Can an allow rule override a deny rule?

No. Deny is checked first and an allow rule cannot carve out an exception.

Can I put permission instructions in CLAUDE.md instead?

Instructions there shape what Claude tries to do, but they do not change what Claude Code allows. Use rules, a mode, or a hook.

How do I set up permissions for unattended runs?

Combine --allowedTools with --permission-mode dontAsk. See headless mode and CI.

Sources

Checked against the official docs on November 10, 2026: Configure permissions, Permission modes, Settings files and precedence and Run Claude Code programmatically.

See every current command, flag, and setting in one reference.

Open the Claude Code Cheatsheet →