File: permissions.md | Updated: 11/15/2025
Agent Skills are now available! Learn more about extending Claude's capabilities with Agent Skills .
English
Search...
Ctrl K
Search...
Navigation
Guides
Handling Permissions
Home Developer Guide API Reference Model Context Protocol (MCP) Resources Release Notes
On this page
The Claude Agent 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 the canUseTool callback, hooks, and settings.json permission rules. For complete API documentation, see the TypeScript SDK reference
.
The Claude Agent SDK provides four complementary ways to control tool usage:
Use cases for each approach:
canUseTool - Dynamic approval for uncovered cases, prompts user for permissionAllow Deny Ask Continue Match No Match Match No Match Match No Match bypassPermissions Other modes Allow Deny
Tool request
PreToolUse Hook
Execute Tool
Denied
canUseTool Callback
Check Deny Rules
Check Allow Rules
Check Ask Rules
Permission Mode?
Feedback to agent
PostToolUse Hook
Tool Response
Processing Order: PreToolUse Hook → Deny Rules → Allow Rules → Ask Rules → Permission Mode Check → canUseTool Callback → PostToolUse Hook
Permission modes provide global control over how Claude uses tools. You can set the permission mode when calling query() 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:
TypeScript
Python
Copy
import { query } from "@anthropic-ai/claude-agent-sdk";
const result = await query({
prompt: "Help me refactor this code",
options: {
permissionMode: 'default' // Standard permission mode
}
});
2. Dynamic Mode Changes (Streaming Only)
Change the mode during a streaming session:
TypeScript
Python
Copy
import { query } from "@anthropic-ai/claude-agent-sdk";
// Create an async generator for streaming input
async function* streamInput() {
yield {
type: 'user',
message: {
role: 'user',
content: "Let's start with default permissions"
}
};
// Later in the conversation...
yield {
type: 'user',
message: {
role: 'user',
content: "Now let's speed up development"
}
};
}
const q = query({
prompt: streamInput(),
options: {
permissionMode: 'default' // Start in default mode
}
});
// Change mode dynamically
await q.setPermissionMode('acceptEdits');
// Process messages
for await (const message of q) {
console.log(message);
}
Mode-Specific Behaviors
Accept Edits Mode (acceptEdits)
In accept edits mode:
Auto-approved operations:
Bypass Permissions Mode (bypassPermissions)
In bypass permissions mode:
Mode Priority in Permission Flow
Permission modes are evaluated at a specific point in the permission flow:
bypassPermissions mode - If active, allows all remaining toolscanUseTool callbackcanUseTool callback - Handles remaining casesThis means:
bypassPermissions modebypassPermissions mode overrides the canUseTool callback for unmatched toolsBest Practices
Example of mode progression:
Copy
// Start in default mode for controlled execution
permissionMode: 'default'
// Switch to acceptEdits for rapid iteration
await q.setPermissionMode('acceptEdits')
The canUseTool 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 acceptEdits mode. Here’s a complete example showing how to implement interactive tool approval:
TypeScript
Python
Copy
import { query } from "@anthropic-ai/claude-agent-sdk";
async function promptForToolApproval(toolName: string, input: any) {
console.log("\n🔧 Tool Request:");
console.log(` Tool: ${toolName}`);
// Display tool parameters
if (input && Object.keys(input).length > 0) {
console.log(" Parameters:");
for (const [key, value] of Object.entries(input)) {
let displayValue = value;
if (typeof value === 'string' && value.length > 100) {
displayValue = value.substring(0, 100) + "...";
} else if (typeof value === 'object') {
displayValue = JSON.stringify(value, null, 2);
}
console.log(` ${key}: ${displayValue}`);
}
}
// Get user approval (replace with your UI logic)
const approved = await getUserApproval();
if (approved) {
console.log(" ✅ Approved\n");
return {
behavior: "allow",
updatedInput: input
};
} else {
console.log(" ❌ Denied\n");
return {
behavior: "deny",
message: "User denied permission for this tool"
};
}
}
// Use the permission callback
const result = await query({
prompt: "Help me analyze this codebase",
options: {
canUseTool: async (toolName, input) => {
return promptForToolApproval(toolName, input);
}
}
});
Was this page helpful?
YesNo
Streaming Input Session Management
Assistant
Responses are generated using AI and may contain mistakes.