All skills
Skillintermediate

Configure permissions

> ## 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 Knowledge Pack7/10/2026

Overview

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.

Configure permissions

Control what Claude Code can access and do with fine-grained permission rules, modes, and managed policies.

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 typeExampleApproval required"Yes, don't ask again" behavior
Read-onlyFile reads, GrepNoN/A
Bash commandsShell executionYesPermanently per project directory and command
File modificationEdit/write filesYesUntil 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:

ModeDescription
defaultStandard behavior: prompts for permission on first use of each tool
acceptEditsAutomatically accepts file edits and common filesystem commands (mkdir, touch, mv, cp, etc.) for paths in the working directory or additionalDirectories
planPlan Mode: Claude can analyze but not modify files or execute commands
autoAuto-approves tool calls with background safety checks that verify actions align with your request. Currently a research preview
dontAskAuto-denies tools unless pre-approved via /permissions or permissions.allow rules
bypassPermissionsSkips permission prompts except for writes to protected directories (see warning below)

bypassPermissions mode skips permission prompts. Writes to .git, .claude, .vscode, .idea, and .husky directories still prompt for confirmation to prevent accidental corruption of repository state, editor configuration, and git hooks. Writes to .claude/commands, .claude/agents, and .claude/skills are exempt and do not prompt, because Claude routinely writes there when creating skills, subagents, and commands. 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).

Match all uses of a tool

To match all uses of a tool, use just the tool name without parentheses:

RuleEffect
BashMatches all Bash commands
WebFetchMatches all web fetch requests
ReadMatches 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:

RuleEffect
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.

Tool-specific permission rules

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.

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:

PatternMeaningExampleMatches
//pathAbsolute path from filesystem rootRead(//Users/alice/secrets/**)/Users/alice/secrets/**
~/pathPath from home directoryRead(~/Documents/*.pdf)/Users/alice/Documents/*.pdf
/pathPath relative to project rootEdit(/src/**/*.ts)<project root>/src/**/*.ts
path or ./pathPath relative to current directoryRead(*.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/

    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