# How the Permission System Works in agent-core-v2: Understanding PermissionManager

> Explore the agent-core-v2 permission system centered on PermissionManager. Learn how configurable modes, rules, and policies control AI tool call execution, user approval, or blocking.

- Repository: [Moonshot AI/kimi-code](https://github.com/MoonshotAI/kimi-code)
- Tags: internals
- Published: 2026-07-25

---

**The permission system in agent-core-v2 centers around the `PermissionManager` class, which uses configurable modes, rules, and policy objects to decide whether AI tool calls execute automatically, require user approval, or are blocked entirely.**

In the MoonshotAI/kimi-code repository, the `agent-core-v2` package implements a sophisticated security layer that governs how AI agents interact with external tools. This system ensures that potentially dangerous operations—such as file deletions or network requests—are either automatically vetted, explicitly approved by users, or prevented based on customizable security policies.

## Core Architecture of the Permission System

The permission system is built around four fundamental concepts that work together to create a flexible, hierarchical security model.

### PermissionManager Class

At the heart of the system lies the `PermissionManager` class defined in [`src/agent/permission/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/src/agent/permission/index.ts). This class serves as the central authority for all permission decisions within an agent session. When initialized, it accepts an optional parent manager (enabling permission inheritance for sub-agents) and an array of initial rules【`PermissionManager` constructor (lines 35‑41)】.

The manager maintains an internal list of **permission policies** created via `createPermissionDecisionPolicies(this.agent)`, which are evaluated sequentially whenever a tool call is intercepted.

### Permission Modes: manual, auto, and yolo

The system supports three distinct **PermissionMode** values that determine default behavior:

- **`manual`** – Requires explicit user approval for every tool call
- **`auto`** – Automatically approves calls that policies deem safe
- **`yolo`** – Bypasses most security checks (use with caution)

The effective mode is resolved through a hierarchy: `modeOverride ?? parent?.mode ?? 'manual'`, allowing child agents to override parent settings while falling back to safe defaults【`mode` getter (lines 44‑46)】.

### Rules and Policies

**PermissionRule** objects define pattern-based matching against tool names or arguments, while **PermissionPolicy** objects implement the actual decision logic through an `evaluate(context)` method. When a tool call occurs, the manager constructs a **PermissionPolicyContext** containing the tool name, arguments, execution metadata, and trace ID, then consults policies until one returns a definitive decision.

## How Permission Evaluation Works

The permission flow follows a strict six-step pipeline that intercepts tool execution before any side effects occur.

### 1. Initialization and Policy Setup

When an agent spawns, it instantiates a `PermissionManager` with optional initial rules:

```typescript
const manager = new PermissionManager(agent, {
  initialRules: [{ pattern: 'git/*', mode: 'deny' }],
});

```

This setup creates the policy chain via `createPermissionDecisionPolicies`, which typically includes guards for plan-mode restrictions and dangerous operation blocks.

### 2. Tool Call Interception

Before any tool executes, the agent invokes `PermissionManager.beforeToolCall(context)`【`beforeToolCall` (lines 96‑110)】. This method acts as the gatekeeper, evaluating policies and converting their decisions into a `PrepareToolExecutionResult` that either allows execution, blocks it, or triggers the approval workflow.

### 3. Sequential Policy Evaluation

The `evaluatePolicies` method iterates through registered policies until one returns a non-undefined result【`evaluatePolicies` (lines 52‑60)】. Each policy can return:

- **`approve`** – Execute the tool immediately
- **`deny`** – Block execution with a formatted message【`formatPolicyDenyMessage` (lines 13‑18)】
- **`ask`** – Initiate user approval flow
- **`result`** – A custom `PrepareToolExecutionResult` for specialized handling

### 4. User Approval Workflow

When a policy returns `ask`, the system invokes `requestToolApproval`, which builds a display payload and fires a `PermissionRequest` hook to the client-side RPC【`requestToolApproval` (lines 16‑57, 59‑86, 100‑122)】. The method calls `rpc.requestApproval` and awaits one of three responses:

- **`Approved`** – The tool proceeds to execution
- **`Rejected`** or **`Cancelled`** – Execution halts with a user-friendly block message【`formatApprovalRejectionMessage` (lines 92‑110)】

### 5. Telemetry and Audit Logging

Every decision—whether allow, deny, or ask—is tracked via `agent.telemetry.track`, providing production visibility into permission behavior and helping developers identify patterns in tool usage or security violations.

## Implementing Custom Permission Rules

Developers can customize the permission system at runtime or during initialization:

```typescript
// Change mode dynamically based on UI preferences
manager.setMode('auto');

// Intercept and handle tool calls manually
async function runTool(context: PermissionPolicyContext) {
  const prepare = await manager.beforeToolCall(context);
  if (prepare?.block) {
    console.log('Blocked:', prepare.reason);
    return;
  }
  // Proceed with actual tool execution
}

```

The test suite demonstrates these patterns in action. For instance, [`enter-plan-mode.test.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/enter-plan-mode.test.ts) verifies that setting the permission mode correctly propagates to the RPC layer【line 8】, while [`plan-mode-hard-block.test.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/plan-mode-hard-block.test.ts) validates that denial policies generate appropriate block messages【lines 10‑15】.

## Key Source Files in agent-core-v2

Understanding the permission system requires familiarity with these specific files in the MoonshotAI/kimi-code repository:

- **[`src/agent/permission/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/src/agent/permission/index.ts)** – Core `PermissionManager` implementation with the constructor, mode resolution, and approval workflows
- **[`src/agent/permission/types.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/src/agent/permission/types.ts)** – TypeScript definitions for `PermissionMode`, `PermissionRule`, `PermissionPolicyContext`, and related interfaces
- **`src/agent/permission/policies/*`** – Built-in policy implementations including plan-mode guards and safety checks
- **`packages/agent-core/test/tools/planning/`** – Test suite covering permission flows including plan-mode transitions and hard blocks

## Summary

- The **PermissionManager** class in [`src/agent/permission/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/src/agent/permission/index.ts) serves as the central authority for tool execution decisions, supporting hierarchical permission inheritance.
- Three **PermissionMode** values (`manual`, `auto`, `yolo`) control default behavior, resolved via `modeOverride ?? parent?.mode ?? 'manual'`【lines 44‑46】.
- **Policies** evaluate tool calls sequentially via `evaluatePolicies`, returning decisions that either approve, deny, request user input, or provide custom results【lines 52‑60】.
- The **approval flow** leverages `requestToolApproval` to communicate with client-side RPC, handling `Approved`, `Rejected`, and `Cancelled` states with appropriate user messaging【lines 16‑122】.
- Comprehensive **telemetry** tracks every permission decision through `agent.telemetry.track`, enabling production monitoring of security boundaries.

## Frequently Asked Questions

### What is the difference between permission rules and permission policies in agent-core-v2?

**Permission rules** are pattern-based configurations (typically matching tool names like `git/*`) that define static constraints, while **permission policies** are executable objects with an `evaluate(context)` method that implement dynamic decision logic. Rules are stored in the manager and inherited from parents, whereas policies are instantiated via `createPermissionDecisionPolicies` and consulted at runtime to determine whether to approve, deny, or ask for each tool call.

### How does the permission system handle sub-agents or nested agent contexts?

The `PermissionManager` supports hierarchical permission through its constructor's optional `parent` parameter【lines 35‑41】. Child managers inherit rules and mode settings from their parents unless explicitly overridden. The mode resolution logic checks `modeOverride` first, then falls back to `parent?.mode`, and finally defaults to `'manual'`, ensuring that sub-agents maintain security boundaries while allowing specialized configurations【lines 44‑46】.

### Can the permission mode be changed dynamically during agent execution?

Yes, the permission mode can be modified at runtime using `manager.setMode()`, allowing the system to respond to UI changes or contextual shifts. For example, an agent might start in `manual` mode for safety, then switch to `auto` mode once it enters a sandboxed environment. However, mode changes only affect subsequent tool calls; they do not retroactively alter the status of operations already in flight.

### What happens when a user rejects a tool approval request?

When a user rejects or cancels an approval request, the `requestToolApproval` method records the result via `recordApprovalResult` and returns a blocked execution result containing a formatted rejection message【`formatApprovalRejectionMessage` (lines 92‑110)】. The tool call is prevented from executing, and the agent receives a descriptive message explaining that the operation was blocked due to user rejection or cancellation, allowing the agent to potentially suggest alternatives or halt the current task flow.