Claude Code permissions: modes, allow and deny rules, and settings.json
Claude Code permissions are rules that decide which actions run without asking you. You control them three ways: a permission mode such as Manual, acceptEdits, plan, auto, dontAsk or bypassPermissions; allow, ask and deny rules written as Tool(specifier); and settings files that stack from user to project to managed. Rules are checked deny first, then ask, then allow, and the first match wins. Claude Code enforces them, not the model, so CLAUDE.md cannot grant access.
What do Claude Code permissions control?
Every tool Claude Code uses is either allowed to run, blocked, or held until you approve it. The permissions page of the Claude Code docs describes a tiered system. In Manual mode, which is the baseline, reading files inside your working directory needs no approval, and almost everything else asks first.
| Tool type | Example | Approval required | “Yes, and don't ask again” lasts |
|---|---|---|---|
| Read-only | File reads, Grep | No, inside the working directory and added directories | Not applicable |
| Bash commands | Running a shell command | Yes, except a built-in set of read-only commands | Permanently, per repository and command |
| File modification | Editing or writing files | Yes | Until the session ends |
| Web fetch | WebFetch | Yes, except a set of preapproved documentation domains | Permanently, per repository and domain |
| Web search | WebSearch | Yes | Permanently, per repository |
What are the permission modes in Claude Code?
A mode sets the baseline: what runs without a prompt. You layer rules on top. The modes below come from the permission modes page. Manual mode is labeled Manual in the CLI and the editor extensions, but its value in config files is default, and manual works as an alias.
| Mode | Runs without asking | Best for |
|---|---|---|
| default (Manual) | Reads only | Reviewing every action, sensitive work |
| acceptEdits | Reads, file edits, and common filesystem commands such as mkdir, touch, mv and cp | Iterating on code you are reviewing |
| plan | Reads, so Claude explores but does not edit your source files | Exploring a codebase before changing it |
| auto | Everything, with a background classifier checking each action against your request | Long tasks, fewer prompts |
| dontAsk | Reads in your working directories and pre-approved tools; anything else is denied | Locked-down CI and scripts |
| bypassPermissions | Everything, except the actions no mode auto-approves | Isolated containers and VMs only |
Switch modes mid-session by pressing Shift+Tab. From auto the cycle runs default, acceptEdits, then plan. The status bar shows the active mode. The modes auto and bypassPermissions appear in the cycle only when available or when you started with the matching flag, and dontAsk never appears in the cycle: set it with --permission-mode dontAsk.
Which mode a session starts in follows an order. The --permission-mode flag wins. Next comes permissions.defaultMode in a settings file. Last is the built-in default. For sessions in a terminal or the VS Code extension, the built-in default is auto from Claude Code v2.1.283 on, and Manual on earlier versions or when auto is not available to the session. The auto mode guide covers the classifier, and the plan mode guide covers planning first.
How do allow, ask and deny rules work?
Run /permissions to see every rule and which settings file it comes from. There are three kinds. Allow rules let a tool run without asking. Ask rules prompt every time, even in a mode that would otherwise approve. Deny rules block the tool.
Rules are evaluated in a fixed order: deny, then ask, then allow. The first match decides, and a more specific rule does not outrank a broader one. A broad deny such as Bash(aws *) blocks every matching call, even one that also matches a narrower allow like Bash(aws s3 ls). An allow cannot carve an exception out of a deny. The same holds across files: a deny in your user settings beats an allow in the project settings.
A bare tool name in a deny rule, such as Bash, removes the tool from Claude's context entirely, so Claude never sees it. A scoped rule such as Bash(rm *) leaves the tool available and blocks matching calls when Claude tries them. You can add or remove rules while Claude is working, and the change applies from Claude's next tool call.
How do you write a permission rule?
A rule is either a tool name or a tool name with a specifier in parentheses: Tool or Tool(specifier). These shapes cover most projects.
| Rule | What it matches |
|---|---|
| Bash | Every Bash command (Bash(*) is the same) |
| Bash(npm run build) | Exactly that command, nothing more |
| Bash(npm run *) | npm run build, npm run test --watch, and bare npm run, but not npm install |
| Bash(git commit *) | Any git commit command |
| Read(./.env) | Reads of the .env file in the current directory |
| Read(./secrets/**) | Reads of anything under secrets |
| Edit(/docs/**) | Edits inside the docs folder of the project |
| WebFetch(domain:example.com) | Fetch requests to example.com |
| mcp__puppeteer__* | Every tool from the puppeteer MCP server |
| Agent(model:opus) | Subagent calls that ask for the Opus tier |
Four rules save time and prevent surprises.
- Put the star after the subcommand. In Bash(git log *), git is the program and log is the subcommand. Bash(git *) allows every git command. Claude Code warns at startup about an allow rule with a star before the subcommand, such as Bash(git * main).
- The space before a trailing star matters. Bash(ls *) matches ls and ls -la but not lsof. Bash(ls*) matches lsof too.
- Use Edit and Read for file rules. Edit rules cover all built-in tools that edit files. A rule written for Write, NotebookEdit or Glob is accepted but never matches anything, so write Edit(docs/) or Read(docs/) instead.
- Know where a path starts. In project settings, /path is relative to the project root. In user settings, /path is relative to ~/.claude. A path starting with // is absolute and ~/ is your home folder. A deny rule like Read(.env) matches a .env file at any depth under the current directory.
Be honest about what a Bash rule can do. It matches the command as Claude writes it. A deny of Bash(curl *) does not stop /usr/bin/curl, and a deny written for git push does not catch git -C . push. The docs also say Read and Edit deny rules do not apply to a command that reads files without naming them, such as grep -r run from the folder that holds the file. For real enforcement at the operating-system level, turn on the sandbox. Rules are guard rails for a helpful agent, not a security boundary against a hostile one.
Where do permission settings live, and which file wins?
Permission rules sit in the permissions object of a settings file. Claude Code reads four kinds of file, and an organization can add managed settings on top. See the settings page for every scope.
| Level | File | Who it affects |
|---|---|---|
| Managed | managed-settings.json, MDM policy or server-managed settings | Everyone in the organization; nothing below can override it |
| Command line | --settings with a file or JSON, for one session | That session only |
| Project local | .claude/settings.local.json | You, in this one project; kept out of git |
| Shared project | .claude/settings.json | Everyone in the folder; commit it |
| User | ~/.claude/settings.json | You, in every project on this machine |
For a normal setting, the highest level that sets a key wins. For permission lists, the lists merge: each file adds entries without removing another file's. Because deny is checked first across all of them, a deny at any level blocks a tool that another level allows. A managed deny cannot be overridden even by --allowedTools on the command line.
Two limits apply to shared project files. Allow rules and additionalDirectories in .claude/settings.json take effect only after you accept the workspace trust dialog for that folder, because they grant capability. Deny and ask rules are not affected, since they only restrict. And a defaultMode of auto or bypassPermissions does not take effect from project or local settings, so put those in ~/.claude/settings.json.
Settings and rules only affect Claude Code. If you are still choosing what to build, browse the developer tools ideas on the board or post your own.
What does a good permissions config look like?
Start small and add rules when a prompt annoys you twice. These three configs cover a solo builder, a read-heavy review session and a CI job. They are assembled from the shapes in the docs, so adjust the commands to your own package manager and scripts.
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git status)",
"Bash(git diff *)",
"Bash(git commit *)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Bash(curl *)"
],
"defaultMode": "acceptEdits"
}
}That config approves npm scripts and local git work, makes git push stop and ask, blocks reads of environment files and the secrets folder, and starts sessions in acceptEdits. Because it is in the project file, commit it so teammates get the same guard rails.
{
"permissions": {
"defaultMode": "plan",
"deny": [
"Read(~/.ssh/**)"
]
}
}claude -p "run the test suite" --permission-mode dontAsk --allowedTools "Bash(npm test)" "Read"
In dontAsk mode anything not on the list is denied instead of prompting, which is what you want in a pipeline where nobody can click yes. The GitHub Actions guide shows where those flags go in a workflow file.
Which files does Claude Code never auto-approve writes to?
Writes to a small set of paths are never auto-approved, except in bypassPermissions mode. The protected directories include .git, .vscode, .idea, .husky, .devcontainer and .claude, with a few exceptions such as Claude's own worktrees. Protected files include .gitconfig, shell startup files such as .zshrc and .bashrc, .npmrc, .mcp.json and .claude.json.
An allow rule in settings does not pre-approve these. The safety check runs before allow rules are evaluated, so adding Edit(.claude/**) changes nothing. In modes that prompt, the prompt can offer to allow edits to the project's .claude folder for the session. In auto mode these writes are routed to the classifier, and in dontAsk mode they are denied.
What are the most common permission mistakes?
- Relying on CLAUDE.md to keep secrets safe. It is guidance. Use a deny rule for .env and credential files.
- Writing an allow rule to override a deny. It cannot. Remove or narrow the deny.
- Using Write(...) for file rules. It never matches. Use Edit(...).
- Expecting a project rule to apply before trust. A fresh clone ignores project allow rules until you accept the trust dialog.
- Reaching for bypassPermissions on your laptop. Use acceptEdits, or a sandbox plus auto mode, and keep bypass for containers.
- Adding rules for every command at once. Approve prompts as they come, then promote the repeat ones to allow rules with /permissions.
Frequently asked questions
How do I stop Claude Code from asking for permission every time?
Pick a looser mode or add allow rules. Press Shift+Tab to move to acceptEdits so file edits stop prompting, or add rules such as Bash(npm run *) under permissions.allow for commands you trust. Choosing “Yes, and don't ask again” in a prompt saves a rule for you. Avoid bypassPermissions outside a container.
Where is the Claude Code settings.json file?
There are several. Your personal file is ~/.claude/settings.json and applies to every project. The shared project file is .claude/settings.json inside a repository, which you commit. The local file .claude/settings.local.json is for your own overrides in one project. Managed settings come from an organization policy and sit above all of them.
What is the difference between acceptEdits and auto mode?
AcceptEdits approves file edits and common filesystem commands such as mkdir and mv, and still asks before other shell commands. Auto mode runs without routine prompts, but a background classifier checks actions such as shell commands and network requests against what you asked for. Auto needs a supported model and can be turned off by your organization.
How do I stop Claude Code from reading my .env file?
Add deny rules to permissions.deny, such as Read(./.env) and Read(./.env.*). Claude Code then excludes matching files from search results and blocks reads and edits of them. The docs note this covers built-in tools and recognized commands like cat, but not every subprocess. For stricter control, enable the sandbox.
Do deny rules work in bypassPermissions mode?
Yes. Deny rules block in every mode, including bypassPermissions. Allow rules, by contrast, have no effect in that mode because it already skips prompts. Even in bypass mode a few actions are never auto-approved, such as tools matched by an explicit ask rule and recognized critical-path removals.
Does a deny rule in user settings override an allow in project settings?
Yes. Deny rules from any settings scope are evaluated before allow rules, so a user-level deny blocks a project-level allow. The reverse also holds: if user settings allow something and project settings deny it, the deny wins. A managed deny cannot be overridden by any file or by command line flags.
Created with AI assistance and edited for this site. Examples are illustrative and do not represent customer research. About the publisher.