> ## Documentation Index > Fetch the complete documentation index at: https://vineetagarwal-code-claude-code.mintlify.app/llms.txt > Use this file to discover all available pages before exploring further. # Permissions API > Reference for permission modes, allow/deny rule syntax, and configuration methods for controlling which tools Claude Code can use without prompting. The permissions system controls whether Claude Code runs a tool immediately, prompts you for confirmation, or blocks the call entirely. You configure it through permission modes and rule lists that can be set globally, per project, or per session. ## Permission modes A permission mode sets the baseline behavior for all tool calls. Individual allow/deny rules can override this baseline for specific tools or commands. | Mode | Description | | ------------------- | -------------------------------------------------------------------------------------------------------------------------- | | `default` | Prompt for approval on potentially dangerous operations. Safe read-only tools run without prompting. | | `acceptEdits` | Auto-approve all file edit operations (`Write`, `Edit`, `MultiEdit`). Bash commands still prompt. | | `bypassPermissions` | Skip all permission checks. All tools run without prompting. Requires `allowDangerouslySkipPermissions: true` in settings. | | `plan` | Read-only planning mode. No tool execution; Claude can only read files and explain what it would do. | | `dontAsk` | Do not prompt the user. Deny any tool call that is not pre-approved by an explicit allow rule. | `bypassPermissions` mode disables all safeguards. Only use it in sandboxed environments or CI pipelines where you fully control the input. The mode requires `allowDangerouslySkipPermissions: true` in your settings file. ### Setting the permission mode Pass `--permission-mode` to set the mode for a single invocation: ```bash theme={null} claude --permission-mode acceptEdits claude --permission-mode bypassPermissions --dangerously-skip-permissions claude --permission-mode plan ``` Set `defaultPermissionMode` in any Claude Code settings file to make it the default for all sessions in that scope: ```json theme={null} { "defaultPermissionMode": "acceptEdits" } ``` Settings files load in this priority order (highest wins): * `.claude/settings.local.json` — local overrides, not committed * `.claude/settings.json` — project-level defaults * `~/.claude/settings.json` — user-level defaults Run `/permissions` inside a session to open the interactive permissions panel where you can view and edit allow/deny rules. Session-level changes are not persisted to disk. ``` /permissions ``` Change the permission mode programmatically via the control protocol: ```json theme={null} { "type": "control_request", "request_id": "pm-1", "request": { "subtype": "set_permission_mode", "mode": "acceptEdits" } } ``` *** ## Permission rules Rules let you pre-approve or block specific tools and commands without changing the global permission mode. Rules are additive across settings scopes — allow rules from all files merge together. ### Configuration format ```json theme={null} { "permissions": { "allow": [ "Bash(git *)", "Bash(npm run *)", "Read", "Write(src/**)", "mcp__myserver" ], "deny": [ "Bash(rm -rf *)", "Bash(curl * | bash)", "Write(/etc/**)" ] } } ``` Rules that auto-approve matching tool calls without prompting. Rules that unconditionally block matching tool calls. Deny rules always take precedence over allow rules. If both an allow rule and a deny rule match a tool call, the call is blocked. ### Rule syntax A rule is a string that matches a tool name, optionally with a parenthesized content pattern. **Tool name only** — matches every call to that tool: ``` Read Write Edit Bash ``` **Tool name with content pattern** — matches calls where the tool's primary input matches the glob: ``` Bash(git *) Bash(npm run *) Write(src/*) Edit(*.ts) ``` For `Bash`, the pattern is matched against the full command string. For file tools (`Write`, `Edit`, `Read`, `Glob`), the pattern is matched against the file path argument. **MCP server** — matches all tools from a specific MCP server: ``` mcp__myserver ``` **MCP server wildcard** — same as above, explicit wildcard form: ``` mcp__myserver__* ``` **Specific MCP tool** — matches one tool from a server: ``` mcp__myserver__query_database ``` **Agent type** — blocks or allows a specific subagent: ``` Agent(Explore) Agent(CodeReviewer) ``` ### Pattern matching for `Bash` Bash rule patterns use shell-style glob matching on the full command string. ```json theme={null} { "permissions": { "allow": [ "Bash(git status)", "Bash(git log *)", "Bash(git diff *)", "Bash(npm run test*)", "Bash(make *)" ], "deny": [ "Bash(rm *)", "Bash(sudo *)", "Bash(* | bash)", "Bash(* | sh)" ] } } ``` Bash patterns match prefix-first. A rule like `Bash(git *)` matches `git status`, `git log --oneline`, and `git push --force`. Be specific when writing deny rules. ### Pattern matching for file tools File path patterns are matched against the absolute path of the file being read, written, or edited. ```json theme={null} { "permissions": { "allow": [ "Write(src/**)", "Write(tests/**)", "Edit(*.md)", "Read" ], "deny": [ "Write(/etc/**)", "Write(~/.ssh/**)", "Edit(.env*)" ] } } ``` *** ## Permission rule sources and priority Rules are collected from multiple sources and evaluated in a defined order. When the same tool call matches rules from different sources, deny takes precedence over allow, and the most restrictive result wins. | Source | Where configured | Editable | | ----------------- | -------------------------------------------- | -------------- | | `policySettings` | Managed policy layer | No | | `flagSettings` | CLI flags and SDK control requests | Per-session | | `userSettings` | `~/.claude/settings.json` | Yes | | `projectSettings` | `.claude/settings.json` | Yes | | `localSettings` | `.claude/settings.local.json` | Yes | | `cliArg` | `--allowedTools` / `--disallowedTools` flags | Per-invocation | | `session` | `/permissions` command, SDK updates | Per-session | ### `--allowedTools` and `--disallowedTools` CLI flags Pass comma-separated rule strings directly on the command line: ```bash theme={null} claude --allowedTools "Bash(git *),Read,Write" --print "Run the tests" claude --disallowedTools "Bash,Write" --print "Summarize this project" ``` These map to the `cliArg` source and apply for the duration of the invocation. *** ## Permission decisions The permission engine evaluates each tool call through a pipeline and returns one of three outcomes. | Decision | Meaning | | -------- | ------------------------------------------------------ | | `allow` | Tool runs immediately. | | `ask` | User is prompted for confirmation. | | `deny` | Tool call is blocked; Claude receives an error result. | ### Decision pipeline Claude Code evaluates tool calls in this order: 1. **Deny rules** — if any deny rule matches, the call is blocked immediately. 2. **Ask rules** — if any ask rule matches, the permission dialog is shown. 3. **Tool's own permission check** — the tool's `checkPermissions` method runs (e.g., Bash checks individual subcommands). 4. **Safety checks** — paths inside `.git/`, `.claude/`, `.vscode/`, and shell config files always prompt, even in `bypassPermissions` mode. 5. **Mode check** — `bypassPermissions` and plan mode apply here. 6. **Allow rules** — if an allow rule matches, the call is approved. 7. **Default behavior** — if no rule matched, prompt the user. Safety checks (step 4) are bypass-immune. Even with `bypassPermissions` mode, Claude Code will prompt before modifying files in `.git/` or shell configuration files like `~/.bashrc`. *** ## Working directories By default, Claude Code restricts file operations to the current working directory and its subdirectories. You can grant access to additional directories. ### Via CLI flag ```bash theme={null} claude --add-dir /path/to/extra/dir ``` ### Via settings ```json theme={null} { "permissions": { "additionalDirectories": [ "/shared/data", "/home/user/configs" ] } } ``` ### Via SDK control request ```json theme={null} { "type": "control_request", "request_id": "dirs-1", "request": { "subtype": "apply_flag_settings", "settings": { "permissions": { "additionalDirectories": ["/shared/data"] } } } } ``` *** ## Permission updates via the SDK SDK hosts (IDEs, desktop apps) can respond to `can_use_tool` control requests and include permission updates to persist rule changes alongside their decisions. ### `PermissionUpdate` object ```json theme={null} { "type": "addRules", "rules": [ { "toolName": "Bash", "ruleContent": "git *" } ], "behavior": "allow", "destination": "userSettings" } ``` The update operation. Rules to add, replace, or remove. Each rule has `toolName` and an optional `ruleContent` (the parenthesized pattern). Which rule list to modify. Where to persist the update. `session` applies only to the current session; `userSettings`, `projectSettings`, and `localSettings` write to the corresponding settings files on disk. ### Permission decision response When responding to a `can_use_tool` request, include `updatedPermissions` to persist rule changes: ```json theme={null} { "type": "control_response", "response": { "subtype": "success", "request_id": "", "response": { "behavior": "allow", "updatedPermissions": [ { "type": "addRules", "rules": [{ "toolName": "Bash", "ruleContent": "git *" }], "behavior": "allow", "destination": "userSettings" } ], "decisionClassification": "user_permanent" } } } ``` The permission decision. Modified tool input to use instead of the original. Only valid when `behavior` is `"allow"`. Permission rule updates to apply and persist alongside this decision. How the user responded, for telemetry. `user_temporary` for allow-once; `user_permanent` for always-allow; `user_reject` for deny. *** ## Hooks and permissions `PreToolUse` and `PermissionRequest` hooks can inject permission decisions programmatically. See [Hooks reference](/reference/sdk/hooks-reference) for details on `permissionDecision` output and `hookSpecificOutput.decision`. The hook-based permission flow is especially useful for headless agents that cannot show interactive prompts. When `shouldAvoidPermissionPrompts` is true (background agent mode), Claude Code runs `PermissionRequest` hooks before falling back to auto-deny. *** ## Safety recommendations Use `bypassPermissions` only in isolated, short-lived environments where you control all inputs. Set explicit deny rules for destructive operations as a defense-in-depth measure: ```json theme={null} { "defaultPermissionMode": "bypassPermissions", "allowDangerouslySkipPermissions": true, "permissions": { "deny": [ "Bash(rm -rf *)", "Bash(sudo *)", "Bash(curl * | bash)" ] } } ``` Use `default` mode with allow rules for common safe operations. This minimizes interruptions while keeping you in control of destructive actions: ```json theme={null} { "defaultPermissionMode": "default", "permissions": { "allow": [ "Read", "Glob", "Grep", "Bash(git status)", "Bash(git log *)", "Bash(git diff *)", "Bash(npm run *)", "Bash(make *)" ] } } ``` Use `plan` mode when you want Claude to reason about code without making any changes. Claude can read files and explain what it would do, but cannot write, edit, or run commands: ```bash theme={null} claude --permission-mode plan "Explain the architecture of this codebase" ``` Use `dontAsk` mode combined with an SDK `PermissionRequest` hook to replace the interactive dialog with your own approval UI. The hook receives every tool call that would have prompted and can allow, deny, or forward it to a human reviewer: ```json theme={null} { "defaultPermissionMode": "dontAsk", "permissions": { "allow": [ "Read", "Bash(git *)" ] } } ``` Any tool call not matching an allow rule is sent to your `PermissionRequest` hook handler instead of being auto-denied. Built with [Mintlify](https://mintlify.com).