Documentation Index
Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Claude Code supports fine-grained permissions so that you can specify exactly what the agent is allowed to do and what it cannot. Permission settings can be checked into version control and distributed to all developers in your organization, as well as customized by individual developers.
Permission system
Claude Code uses a tiered permission system to balance power and safety:
| Tool type | Example | Approval required | ”Yes, don’t ask again” behavior |
|---|
| Read-only | File reads, Grep | No | N/A |
| Bash commands | Shell execution | Yes | Permanently per project directory and command |
| File modification | Edit/write files | Yes | Until session end |
Manage permissions
You can view and manage Claude Code’s tool permissions with /permissions. This UI lists all permission rules and the settings.json file they are sourced from.
- 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 -> ask -> allow. The first matching rule wins, so deny rules always take precedence.
Permission modes
Claude Code supports several permission modes that control how tools are approved. See Permission modes for when to use each one. Set the defaultMode in your settings files:
| Mode | Description |
|---|
default | Standard behavior: prompts for permission on first use of each tool |
acceptEdits | Automatically accepts file edits and common filesystem commands (mkdir, touch, mv, cp, etc.) for paths in the working directory or additionalDirectories |
plan | Plan Mode: Claude reads files and runs read-only shell commands to explore but does not edit your source files |
auto | Auto-approves tool calls with background safety checks that verify actions align with your request. Currently a research preview |
dontAsk | Auto-denies tools unless pre-approved via /permissions or permissions.allow rules |
bypassPermissions | Skips all permission prompts. Root and home directory removals such as rm -rf / still prompt as a circuit breaker |
bypassPermissions mode skips all permission prompts, including writes to .git, .claude, .vscode, .idea, and .husky. Removals targeting the filesystem root or home directory, such as rm -rf / and rm -rf ~, still prompt as a circuit breaker against model error. Only use this mode in isolated environments like containers or VMs where Claude Code cannot cause damage. Administrators can prevent this mode by setting permissions.disableBypassPermissionsMode to "disable" in managed settings.
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 cannot be overridden.
Permission rule syntax
Permission rules follow the format Tool or Tool(specifier).
To match all uses of a tool, use just the tool name without parentheses:
| Rule | Effect |
|---|
Bash | Matches all Bash commands |
WebFetch | Matches all web fetch requests |
Read | Matches all file reads |
Bash(*) is equivalent to Bash and matches all Bash commands.
Use specifiers for fine-grained control
Add a specifier in parentheses to match specific tool uses:
| Rule | Effect |
|---|
Bash(npm run build) | Matches the exact command npm run build |
Read(./.env) | Matches reading the .env file in the current directory |
WebFetch(domain:example.com) | Matches fetch requests to example.com |
Wildcard patterns
Bash rules support glob patterns with *. Wildcards can appear at any position in the command. This configuration allows npm and git commit commands while blocking git push:
{
"permissions": {
"allow": [
"Bash(npm run *)",
"Bash(git commit *)",
"Bash(git * main)",
"Bash(* --version)",
"Bash(* --help *)"
],
"deny": [
"Bash(git push *)"
]
}
}
The space before * matters: Bash(ls *) matches ls -la but not lsof, while Bash(ls*) matches both. The :* suffix is an equivalent way to write a trailing wildcard, so Bash(ls:*) matches the same commands as Bash(ls *).
The permission dialog writes the space-separated form when you select “Yes, don’t ask again” for a command prefix. The :* form is only recognized at the end of a pattern. In a pattern like Bash(git:* push), the colon is treated as a literal character and won’t match git commands.
Bash
Bash permission rules support wildcard matching with *. Wildcards can appear at any position in the command, including at the beginning, middle, or end:
Bash(npm run build) matches the exact Bash command npm run build
Bash(npm run test *) matches Bash commands starting with npm run test
Bash(npm *) matches any command starting with npm
Bash(* install) matches any command ending with install
Bash(git * main) matches commands like git checkout main and git log --oneline main
A single * matches any sequence of characters including spaces, so one wildcard can span multiple arguments. Bash(git *) matches git log --oneline --all, and Bash(git * main) matches git push origin main as well as git merge main.
When * appears at the end with a space before it (like Bash(ls *)), it enforces a word boundary, requiring the prefix to be followed by a space or end-of-string. For example, Bash(ls *) matches ls -la but not lsof. In contrast, Bash(ls*) without a space matches both ls -la and lsof because there’s no word boundary constraint.
Compound commands
Claude Code is aware of shell operators, so a rule like Bash(safe-cmd *) won’t give it permission to run the command safe-cmd && other-cmd. The recognized command separators are &&, ||, ;, |, |&, &, and newlines. A rule must match each subcommand independently.
When you approve a compound command with “Yes, don’t ask again”, Claude Code saves a separate rule for each subcommand that requires approval, rather than a single rule for the full compound string. For example, approving git status && npm test saves a rule for npm test, so future npm test invocations are recognized regardless of what precedes the &&. Subcommands like cd into a subdirectory generate their own Read rule for that path. Up to 5 rules may be saved for a single compound command.
Process wrappers
Before matching Bash rules, Claude Code strips a fixed set of process wrappers so a rule like Bash(npm test *) also matches timeout 30 npm test. The recognized wrappers are timeout, time, nice, nohup, and stdbuf.
Bare xargs is also stripped, so Bash(grep *) matches xargs grep pattern. Stripping applies only when xargs has no flags: an invocation like xargs -n1 grep pattern is matched as an xargs command, so rules written for the inner command do not cover it.
This wrapper list is built in and is not configurable. Development environment runners such as direnv exec, devbox run, mise exec, npx, and docker exec are not in the list. Because these tools execute their arguments as a command, a rule like Bash(devbox run *) matches whatever comes after run, including devbox run rm -rf .. To approve work inside an environment runner, write a specific rule that includes both the runner and the inner command, such as Bash(devbox run npm test). Add one rule per inner command you want to allow.
Exec wrappers such as watch, setsid, ionice, and flock always prompt and cannot be auto-approved by a prefix rule like Bash(watch *). The same applies to find with -exec or -delete: a Bash(find *) rule does not cover these forms. To approve a specific invocation, write an exact-match rule for the full command string.
Read-only commands
Claude Code recognizes a built-in set of Bash commands as read-only and runs them without a permission prompt in every mode. These include ls, cat, head, tail, grep, find, wc, diff, stat, du, cd, and read-only forms of git. The set is not configurable; to require a prompt for one of these commands, add an ask or deny rule for it.
Unquoted glob patterns are permitted for commands whose every flag is read-only, so ls *.ts and wc -l src/*.py run without a prompt. Commands with write-capable or exec-capable flags, such as find, sort, sed, and git, still prompt when an unquoted glob is present because the glob could expand to a flag like -delete.
A cd into a path inside your working directory or an additional directory is also read-only. A compound command like cd packages/api && ls runs without a prompt when each part qualifies on its own. Combining cd with git in one compound command always prompts, regardless of the target directory.
Bash permission patterns that try to constrain command arguments are fragile. For example, Bash(curl http://github.com/ *) intends to restrict curl to GitHub URLs, but won’t match variations like:
- Options before URL:
curl -X GET http://github.com/...
- Different protocol:
curl https://github.com/...
- Redirects:
curl -L http://bit.ly/xyz (redirects to github)
- Variables:
URL=http://github.com && curl $URL
- Extra spaces:
curl http://github.com
For more reliable URL filtering, consider:
- Restrict Bash network tools: use deny rules to block
curl, wget, and similar commands, then use the WebFetch tool with WebFetch(domain:github.com) permission for allowed domains
- Use PreToolUse hooks: implement a hook that validates URLs in Bash commands and blocks disallowed domains
- Instructing Claude Code about your allowed curl patterns via CLAUDE.md
Note that using WebFetch alone does not prevent network access. If Bash is allowed, Claude can still use curl, wget, or other tools to reach any URL.
PowerShell
PowerShell permission rules use the same shape as Bash rules. Wildcards with * match at any position, the :* suffix is equivalent to a trailing *, and a bare PowerShell or PowerShell(*) matches every command. This configuration allows Get-ChildItem and git commit commands while blocking Remove-Item:
{
"permissions": {
"allow": [
"PowerShell(Get-ChildItem *)",
"PowerShell(git commit *)"
],
"deny": [
"PowerShell(Remove-Item *)"
]
}
}
Common aliases are canonicalized before matching. A rule written for the cmdlet name also matches its aliases, so PowerShell(Get-ChildItem *) matches gci, ls, and dir as well. Matching is case-insensitive.
Claude Code parses the PowerShell AST and checks each command in a compound command independently. Pipeline operators |, statement separators ;, and on PowerShell 7+ the chain operators && and || split a compound command into subcommands. A rule must match every subcommand for the compound command to be allowed.
Read and Edit
Edit rules apply to all built-in tools that edit files. Claude makes a best-effort attempt to apply Read rules to all built-in tools that read files like Grep and Glob.
Read and Edit deny rules apply to Claude’s built-in file tools, not to Bash subprocesses. A Read(./.env) deny rule blocks the Read tool but does not prevent cat .env in Bash. For OS-level enforcement that blocks all processes from accessing a path, enable the sandbox.
Read and Edit rules both follow the gitignore specification with four distinct pattern types:
| Pattern | Meaning | Example | Matches |
|---|
//path | Absolute path from filesystem root | Read(//Users/alice/secrets/**) | /Users/alice/secrets/** |
~/path | Path from home directory | Read(~/Documents/*.pdf) | /Users/alice/Documents/*.pdf |
/path | Path relative to project root | Edit(/src/**/*.ts) | <project root>/src/**/*.ts |
path or ./path | Path relative to current directory | Read(*.env) | <cwd>/*.env |
A pattern like /Users/alice/file is NOT an absolute path. It’s relative to the project root. Use //Users/alice/file for absolute paths.
On Windows, paths are normalized to POSIX form before matching. C:\Users\alice becomes /c/Users/alice, so use //c/**/.env to match .env files anywhere on that drive. To match across all drives, use //**/.env.
Examples:
Edit(/docs/**): edits in <project>/docs/ (NOT /docs/ and NOT <project>/.claude/docs/)
Read(~/.zshrc): reads your home directory’s .zshrc
Edit(//tmp/scratch.txt): edits the absolute path /tmp/scratch.txt
Read(src/**): reads from <current-directory>/src/
A rule only matches files under its anchor, so the anchor determines how far a deny rule reaches. Bare filenames follow gitignore semantics and match at any depth, so Read(.env) and Read(**/.env) are equivalent:
| Deny rule | Blocks | Does not block |
|---|
Read(.env) or Read(**/.env) | any .env at or under the current directory | .env in a parent directory or another project |
Read(//**/.env) | any .env anywhere on the filesystem | nothing; the rule is anchored at the filesystem root |
In gitignore patterns, * matches files in a single directory while ** matches recursively across directories. To allow all file access, use just the tool name without parentheses: Read, Edit, or Write.
When Claude accesses a symlink, permission rules check two paths: the symlink itself and the file it resolves to. Allow and deny rules treat that pair differently: allow rules fall back to prompting you, while deny rules block outright.
- Allow rules: apply only when both the symlink path and its target match. A symlink inside an allowed directory that points outside it still prompts you.
- Deny rules: apply when either the symlink path or its target matches. A symlink that points to a denied file is itself denied.
For example, with Read(./project/**) allowed and Read(~/.ssh/**) denied, a symlink at ./project/key pointing to ~/.ssh/id_rsa is blocked: the target fails the allow rule and matches the deny rule.
WebFetch
WebFetch(domain:example.com) matches fetch requests to example.com
MCP
mcp__puppeteer matches any tool provided by the puppeteer server (name configured in Claude Code)
mcp__puppeteer__* wildcard syntax that also matches all tools from the puppeteer server
mcp__puppeteer__puppeteer_navigate matches the puppeteer_navigate tool provided by the puppeteer server
Agent (subagents)
Use Agent(AgentName) rules to control which subagents Claude can use:
Agent(Explore) matches the Explore subagent
Agent(Plan) matches the Plan subagent
Agent(my-custom-agent) matches a custom subagent named my-custom-agent
Add these rules to the deny array in your settings or use the --disallowedTools CLI flag to disable specific agents. To disable the Explore agent:
{
"permissions": {
"deny": ["Agent(Explore)"]
}
}
Extend permissions with hooks
Claude Code hooks provide a way to register custom shell commands to perform permission evaluation at runtime. When Claude Code makes a tool call, PreToolUse hooks run before the permission prompt. The hook output can deny the tool call, force a prompt, or skip the prompt to let the call proceed.
Hook decisions do not bypass permission rules. Deny and ask rules are evaluated regardless of what a PreToolUse hook returns, so a matching deny rule blocks the call and a matching ask rule still prompts even when the hook returned "allow" or "ask". This preserves the deny-first precedence described in Manage permissions, including deny rules set in managed settings.
A blocking hook also takes precedence over allow rules. A hook that exits with code 2 stops the tool call before permission rules are evaluated, so the block applies even when an allow rule would otherwise let the call proceed. To run all Bash commands without prompts except for a few you want blocked, add "Bash" to your allow list and register a PreToolUse hook that rejects those specific commands. See Block edits to protected files for a hook script you can adapt.
Working directories
By default, Claude has access to files in the directory where it was launched. You can extend this access:
- During startup: use
--add-dir <path> CLI argument
- During session: use
/add-dir command
- Persistent configuration: add to
additionalDirectories in settings files
Files in additional directories follow the same permission rules as the original working directory: they become readable without prompts, and file editing permissions follow the current permission mode.
Additional directories grant file access, not configuration
Adding a directory extends where Claude can read and edit files. It does not make that directory a full configuration root: most .claude/ configuration is not discovered from additional directories, though a few types are loaded as exceptions.
The following configuration types are loaded from --add-dir directories:
| Configuration | Loaded from --add-dir |
|---|
Skills in .claude/skills/ | Yes, with live reload |
Plugin settings in .claude/settings.json | enabledPlugins and extraKnownMarketplaces only |
CLAUDE.md files, .claude/rules/, and CLAUDE.local.md | Only when CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 is set. CLAUDE.local.md additionally requires the local setting source, which is enabled by default |
Everything else, including subagents, commands, output styles, hooks, and other settings, is discovered only from the current working directory and its parents, your user directory at ~/.claude/, and managed settings. To share that configuration across projects, use one of these approaches:
- User-level configuration: place files in
~/.claude/agents/, ~/.claude/output-styles/, or ~/.claude/settings.json to make them available in every project
- Plugins: package and distribute configuration as a plugin that teams can install
- Launch from the config directory: run Claude Code from the directory containing the
.claude/ configuration you want
How permissions interact with sandboxing
Permissions and sandboxing are complementary security layers:
- Permissions control which tools Claude Code can use and which files or domains it can access. They apply to all tools (Bash, Read, Edit, WebFetch, MCP, and others).
- Sandboxing provides OS-level enforcement that restricts the Bash tool’s filesystem and network access. It applies only to Bash commands and their child processes.
Use both for defense-in-depth:
- Permission deny rules block Claude from even attempting to access restricted resources
- Sandbox restrictions prevent Bash commands from reaching resources outside defined boundaries, even if a prompt injection bypasses Claude’s decision-making
- Filesystem restrictions in the sandbox combine the
sandbox.filesystem settings with Read and Edit deny rules; both are merged into the final sandbox boundary
- Network restrictions combine WebFetch permission rules with the sandbox’s
allowedDomains and deniedDomains lists
When sandboxing is enabled with autoAllowBashIfSandboxed: true, which is the default, sandboxed Bash commands run without prompting even if your permissions include ask: Bash(*). The sandbox boundary substitutes for the per-command prompt. Explicit deny rules still apply, and rm or rmdir commands that target /, your home directory, or other critical system paths still trigger a prompt. See sandbox modes to change this behavior.
Managed settings
For organizations that need centralized control over Claude Code configuration, administrators can deploy managed settings that cannot be overridden by user or project settings. These policy settings follow the same format as regular settings files and can be delivered through MDM/OS-level policies, managed settings files, or server-managed settings. See settings files for delivery mechanisms and file locations.
Managed-only settings
The following settings are only read from managed settings. Placing them in user or project settings files has no effect.
| Setting | Description |
|---|
allowedChannelPlugins | Allowlist of channel plugins that may push messages. Replaces the default Anthropic allowlist when set. Requires channelsEnabled: true. See Restrict which channel plugins can run |
allowManagedHooksOnly | When true, only managed hooks, SDK hooks, and hooks from plugins force-enabled in managed settings enabledPlugins are loaded. User, project, and all other plugin hooks are blocked |
allowManagedMcpServersOnly | When true, only allowedMcpServers from managed settings are respected. deniedMcpServers still merges from all sources. See Managed MCP configuration |
allowManagedPermissionRulesOnly | When true, prevents user and project settings from defining allow, ask, or deny permission rules. Only rules in managed settings apply |
blockedMarketplaces | Blocklist of marketplace sources. Blocked sources are checked before downloading, so they never touch the filesystem. See managed marketplace restrictions |
channelsEnabled | Allow channels for the organization. See enterprise controls for the default on each plan |
forceRemoteSettingsRefresh | When true, blocks CLI startup until remote managed settings are freshly fetched and exits if the fetch fails. See fail-closed enforcement |
pluginTrustMessage | Custom message appended to the plugin trust warning shown before installation |
sandbox.filesystem.allowManagedReadPathsOnly | When true, only filesystem.allowRead paths from managed settings are respected. denyRead still merges from all sources |
sandbox.network.allowManagedDomainsOnly | When true, only allowedDomains and WebFetch(domain:...) allow rules from managed settings are respected. Non-allowed domains are blocked automatically without prompting the user. Denied domains still merge from all sources |
strictKnownMarketplaces | Controls which plugin marketplace sources users can add and install plugins from. See managed marketplace restrictions |
wslInheritsWindowsSettings | When true in the Windows HKLM registry key or C:\Program Files\ClaudeCode\managed-settings.json, WSL reads managed settings from the Windows policy chain in addition to /etc/claude-code. See Settings files |
disableBypassPermissionsMode is typically placed in managed settings to enforce organizational policy, but it works from any scope. A user can set it in their own settings to lock themselves out of bypass mode.
Settings precedence
Permission rules follow the same settings precedence as all other Claude Code settings:
- Managed settings: cannot be overridden by any other level, including command line arguments
- Command line arguments: temporary session overrides
- Local project settings (
.claude/settings.local.json)
- Shared project settings (
.claude/settings.json)
- User settings (
~/.claude/settings.json)
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, and --disallowedTools can add restrictions beyond what managed settings define.
If a permission is allowed in user settings but denied in project settings, the project setting takes precedence and the permission is blocked.
Example configurations
This repository includes starter settings configurations for common deployment scenarios. Use these as starting points and adjust them to fit your needs.
See also
- Settings: complete configuration reference including the permission settings table
- Configure auto mode: tell the auto mode classifier which infrastructure your organization trusts
- Sandboxing: OS-level filesystem and network isolation for Bash commands
- Authentication: set up user access to Claude Code
- Security: security safeguards and best practices
- Hooks: automate workflows and extend permission evaluation