---
title: "Configure Permissions"
aliases: [sdk-permissions, agent-permissions, permission-modes]
tags: [agent-sdk, permissions, tools, security, hooks]
sources: [raw/Configure permissions.md]
created: 2026-04-17
updated: 2026-04-17
---

# Configure Permissions

Control how your agent uses tools using permission modes, allow/deny rules, and hooks. The SDK evaluates these in a fixed order every time Claude requests a tool.

## Permission Evaluation Order

When Claude requests a tool, the SDK checks in this sequence:

1. **Deny rules** (`disallowed_tools`) — always checked first; hard block in every mode
2. **Allow rules** (`allowed_tools`) — pre-approves listed tools
3. **Hooks** — custom code that can allow, deny, or modify
4. **Permission mode** — global fallback behavior
5. **`canUseTool` callback** — runtime user approval (only called in `default` mode)

## Allow and Deny Rules

| Option | Effect |
|--------|--------|
| `allowed_tools=["Read", "Grep"]` | Listed tools auto-approved; unlisted tools fall through to mode/callback |
| `disallowed_tools=["Bash"]` | Always denied — overrides even `bypassPermissions` |

- **Deny rules win everywhere** — `disallowed_tools` is checked before the mode, so it blocks even `bypassPermissions`
- **`allowed_tools` does not constrain `bypassPermissions`** — unlisted tools still fall through to the mode, which approves everything; use `disallowed_tools` if you need to block specific tools while in bypass mode
- Rules can also be set declaratively in `.claude/settings.json` (requires `"project"` in `settingSources`)

### Locked-down headless pattern

```typescript
const options = {
  allowedTools: ["Read", "Glob", "Grep"],
  permissionMode: "dontAsk"   // anything not listed → hard deny, never prompts
};
```

## Permission Modes

Set via `permission_mode` (Python) or `permissionMode` (TypeScript) in `query()` options.

| Mode | Auto-approves | Calls `canUseTool`? | Use when |
|------|--------------|---------------------|----------|
| `default` | Nothing | Yes (unmatched tools) | Interactive sessions |
| `dontAsk` | `allowed_tools` + rule matches only | No — denies instead | Headless, fixed tool surface |
| `acceptEdits` | File edits + filesystem ops inside working dir | Yes (other tools) | Prototyping, isolated dir |
| `bypassPermissions` | Everything | No | Fully trusted, controlled env |
| `plan` | Nothing — no execution | No | Code review, propose-before-apply |
| `auto` *(TS only)* | Model classifier decides | No | Eliminate prompts automatically |

### acceptEdits — auto-approved operations

- `Edit`, `Write` tools
- Shell filesystem commands: `mkdir`, `touch`, `rm`, `rmdir`, `mv`, `cp`, `sed`
- Only for paths inside `cwd` or `additionalDirectories`; outside paths still prompt

### bypassPermissions — cautions

- Hooks still execute and can block
- `allowed_tools` has no effect — every tool is approved
- `disallowed_tools` and explicit `ask` rules still run before the mode check
- Subagents **inherit** this mode and cannot override it — they get full system access

### plan mode

- No tool execution at all
- Claude may call `AskUserQuestion` to clarify before finalizing the plan
- Good for code-review workflows where you approve before anything runs

## Setting Permission Mode at Runtime

```python
# Python — at query time
async for message in query(
    prompt="Help me refactor this code",
    options=ClaudeAgentOptions(permission_mode="default"),
):
    ...
```

For streaming sessions, the mode can also be changed dynamically while the session is active.

## Subagent Inheritance

When the parent uses `bypassPermissions`, `acceptEdits`, or `auto`, all subagents inherit that mode and it cannot be overridden per-subagent. Subagents may have less constrained system prompts, so `bypassPermissions` grants them full autonomous system access.

## Key Takeaways

- Deny rules (`disallowed_tools`) are absolute — they win in every mode, including `bypassPermissions`
- `allowed_tools` pre-approves tools but does **not** block unlisted ones; pair with `dontAsk` for a fixed surface
- `bypassPermissions` + `allowed_tools` still approves everything — use `disallowed_tools` to actually restrict
- `acceptEdits` is the sweet spot for coding agents: fast file edits, normal prompts for shell commands
- `plan` mode is zero-risk code review: Claude proposes, nothing executes
- Subagents inherit the parent's mode; `bypassPermissions` propagates fully

## Related Articles

- [[wiki/agent-sdk/hooks-guide|Hooks Guide]] — custom code that runs in the evaluation chain before the mode check
- [[wiki/agent-sdk/python-api-reference|Python API Reference]] — full `ClaudeAgentOptions` type with all permission fields
- [[wiki/agent-sdk/typescript-api-reference|TypeScript API Reference]] — `permissionMode`, `allowedTools`, `disallowedTools` options
- [[wiki/agent-sdk/overview|Agent SDK Overview]] — SDK capabilities and architecture

## Sources

- `raw/Configure permissions.md` (clipped from https://code.claude.com/docs/en/agent-sdk/permissions)
