How to Configure Claude Code Permissions: Allow, Ask, and Deny Rules
Developers approve 93% of Claude Code permission prompts without careful review, turning a security mechanism into background noise. This guide covers the three rule types, their deny-first evaluation order, settings.json configuration at project, user, and managed levels, and copy-paste recipes that lock Claude Code to exactly what your project needs.
Why Default Permission Prompts Fall Short
Anthropic's engineering team found that developers approve 93% of Claude Code permission prompts without careful review. That number exposes a real problem: prompting for every action creates the illusion of oversight while the actual security value drops to near zero. Developers click "yes" reflexively because stopping to evaluate each shell command or file edit breaks their flow.
Claude Code's permission system solves this by moving security decisions out of the moment and into configuration. Instead of approving individual actions during a coding session, you define rules in advance that specify what Claude Code can do freely, what it should ask about, and what it must never attempt.
The system uses three rule types:
- Allow rules let Claude Code use a tool without asking
- Ask rules pause for confirmation before each use
- Deny rules block a tool entirely, no matter what other rules say
Rules live in settings.json files at three levels. Project settings (.claude/settings.json) apply to everyone working on the repo. User settings (~/.claude/settings.json) apply across all your projects. Managed settings, deployed by an organization's administrators through MDM or policy files, override everything else and cannot be loosened by individual developers or project configs.
The evaluation order is fixed: deny first, then ask, then allow. A deny rule always wins, even when a more specific allow rule also matches the same call. This means you can grant broad permissions for everyday work while blocking specific dangerous operations with full confidence that the blocks hold.
How Allow, Ask, and Deny Rules Work
Each permission rule targets a specific tool or tool pattern using the format Tool or Tool(specifier). A bare tool name like Bash matches every call to that tool. Adding a specifier in parentheses narrows the match to specific uses.
Allow rules tell Claude Code to proceed without prompting. When you know a command is safe for your project, adding it to the allow list removes friction without removing security for everything else. A rule like Bash(npm run build) lets Claude run your build command on its own while still prompting for unfamiliar shell commands.
Ask rules force a confirmation prompt even when the current permission mode would otherwise auto-approve the action. This is useful for commands that are sometimes fine but deserve a second look, like database migrations or deployment scripts. Ask rules override allow rules for the same tool call.
Deny rules block matching tool calls completely. There are two flavors with different behavior. A bare tool name like Bash removes the tool from Claude's awareness entirely, so Claude never even considers using it. A scoped rule like Bash(rm -rf *) leaves the Bash tool available but blocks any command matching that pattern when Claude attempts it.
The critical detail is evaluation order. Claude Code checks deny rules first across all settings levels, then ask rules, then allow rules. The first match in that sequence determines the outcome. 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). You cannot punch holes in a deny rule with allow exceptions.
This ordering also works across settings levels. If your user settings allow Bash(git push *) but your project settings deny it, the deny wins. If managed settings deny a tool, neither project nor user settings can override it. The same logic applies between ask and allow: a matching ask rule prompts even when a more specific allow rule also matches.
Writing Permission Rules in settings.json
Permission rules go in the permissions object of your settings.json file. Here is a starting configuration for a typical web project:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(npx tsc --noEmit)"
],
"deny": [
"Bash(git push *)",
"Bash(rm -rf *)",
"Bash(curl *)"
],
"ask": [
"Bash(git checkout *)"
]
}
}
Wildcard Patterns for Bash
Bash rules support glob patterns with *. Wildcards can appear at any position in the command. The space before * matters: Bash(ls *) matches ls -la but not lsof, while Bash(ls*) without the space matches both. A single * matches any sequence of characters including spaces, so one wildcard can span arguments.
Practical examples:
Bash(npm run test *)matches any test command variantBash(git * main)matchesgit checkout main,git merge main, andgit push origin mainBash(* --version)matches version checks for any toolBash(* --help *)matches help output for any command
Claude Code is aware of shell operators. A rule like Bash(npm test) does not automatically permit npm test && rm -rf /. Each subcommand in a compound expression (&&, ||, ;, |) is checked independently against the rules.
File Path Rules for Read and Edit
Read and Edit rules use gitignore-style patterns with four anchor types:
//pathmatches an absolute filesystem path~/pathmatches relative to your home directory/pathmatches relative to the project rootpathor./pathmatches relative to the current directory
Common file protection patterns:
{
"permissions": {
"deny": [
"Read(**/.env)",
"Read(~/.ssh/**)",
"Edit(.github/workflows/**)"
],
"allow": [
"Edit(/src/**/*.ts)",
"Edit(/tests/**)"
]
}
}
A bare filename like Read(.env) uses gitignore semantics and matches at any depth under the current directory. For broader protection, Read(//**/.env) blocks .env files anywhere on the filesystem.
Domain Rules for WebFetch
WebFetch rules use a domain: prefix to control which URLs Claude Code can access:
WebFetch(domain:docs.example.com)matches that exact hostWebFetch(domain:*.example.com)matches any subdomain but not the root domainWebFetch(domain:*)matches all domains
MCP Server Rules
When Claude Code connects to MCP servers for external tool access, you can control individual server tools with the mcp__server__tool naming pattern:
{
"permissions": {
"allow": [
"mcp__workspace__*"
],
"deny": [
"mcp__workspace__delete_workspace"
]
}
}
This pattern works well when connecting Claude Code to services like Fast.io's MCP server, where you want agents to read and write files but not modify workspace settings. Fast.io's own workspace permissions add a second layer of control at the platform level, giving you tool-level rules in Claude Code and resource-level permissions in the workspace.
Store and share agent output with workspace-level permissions
Fast.io workspaces give AI agents MCP access to files with granular permissions at the org, workspace, and folder level. Pair Claude Code tool rules with platform-level access controls for end-to-end security over every file your agents create.
Choosing the Right Permission Mode
Permission modes set the baseline behavior for a session. Rules layer on top of whichever mode you pick. Six modes are available, each with a different tradeoff between convenience and oversight.
default prompts for permission on first use of each tool type. Start here when you are learning the system or working on sensitive code.
acceptEdits auto-approves file creation, edits, and common filesystem commands like mkdir, touch, mv, and cp within your working directory. Other Bash commands still prompt. This is the productive middle ground for iterating on code you plan to review with git diff afterward.
plan restricts Claude to read-only exploration. Claude reads files and runs read-only shell commands to investigate, then writes a plan without editing your source files. Use this when you want Claude's analysis before committing to a direction.
auto eliminates routine prompts by running a background classifier (powered by Sonnet) that reviews each action before execution. The classifier checks whether the action aligns with your request and blocks anything that escalates beyond scope, targets unrecognized infrastructure, or looks like prompt injection. Your deny and ask rules still apply on top of the classifier's decisions. Auto mode blocks production deploys, force pushes, mass deletions, and credential exfiltration by default.
dontAsk auto-denies every tool call that would normally prompt. Only actions matching your allow rules and built-in read-only commands can execute. This makes Claude Code fully non-interactive for CI pipelines and automated scripts.
bypassPermissions disables all prompts except those forced by explicit ask rules. Removals targeting / or your home directory still prompt as a safety circuit breaker. Only use this in isolated containers or VMs. Administrators can block this mode entirely by setting permissions.disableBypassPermissionsMode to "disable" in managed settings.
Set the default mode in settings.json:
{
"permissions": {
"defaultMode": "acceptEdits"
}
}
Or pass it as a startup flag:
claude --permission-mode plan
Switch modes mid-session by pressing Shift+Tab in the CLI, which cycles through default, acceptEdits, and plan. Auto and bypass modes appear in the cycle only after you opt into them.
A common team pattern is setting acceptEdits as the project default in .claude/settings.json while adding deny rules for deployment and infrastructure commands. Individual developers can drop to plan mode with Shift+Tab when exploring unfamiliar code, or escalate to auto for long-running tasks where prompt fatigue is a real concern.
Practical Permission Recipes
Here are tested configurations for common scenarios. Copy the one closest to your workflow and adjust from there.
Web Development Team
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(npm run *)",
"Bash(npx *)",
"Bash(git commit *)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git status)",
"Bash(git stash *)"
],
"deny": [
"Bash(git push *)",
"Bash(rm -rf *)",
"Bash(curl *)",
"Bash(wget *)",
"Edit(.github/workflows/**)"
],
"ask": [
"Bash(git checkout *)",
"Bash(docker *)"
]
}
}
This lets Claude run builds, tests, and local git operations while blocking pushes, destructive deletions, and network requests. Docker commands prompt for review since they can affect the host system. CI workflow files are protected from edits.
CI Pipeline (Fully Locked Down)
{
"permissions": {
"defaultMode": "dontAsk",
"allow": [
"Bash(npm run test *)",
"Bash(npm run lint *)",
"Bash(npm run build)",
"Read"
],
"deny": [
"Bash(git push *)",
"Bash(npm publish *)",
"WebFetch"
]
}
}
In dontAsk mode, Claude Code runs without interactive prompts. Only the explicitly allowed commands execute. Everything else is silently denied, making this safe for unattended automation.
AI Agent Workspace Access
When Claude Code works with external services through MCP, combine Claude Code permissions with the service's own access controls. For agent workflows using Fast.io workspaces as persistent storage:
{
"permissions": {
"allow": [
"mcp__fastio__*"
],
"deny": [
"mcp__fastio__delete_workspace",
"mcp__fastio__transfer_ownership"
]
}
}
This gives Claude full read/write access to workspace files through the MCP server while blocking destructive administrative operations. Fast.io's workspace permissions handle the second layer: who can access which files, version history, and audit trails for everything the agent touches.
Defense in Depth with Sandboxing
Permissions and sandboxing are complementary. Permissions control what Claude Code attempts. Sandboxing restricts what Bash commands can reach at the OS level, even if prompt injection bypasses Claude's decision-making.
{
"permissions": {
"deny": [
"Bash(curl *)",
"Bash(wget *)",
"Read(**/.env)"
]
},
"sandbox": {
"filesystem": {
"denyRead": ["~/.ssh/**", "~/.aws/**"]
}
}
}
Permission deny rules stop Claude from attempting access. Sandbox restrictions prevent Bash child processes from reaching those paths regardless of what Claude decides to do. Using both layers together gives you the strongest protection against both accidental and adversarial access.
Frequently Asked Questions
How do I set up Claude Code permissions?
Add a permissions object to your .claude/settings.json file with allow, deny, and ask arrays. Each array contains rules in Tool(specifier) format. Deny rules block tools, allow rules auto-approve them, and ask rules force a confirmation prompt. The system evaluates rules in deny-first order, so a deny always overrides a matching allow rule.
What are Claude Code permission modes?
Claude Code has six permission modes that set the baseline approval behavior. Default mode prompts for each tool use. AcceptEdits auto-approves file changes and common filesystem commands. Plan mode restricts Claude to read-only exploration. Auto mode uses a background AI classifier to approve safe actions. DontAsk only runs pre-approved tools. BypassPermissions skips all prompts and should only be used in isolated containers.
How does Claude Code auto mode work?
Auto mode runs a background classifier that evaluates each tool call before execution. The classifier checks whether the action aligns with your stated request and blocks escalations like production deploys, force pushes, credential exfiltration, and mass deletions. Your explicit deny and ask rules still apply on top of the classifier. If the classifier blocks an action three times consecutively or twenty times total, auto mode pauses and reverts to manual prompting.
Can I restrict Claude Code from running certain commands?
Add the commands to the deny array in your permissions configuration. For example, Bash(git push *) blocks all git push commands, and Bash(rm -rf *) blocks recursive deletions. Deny rules support glob wildcards and apply across all permission modes, including bypassPermissions mode.
Where do Claude Code permission settings files live?
Permission rules can live in three locations with different scopes. Project settings at .claude/settings.json apply to everyone working on that repository and can be checked into version control. User settings at ~/.claude/settings.json apply across all your projects. Managed settings, deployed by enterprise administrators through MDM or policy files, override all other levels and cannot be loosened by anyone.
Related Resources
Store and share agent output with workspace-level permissions
Fast.io workspaces give AI agents MCP access to files with granular permissions at the org, workspace, and folder level. Pair Claude Code tool rules with platform-level access controls for end-to-end security over every file your agents create.