# How OpenClaude's Permission System Controls Tool Execution: A Deep Dive into the SDK Architecture

> Explore OpenClaude's SDK architecture and its permission system. Learn how it controls tool execution with user-defined modes and secures approval for automatic clearance.

- Repository: [Gitlawb/openclaude](https://github.com/Gitlawb/openclaude)
- Tags: deep-dive
- Published: 2026-09-08

---

**OpenClaude employs a layered permission model centered in [`src/entrypoints/sdk/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/entrypoints/sdk/permissions.ts) that validates every tool execution against user-defined modes, emitting `permission_request` messages for human approval when automatic clearance is unavailable.**

The **permission system** in the Gitlawb/openclaude repository acts as a security gatekeeper for all tool operations, determining whether commands like Bash, PowerShell, or MCP-provided tools may execute during a session. This architecture ensures that potentially dangerous operations require explicit user consent while allowing trusted workflows to proceed automatically. Understanding how this system controls tool execution is essential for both SDK consumers and host implementers building on top of the OpenClaude platform.

## Understanding the Permission Architecture

The core permission logic resides in [`src/entrypoints/sdk/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/entrypoints/sdk/permissions.ts), where the SDK constructs a **tool-permission context** at session initialization. This context captures the active permission mode and any custom allow or deny rules that govern subsequent execution attempts.

### Permission Context Construction

When a session starts, the SDK invokes `buildPermissionContext()` to establish the security boundary for the current interaction. According to the source code at `src/entrypoints/sdk/permissions.ts#L4-L5`, this initialization captures the current **permission mode**—which may be `default`, `acceptEdits`, `bypass-permissions`, `fullAccess`, or `plan`—alongside any granular allow or deny rules configured by the user. This context object becomes the authoritative source for all subsequent permission checks during the session lifecycle.

### Mode Mapping and Validation

User-supplied permission strings are mapped to the internal `PermissionMode` enum defined in [`src/types/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/types/permissions.ts). The SDK validates these mappings strictly: if a user requests an unsupported bypass mode, the system raises a clear error unless the `allowDangerouslySkipPermissions` flag is explicitly set. As implemented in `src/entrypoints/sdk/permissions.ts#L183-L204`, this validation layer prevents accidental escalation to dangerous modes like `fullAccess` without proper administrative acknowledgment.

## How the canUseTool Wrapper Enforces Security

Every tool in the OpenClaude ecosystem calls the `canUseTool` function before executing its core logic. This wrapper function, created via `createDefaultCanUseTool()` from [`src/utils/permissions/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/utils/permissions/permissions.ts), implements the decision engine that determines whether execution proceeds, pauses for approval, or terminates with a denial.

### Automatic Approval Flow

When the active permission mode pre-approves a specific tool category, the `canUseTool` wrapper returns an immediate approval decision without user intervention. For example, when operating in `acceptEdits` mode, file modification tools receive automatic clearance while system commands still trigger permission requests. This conditional logic at `src/entrypoints/sdk/permissions.ts#L255-L259` allows high-trust workflows to maintain speed while preserving security boundaries for sensitive operations.

### Interactive Permission Requests

If a tool lacks pre-approval from the current mode, the SDK emits a **`permission_request`** message to the host stream. Host implementations—whether CLI clients, VS Code extensions, or remote servers—receive this message and present an interactive prompt to the user. The host then responds with a `permission_response` message containing the decision and the original `request_id`. This architecture decouples the permission policy engine from the user interface, allowing diverse host implementations to present appropriate confirmation dialogs.

### Timeout Handling

The permission system implements defensive timeouts to prevent indefinite blocking. If the host fails to respond to a `permission_request` within the default 30-second window, the SDK automatically emits a **`permission_timeout`** message as defined at `src/entrypoints/sdk/permissions.ts#L36-L42`. Upon timeout, the tool execution receives a denial decision, ensuring that hung or unresponsive hosts cannot leave dangerous operations pending indefinitely.

## Implementation Details for Developers

Developers integrating with the OpenClaude SDK can configure permission behavior through the `query()` function or interact directly with the low-level permission API.

To execute a query with automatic edit acceptance:

```typescript
import { query } from '@openclaude/sdk';

// Accept any file-edit tool without prompting
await query({
  prompt: 'Rename the file "old.txt" to "new.txt".',
  permissionMode: 'acceptEdits',          // ← auto-accept edits
});

```

For custom tool implementations requiring explicit permission checks:

```typescript
import { createDefaultCanUseTool } from '../../utils/permissions/permissions.js';
import { buildPermissionContext } from '../../entrypoints/sdk/permissions.js';

const permCtx = buildPermissionContext({ permissionMode: 'default' });
const canUseTool = createDefaultCanUseTool(permCtx);

// Example tool implementation
async function runBash(cmd: string) {
  const decision = await canUseTool({ name: 'bash', input: { cmd } });
  if (!decision.approved) throw new Error('Permission denied');
  // ...execute the command...
}

```

Host developers handling permission requests must listen for the dedicated event:

```typescript
engine.on('permission_request', async msg => {
  const answer = await promptUser(`Allow ${msg.tool_name}?`);
  engine.send({
    type: 'permission_response',
    request_id: msg.request_id,
    decision: answer ? 'allow' : 'deny',
  });
});

```

## Security-By-Default Design

OpenClaude implements a **secure-by-default** posture where tools execute only when explicitly allowed by the active mode or through direct user approval. When no `canUseTool` callback is supplied and the permission request cannot resolve—either through timeout or host failure—the system denies execution with a clear error message as implemented at `src/entrypoints/sdk/permissions.ts#L702-L708`.

Dangerous modes including `bypass-permissions` and `fullAccess` require the `--allow-dangerously-skip-permissions` CLI flag and an explicit confirmation handler to activate. This gating mechanism at `src/entrypoints/sdk/permissions.ts#L166-L173` ensures that unrestricted execution capabilities cannot be enabled accidentally through configuration errors.

## Summary

- **Layered Validation**: The permission system constructs a context at `src/entrypoints/sdk/permissions.ts#L4-L5` that combines mode selection with custom rules to govern tool execution.
- **Mode Mapping**: User-facing permission strings map to internal enums with strict validation that rejects dangerous modes unless `allowDangerouslySkipPermissions` is enabled.
- **Request/Response Protocol**: Unapproved tools trigger `permission_request` messages to hosts, which must respond within 30 seconds or face automatic timeout denial.
- **Default Denial**: When permission status cannot be determined, the system defaults to denying execution to maintain security boundaries.
- **Host Decoupling**: The architecture separates policy enforcement from UI presentation, allowing CLI, IDE, and remote implementations to handle prompts appropriately.

## Frequently Asked Questions

### What permission modes does OpenClaude support?

OpenClaude supports six primary permission modes defined in the source: `default` (interactive approval required), `acceptEdits` (automatic approval for file modifications), `plan` (read-only operations), `bypass-permissions` (dangerous, requires explicit flag), `fullAccess` (unrestricted execution, requires explicit flag), and custom configurations with specific allow or deny rules. Each mode maps to specific tool categories that may execute without interactive prompting.

### How does the permission timeout mechanism work?

The SDK enforces a 30-second timeout window for all permission requests emitted to hosts. If the host does not return a `permission_response` message within this window, the system automatically emits a `permission_timeout` event and denies the tool execution. This prevents indefinite blocking and ensures that network issues or unresponsive hosts cannot leave sensitive operations in a pending state.

### Can I bypass the permission system for automated workflows?

Yes, but only through explicit opt-in mechanisms. The `bypass-permissions` and `fullAccess` modes disable interactive checks, but activating these requires setting the `allowDangerouslySkipPermissions` flag to `true` and supplying an explicit confirmation handler. As implemented in the codebase, these modes are gated behind multiple validation checks to prevent accidental activation in production environments.

### Where is the permission logic implemented in the codebase?

The primary implementation resides in [`src/entrypoints/sdk/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/entrypoints/sdk/permissions.ts), which handles context construction, mode validation, and request emission. Low-level permission evaluation logic lives in [`src/utils/permissions/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/utils/permissions/permissions.ts), while type definitions for `PermissionMode` and related structures are defined in [`src/types/permissions.ts`](https://github.com/Gitlawb/openclaude/blob/main/src/types/permissions.ts). UI components for mode selection appear in [`src/components/permissions/rules/PermissionModeTab.tsx`](https://github.com/Gitlawb/openclaude/blob/main/src/components/permissions/rules/PermissionModeTab.tsx).