SDK Permissions
The Claude Code SDK provides powerful permission controls that allow you to manage how Claude uses tools in your application. This guide covers how to implement permission systems using thecanUseTool
callback, hooks, and settings.json permission rules. For complete API documentation, see the TypeScript SDK reference.
Overview
The Claude Code SDK provides four complementary ways to control tool usage:- Permission Modes - Global permission behavior settings that affect all tools
- canUseTool callback - Runtime permission handler for cases not covered by other rules
- Hooks - Fine-grained control over every tool execution with custom logic
- Permission rules (settings.json) - Declarative allow/deny rules with integrated bash command parsing
- Permission modes - Set overall permission behavior (planning, auto-accepting edits, bypassing checks)
canUseTool
- Dynamic approval for uncovered cases, prompts user for permission- Hooks - Programmatic control over all tool executions
- Permission rules - Static policies with intelligent bash command parsing
Permission Flow Diagram
Processing Order: PreToolUse Hook → Ask Rules → Deny Rules → Permission Mode Check → Allow Rules → canUseTool Callback → PostToolUse HookPermission Modes
Permission modes provide global control over how Claude uses tools. You can set the permission mode when callingquery()
or change it dynamically during streaming sessions.
Available Modes
The SDK supports four permission modes, each with different behavior:Mode | Description | Tool Behavior |
---|---|---|
default | Standard permission behavior | Normal permission checks apply |
plan | Planning mode - no execution | Claude can only use read-only tools; presents a plan before execution (Not currently supported in SDK) |
acceptEdits | Auto-accept file edits | File edits and filesystem operations are automatically approved |
bypassPermissions | Bypass all permission checks | All tools run without permission prompts (use with caution) |
Setting Permission Mode
You can set the permission mode in two ways:1. Initial Configuration
Set the mode when creating a query:2. Dynamic Mode Changes (Streaming Only)
Change the mode during a streaming session:Mode-Specific Behaviors
Accept Edits Mode (acceptEdits
)
In accept edits mode:
- All file edits are automatically approved
- Filesystem operations (mkdir, touch, rm, etc.) are auto-approved
- Other tools still require normal permissions
- Speeds up development when you trust Claude’s edits
- Useful for rapid prototyping and iterations
- File edits (Edit, MultiEdit, Write tools)
- Bash filesystem commands (mkdir, touch, rm, mv, cp)
- File creation and deletion
Bypass Permissions Mode (bypassPermissions
)
In bypass permissions mode:
- ALL tool uses are automatically approved
- No permission prompts appear
- Hooks still execute (can still block operations)
- Use with extreme caution - Claude has full system access
- Recommended only for controlled environments
Mode Priority in Permission Flow
Permission modes are evaluated at a specific point in the permission flow:- Hooks execute first - Can override any mode
- Deny rules are checked - Block tools regardless of mode
bypassPermissions
mode - If active, allows all remaining tools- Allow rules are checked
- Other modes affect specific tool behaviors
canUseTool
callback - Handles remaining cases
- Hooks can always block tool use, even in
bypassPermissions
mode - Explicit deny rules override all permission modes
bypassPermissions
mode overrides allow rules andcanUseTool
Best Practices
- Use default mode for controlled execution with normal permission checks
- Use acceptEdits mode when working on isolated files or directories
- Avoid bypassPermissions in production or on systems with sensitive data
- Combine modes with hooks for fine-grained control
- Switch modes dynamically based on task progress and confidence
canUseTool
ThecanUseTool
callback is passed as an option when calling the query
function. It receives the tool name and input parameters, and must return a decision- either allow or deny.
canUseTool fires whenever Claude Code would show a permission prompt to a user, e.g. hooks and permission rules do not cover it and it is not in autoaccept mode.
Here’s a complete example showing how to implement interactive tool approval:
Using Hooks for Tool Control
Hooks provide programmatic control over tool execution at various stages. Hooks are called for every tool use, giving you complete control over the permission pipeline.Hook Implementation
Key Differences from canUseTool
- Scope: Hooks are called for all tool uses;
canUseTool
handles cases not covered by permission rules - Control: Hooks require parsing and validating inputs yourself
- Events: Hooks support multiple events (PreToolUse, PostToolUse, etc.) for different stages
Using Permission Rules (settings.json)
Permission rules insettings.json
provide declarative control with built-in bash command parsing. These rules are evaluated before canUseTool
is called. For more details on settings configuration, see the Claude Code settings documentation.
Configuration Structure
Rule Syntax
Permission rules follow the pattern:ToolName(pattern)
- Bash rules: Use prefix matching (not regex). Example:
Bash(npm:*)
matches any command starting with “npm” - File rules: Support glob patterns. Example:
Read(./src/**/*.ts)
matches TypeScript files in src - Tool-only rules: Omit parentheses to control entire tools. Example:
WebFetch
blocks all web fetches
Using with SDK
While rules cannot be set programtically in the SDK yet, they will be read from the settings.json file in the path that the SDK is loaded in.Permission Evaluation Order
- Deny rules are checked first - if matched, tool use is blocked
- Allow rules are checked next - if matched, tool use is permitted
- Ask rules are checked - if matched, user is prompted
- canUseTool callback is invoked for any remaining cases
Bash Command Parsing
The SDK includes an integrated bash parser that understands command structure:- Handles pipes, redirects, and command substitution
- Recognizes dangerous patterns like
rm -rf
orcurl | sh
- Supports wildcards and prefix matching
Bash(git:*)
- Matches any git commandBash(npm run test)
- Matches exact commandBash(npm run test:*)
- Matches npm run test:unit, test:integration, etc.
Best Practices
- Start with default mode for standard permission checks
- Use permission rules for static policies, especially bash commands (see permission settings)
- Use hooks to log, audit, or transform all tool uses (see hook types)
- Use canUseTool for dynamic decisions on uncovered cases (see CanUseTool type)
- Layer defenses by combining modes, rules, hooks, and callbacks for critical applications