> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/QwenLM/qwen-code/llms.txt
> Use this file to discover all available pages before exploring further.

# Permission Modes

> Control tool execution with permission modes and custom handlers

Permission modes control how the SDK handles tool execution approval. They provide different levels of control over which operations the AI can perform automatically.

## Permission Modes Overview

The SDK supports four built-in permission modes:

| Mode        | Description                                                                                                   | Use Case                        |
| ----------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------- |
| `default`   | Write tools denied unless approved via `canUseTool` or `allowedTools`. Read-only tools execute automatically. | Most interactive applications   |
| `plan`      | Blocks all write tools. AI presents a plan instead of executing.                                              | Planning and analysis workflows |
| `auto-edit` | Auto-approves edit tools (`edit`, `write_file`). Other tools require confirmation.                            | Code editing assistants         |
| `yolo`      | All tools execute automatically without confirmation.                                                         | Trusted automation scripts      |

## Default Mode

The safest interactive mode. Write operations require explicit approval.

### Behavior

* **Read-only tools**: Execute automatically (e.g., `read_file`, `list_directory`)
* **Write tools**: Denied unless approved via `canUseTool` callback or in `allowedTools`
* **Shell commands**: Require approval

### Example

```typescript theme={null}
import { query } from '@qwen-code/sdk';

const result = query({
  prompt: 'Read package.json and create a backup',
  options: {
    permissionMode: 'default',
    canUseTool: async (toolName, input) => {
      // Read operations: auto-approve
      if (toolName === 'read_file') {
        return { behavior: 'allow', updatedInput: input };
      }
      
      // Write operations: ask user
      const approved = await askUser(`Allow ${toolName} on ${input.path}?`);
      if (approved) {
        return { behavior: 'allow', updatedInput: input };
      }
      
      return { behavior: 'deny', message: 'User denied permission' };
    },
  },
});
```

### Without canUseTool

If no `canUseTool` callback is provided, write tools are automatically denied:

```typescript theme={null}
const result = query({
  prompt: 'Create a new file',
  options: {
    permissionMode: 'default',
    // No canUseTool - write operations will be denied
  },
});
```

## Plan Mode

Blocks all write operations. The AI explains what it would do instead of executing.

### Behavior

* **Read-only tools**: Execute normally
* **Write tools**: Blocked (AI instructed to present a plan)
* **Special**: `exit_plan_mode` tool allowed (if available)

### Example

```typescript theme={null}
const result = query({
  prompt: 'How would you refactor this codebase?',
  options: {
    permissionMode: 'plan',
  },
});

for await (const message of result) {
  if (message.type === 'assistant') {
    // AI will explain the refactoring plan instead of executing
    console.log(message.message.content);
  }
}
```

### Use Cases

* Getting implementation plans before execution
* Code review and suggestions
* Architecture analysis
* Exploration without modification

## Auto-Edit Mode

Auto-approves file editing operations while requiring confirmation for other tools.

### Behavior

* **Edit tools** (`edit`, `write_file`): Execute automatically
* **Other write tools**: Require approval via `canUseTool` or `allowedTools`
* **Read-only tools**: Execute automatically

### Example

```typescript theme={null}
const result = query({
  prompt: 'Fix all TypeScript errors in the src/ directory',
  options: {
    permissionMode: 'auto-edit',
    // File edits happen automatically
    // Other operations (like shell commands) would need approval
  },
});
```

### With Additional Approvals

```typescript theme={null}
const result = query({
  prompt: 'Fix errors and run tests',
  options: {
    permissionMode: 'auto-edit',
    canUseTool: async (toolName, input) => {
      // Edits already auto-approved by mode
      // This only gets called for non-edit tools
      if (toolName === 'run_terminal_cmd' && input.command?.startsWith('npm test')) {
        return { behavior: 'allow', updatedInput: input };
      }
      return { behavior: 'deny', message: 'Not allowed' };
    },
  },
});
```

### Use Cases

* Code refactoring assistants
* Automated fix tools
* Documentation generators
* Bulk code updates

## YOLO Mode

Auto-approves all tools without confirmation. Use with extreme caution.

### Behavior

* **All tools**: Execute automatically
* **No callbacks**: `canUseTool` is never called
* **No restrictions**: Except tools in `excludeTools`

<Warning>
  YOLO mode grants the AI full access to file system operations and shell commands. Only use in trusted, isolated environments.
</Warning>

### Example

```typescript theme={null}
const result = query({
  prompt: 'Set up the project structure and install dependencies',
  options: {
    permissionMode: 'yolo',
    cwd: '/safe/isolated/directory',
  },
});
```

### Safe YOLO with Exclusions

Combine with `excludeTools` to prevent dangerous operations:

```typescript theme={null}
const result = query({
  prompt: 'Analyze and refactor the code',
  options: {
    permissionMode: 'yolo',
    excludeTools: [
      'delete_file',
      'run_terminal_cmd',
      'ShellTool(rm )',
      'ShellTool(git push)',
    ],
  },
});
```

### Use Cases

* Automated CI/CD pipelines in isolated environments
* Batch processing scripts
* Development environment setup
* Testing and experimentation in sandboxes

## Permission Priority Chain

Understanding the order of permission checks:

```
1. excludeTools          -> Blocks completely (highest priority)
   ↓
2. permissionMode: 'plan' -> Blocks non-read-only tools
   ↓
3. permissionMode: 'yolo' -> Auto-approves all tools
   ↓
4. allowedTools          -> Auto-approves matching tools
   ↓
5. canUseTool callback   -> Custom approval logic
   ↓
6. Default behavior      -> Auto-deny in SDK mode
```

### Example with Multiple Controls

```typescript theme={null}
const result = query({
  prompt: 'Modify the project',
  options: {
    permissionMode: 'default',
    
    // Highest priority - always blocked
    excludeTools: ['delete_file', 'ShellTool(rm )'],
    
    // Auto-approve these tools
    allowedTools: ['ShellTool(git status)', 'ShellTool(npm test)'],
    
    // Custom logic for everything else
    canUseTool: async (toolName, input) => {
      // This won't be called for:
      // - Tools in excludeTools (already blocked)
      // - Tools in allowedTools (already approved)
      // - Read-only tools (auto-approved in default mode)
      
      if (toolName === 'write_file') {
        return { behavior: 'allow', updatedInput: input };
      }
      
      return { behavior: 'deny', message: 'Not allowed' };
    },
  },
});
```

## Custom Permission Handler

The `canUseTool` callback provides fine-grained control over tool execution.

### Signature

```typescript theme={null}
type CanUseTool = (
  toolName: string,
  input: Record<string, unknown>,
  options: {
    signal: AbortSignal;
    suggestions?: PermissionSuggestion[] | null;
  }
) => Promise<PermissionResult>;

type PermissionResult =
  | {
      behavior: 'allow';
      updatedInput: Record<string, unknown>;
    }
  | {
      behavior: 'deny';
      message: string;
      interrupt?: boolean;
    };
```

### Parameters

<ParamField path="toolName" type="string" required>
  Name of the tool requesting permission.
</ParamField>

<ParamField path="input" type="Record<string, unknown>" required>
  Input parameters for the tool.
</ParamField>

<ParamField path="options.signal" type="AbortSignal" required>
  Signal for cancelling the permission request.
</ParamField>

<ParamField path="options.suggestions" type="PermissionSuggestion[] | null">
  Suggested actions from the CLI (if available).
</ParamField>

### Return Value

<ResponseField name="behavior" type="'allow' | 'deny'" required>
  Whether to allow or deny the tool execution.
</ResponseField>

<ResponseField name="updatedInput" type="Record<string, unknown>">
  Modified input parameters (only for `'allow'`). Return the original `input` if no modifications needed.
</ResponseField>

<ResponseField name="message" type="string">
  Explanation for denial (only for `'deny'`).
</ResponseField>

<ResponseField name="interrupt" type="boolean">
  Whether to interrupt the entire session on denial (only for `'deny'`).
</ResponseField>

### Examples

#### Allow with Modified Input

```typescript theme={null}
canUseTool: async (toolName, input) => {
  if (toolName === 'write_file') {
    // Redirect all writes to a safe directory
    return {
      behavior: 'allow',
      updatedInput: {
        ...input,
        path: `/safe/dir/${input.path}`,
      },
    };
  }
  return { behavior: 'deny', message: 'Not allowed' };
}
```

#### Deny with Interrupt

```typescript theme={null}
canUseTool: async (toolName, input) => {
  if (toolName === 'delete_file') {
    return {
      behavior: 'deny',
      message: 'File deletion is not allowed',
      interrupt: true, // Stop the entire session
    };
  }
  return { behavior: 'allow', updatedInput: input };
}
```

#### Path-Based Approval

```typescript theme={null}
canUseTool: async (toolName, input) => {
  if (toolName === 'write_file' || toolName === 'edit') {
    const path = input.path as string;
    
    // Only allow writes to specific directories
    if (path.startsWith('src/') || path.startsWith('tests/')) {
      return { behavior: 'allow', updatedInput: input };
    }
    
    return {
      behavior: 'deny',
      message: `Cannot modify files outside src/ and tests/: ${path}`,
    };
  }
  
  return { behavior: 'allow', updatedInput: input };
}
```

#### Interactive Approval

```typescript theme={null}
import * as readline from 'readline';

function askUser(question: string): Promise<boolean> {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  
  return new Promise((resolve) => {
    rl.question(`${question} (y/n): `, (answer) => {
      rl.close();
      resolve(answer.toLowerCase() === 'y');
    });
  });
}

const result = query({
  prompt: 'Modify the codebase',
  options: {
    permissionMode: 'default',
    canUseTool: async (toolName, input) => {
      // Auto-approve reads
      if (toolName.startsWith('read_') || toolName === 'list_directory') {
        return { behavior: 'allow', updatedInput: input };
      }
      
      // Ask user for writes
      const approved = await askUser(
        `Allow ${toolName}?\nInput: ${JSON.stringify(input, null, 2)}`
      );
      
      if (approved) {
        return { behavior: 'allow', updatedInput: input };
      }
      
      return { behavior: 'deny', message: 'User denied permission' };
    },
  },
});
```

## Allowed and Excluded Tools

### allowedTools

Auto-approve specific tools without calling `canUseTool`.

**Pattern matching:**

* Tool name: `'write_file'`, `'run_shell_command'`
* Tool class: `'WriteTool'`, `'ShellTool'`
* Shell command prefix: `'ShellTool(git status)'`

```typescript theme={null}
options: {
  permissionMode: 'default',
  allowedTools: [
    'read_file',                    // Specific tool
    'ShellTool(git status)',        // Git status commands
    'ShellTool(npm test)',          // npm test commands
    'ShellTool(ls)',                // ls commands
  ],
}
```

### excludeTools

Block specific tools completely (highest priority).

```typescript theme={null}
options: {
  permissionMode: 'yolo',
  excludeTools: [
    'delete_file',                  // Block file deletion
    'ShellTool(rm )',               // Block rm commands
    'ShellTool(git push)',          // Block git push
    'run_terminal_cmd',             // Block all terminal commands
  ],
}
```

## Timeout Configuration

The `canUseTool` callback must respond within a timeout period (default: 60 seconds).

```typescript theme={null}
options: {
  permissionMode: 'default',
  canUseTool: async (toolName, input) => {
    // Must respond within timeout
    return { behavior: 'allow', updatedInput: input };
  },
  timeout: {
    canUseTool: 120000, // 2 minutes
  },
}
```

If the timeout is exceeded, the tool request is automatically denied with a timeout error.

## Best Practices

### 1. Start with Default Mode

Use `default` mode with a custom `canUseTool` handler for most applications:

```typescript theme={null}
options: {
  permissionMode: 'default',
  canUseTool: async (toolName, input) => {
    // Implement your approval logic
  },
}
```

### 2. Use Plan Mode for Analysis

When you want suggestions without execution:

```typescript theme={null}
options: {
  permissionMode: 'plan',
}
```

### 3. Combine Modes with Tool Lists

Use `allowedTools` and `excludeTools` to fine-tune any mode:

```typescript theme={null}
options: {
  permissionMode: 'auto-edit',
  allowedTools: ['ShellTool(git status)'],
  excludeTools: ['delete_file', 'ShellTool(rm )'],
}
```

### 4. Validate Tool Input

Always validate and sanitize tool inputs:

```typescript theme={null}
canUseTool: async (toolName, input) => {
  if (toolName === 'write_file') {
    const path = input.path as string;
    
    // Validate path
    if (path.includes('..') || path.startsWith('/')) {
      return { behavior: 'deny', message: 'Invalid path' };
    }
    
    return { behavior: 'allow', updatedInput: input };
  }
  return { behavior: 'allow', updatedInput: input };
}
```

### 5. Log Permission Decisions

Log all permission decisions for audit trails:

```typescript theme={null}
canUseTool: async (toolName, input) => {
  const decision = /* your logic */;
  
  console.log({
    timestamp: new Date().toISOString(),
    toolName,
    input,
    decision: decision.behavior,
  });
  
  return decision;
}
```

## See Also

* [query() Function](/sdk/api/query) - Main API documentation
* [Custom Permissions Example](/sdk/examples/custom-permissions) - Detailed permission handler examples
* [Query Instance Methods](/sdk/api/query-instance) - Control permission mode during execution
