How the Kimi CLI Approval System Controls Tool Execution Authorization
The Kimi CLI approval system intercepts every tool call through the Approval class in src/kimi_cli/soul/approval.py, validating execution context and routing requests through auto-approval logic or interactive user consent before allowing potentially destructive operations to proceed.
Kimi CLI implements a robust permission gate to prevent unauthorized tool execution. According to the MoonshotAI/kimi-cli source code, the approval system centered in src/kimi_cli/soul/approval.py provides both automatic and manual authorization paths while maintaining comprehensive audit trails for every decision.
Architecture of the Approval System
The approval workflow is orchestrated by the Approval class, which acts as a mandatory checkpoint between the AI agent and tool execution.
Core Entry Point and Context Validation
Tool implementations initiate authorization by invoking await approval.request(...). This method accepts four critical parameters:
- sender: The tool name (e.g.,
"shell","file_editor") - action: A machine-readable identifier for the operation
- description: Human-readable context for the UI
- display: Optional UI blocks (diffs, shell commands, etc.)
Before processing, the system validates that the call originates from an active tool execution context using get_current_tool_call_or_none. If validation fails, the method aborts immediately with a RuntimeError (lines 223-226).
Auto-Approval Modes for Unattended Operation
The approval system supports bypass mechanisms for automated workflows while preserving telemetry records.
Yolo and AFK Flags
When self.is_auto_approve() returns True (indicating Yolo or AFK mode), the system bypasses user interaction entirely. It emits a tool_approved telemetry event (lines 42-50) and returns ApprovalResult(approved=True) immediately.
Session-Wide Auto-Approval
Users can opt to approve specific actions for the entire session. The system maintains _state.auto_approve_actions as a registry of pre-authorized operations. When a request matches an entry in this cache, it receives automatic approval without UI interruption (lines 62-70).
Manual Authorization Flow
When no auto-approval rule applies, the system enters an interactive blocking flow:
- Request Registration: Creates a unique request ID and registers it with
ApprovalRuntime - UI Blocking: Suspends tool execution via
await self._runtime.wait_for_response(request_id) - User Response Processing: Handles three possible responses from the UI layer:
"approve": Executes the tool immediately"approve_for_session": Executes the tool and adds the action toauto_approve_actions(lines 70-78)"reject": Aborts execution and optionally raisesToolRejectedError
Session Cache Persistence
When a user selects "approve for session", the system resolves pending requests automatically. The resolve method updates all queued instances of the same action with approved_via_session_cache=True (lines 72-79), ensuring the UI reflects the updated authorization state without requiring individual confirmations.
Telemetry and Audit Trails
Every authorization decision records detailed metrics through _track_permission_result (lines 36-48). The telemetry captures:
- Step number and tool name
- Permission mode:
auto,yolo, ormanual - Result status:
approved,rejected,cancelled, orerror - Approval surface: Derived from the first
DisplayBlocktype - Duration and session cache writes
- User feedback content
This implementation mirrors the TypeScript permissionGateService contract (as noted in comments at line 47), ensuring compatibility with existing observability infrastructure.
Implementation Example
Tool developers integrate approval checks using the Approval class:
from kimi_cli.soul.approval import Approval
async def run_command(tool_input: str) -> str:
approval = Approval()
result = await approval.request(
sender="shell",
action="run_shell_command",
description=f"Execute: {tool_input}",
display=[DisplayBlock(type="shell", content=tool_input)],
)
if not result:
raise result.rejection_error()
return await execute_shell(tool_input)
The manual approval flow triggers automatically when the UI presents the request:
# When user selects "Approve for this session":
# 1. Action added to auto_approve_actions
# 2. Pending identical requests resolved via runtime.resolve()
# 3. Tool receives ApprovalResult(approved=True)
# 4. Telemetry logs tool_approved with session_cache_write=True
Summary
- Entry Point: The
Approval.requestmethod validates context and initiates authorization checks - Auto-Approval: Yolo/AFK flags and session caches bypass UI for trusted workflows
- Manual Flow: Blocking wait for user input with support for one-time or session-wide approval
- Persistence: Session caches automatically resolve pending identical requests
- Observability: Comprehensive telemetry tracks permission modes, results, and user feedback
Frequently Asked Questions
How does Kimi CLI prevent unauthorized tool execution?
The system validates every tool call originates from an active execution context using get_current_tool_call_or_none (lines 223-226). Without this validation, the request aborts immediately. Valid requests then route through the approval decision tree requiring explicit authorization unless auto-approved.
What is the difference between Yolo mode and session-wide approval?
Yolo mode (and AFK flags) bypasses all authorization checks immediately, automatically approving every request without UI interaction or persistence. Session-wide approval requires an initial manual approval with the "approve for session" option, which then persists that specific action to auto_approve_actions for the duration of the session while still logging telemetry for each execution.
How does the approval system track user decisions?
The _track_permission_result method (lines 36-48) records step numbers, tool identifiers, permission modes (auto/yolo/manual), results (approved/rejected/cancelled/error), approval surfaces, durations, and session cache writes. This data emits as tool_approved or tool_rejected events for audit trails.
Can tool executions be approved automatically without user interaction?
Yes. Two mechanisms enable automatic approval: global flags like Yolo/AFK mode that bypass all checks, or session-wide auto-approval where specific actions are pre-authorized after initial user consent. Both paths emit telemetry events and return ApprovalResult(approved=True) without blocking for UI input.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →