How the Kimi CLI Approval System Manages Tool Execution Permissions
The Kimi CLI approval system acts as a gatekeeper that decides whether a tool call may be executed by evaluating permission modes, routing requests through an approval runtime, and caching user decisions for the session.
The MoonshotAI/kimi-cli repository implements a robust permission framework that governs every external action performed by the CLI. This system intercepts tool invocations before execution, presents contextual information to the user, and maintains audit trails through integrated telemetry. Understanding how the approval system manages tool execution permissions is essential for configuring secure automation workflows and unattended operations.
Core Architecture and Entry Points
Every tool invocation in Kimi CLI flows through a centralized approval mechanism defined in src/kimi_cli/soul/approval.py. The architecture separates concerns between permission policy definition, runtime request handling, and result tracking.
The Approval.request Gatekeeper
The primary entry point is Approval.request(), a class method that every tool call must traverse before execution. Located in src/kimi_cli/soul/approval.py, this method receives the tool name, its arguments, and UI display blocks that will be shown to the user.
The method constructs a permission mode based on current session flags before determining whether to auto-approve, prompt the user, or reject the request. This design ensures that no external command executes without explicit policy evaluation.
Permission Modes and Session Flags
The system supports four distinct permission modes that control execution behavior:
yolo– Auto-approves every request, useful for "trust everything" automation scriptsafk– Auto-rejects every request, designed for unattended runs where no interaction is possibleauto_approve– Approves the request without prompting, but only for the current execution stepapprove_for_session– Prompts the user once and caches the decision for all subsequent identical calls during the session
These flags are manipulated programmatically through the Approval object using set_yolo(), set_afk(), and set_runtime_afk() methods.
The Approval Runtime and User Interaction
When a permission mode requires user confirmation, the system delegates to the approval runtime implemented in src/kimi_cli/approval_runtime/runtime.py.
ApprovalSource and Request Construction
The runtime creates an ApprovalSource record (defined in src/kimi_cli/approval_runtime/models.py) containing the session ID, tool name, and display surface derived from the first DisplayBlock.type. It then constructs an ApprovalRequest message defined in src/kimi_cli/wire/types.py and transmits it over the wire to the UI layer.
The shell visualizer renders this request, presenting the tool operation and arguments to the user for evaluation.
Response Handling and Execution Flow
The UI returns one of three responses: "approve", "approve_for_session", or "reject". The runtime translates this into an ApprovalResult object, where ApprovalResult.__bool__ returns True for approved responses to maintain compatibility with legacy boolean checks.
If the user rejects the request, ApprovalResult.rejection_error() constructs a ToolRejectedError from src/kimi_cli/tools/utils.py that propagates back to abort execution immediately.
Session Caching and Telemetry Integration
The approval system maintains state across long-running sessions and records comprehensive audit trails.
Persistent Session Decisions
When a user selects "approve for session", the approval runtime stores the decision in a session cache. Subsequent identical tool calls bypass the UI entirely and receive automatic approval, reducing friction while maintaining security boundaries for recurring operations.
Audit Trails via _track_permission_result
After every decision, the _track_permission_result method emits a permission_approval_result telemetry event. This records:
- The tool name and permission mode used
- The approval result and surface type
- Request latency and session cache updates
- Any user-provided feedback
This data flows through the Kimi CLI telemetry system defined in src/kimi_cli/telemetry.py, creating immutable audit trails for compliance and debugging.
Practical Implementation Examples
Respecting the Approval System in Custom Tools
# A tool implementation that respects the approval gate
async def run_git_pull():
# The toolset automatically calls Approval.request()
# before executing the actual git command
result = await some_tool.call(name="git_pull", args={"repo": "."})
if not result:
# User rejected the request - ToolRejectedError is raised
raise result.rejection_error()
return result
Configuring Permission Modes Programmatically
from kimi_cli.soul.approval import Approval
approval = Approval.shared()
# Enable auto-approval for all operations
approval.set_yolo(True)
# Ensure we are not auto-rejecting
approval.set_afk(False)
approval.set_runtime_afk(False)
Manual Approval Requests
# Direct usage (rarely needed - tools invoke this internally)
approval = Approval.shared()
decision = await approval.request(
tool_name="shell",
display=[DisplayBlock(type="shell", content="rm -rf /tmp/*")],
)
if decision:
# Approved - proceed with execution
pass
else:
# Rejected - handle gracefully
raise decision.rejection_error()
Summary
- Entry Point: Every tool call passes through
Approval.request()insrc/kimi_cli/soul/approval.pybefore execution - Permission Modes: Four modes (
yolo,afk,auto_approve,approve_for_session) control whether requests auto-approve, prompt, or reject - Runtime Flow: The approval runtime in
src/kimi_cli/approval_runtime/runtime.pycreatesApprovalSourcerecords and managesApprovalRequestmessages viasrc/kimi_cli/wire/types.py - Result Handling:
ApprovalResultobjects provide boolean evaluation andrejection_error()methods that raiseToolRejectedErrorfromsrc/kimi_cli/tools/utils.py - Session Management: "Approve for session" decisions cache permissions to bypass future prompts for identical operations
- Telemetry: The
_track_permission_resultfunction emitspermission_approval_resultevents throughsrc/kimi_cli/telemetry.pyfor complete audit trails
Frequently Asked Questions
How do I enable automatic approval for all tool executions in Kimi CLI?
Set the yolo permission mode by calling Approval.shared().set_yolo(True) in your script or configuration. This mode auto-approves every request without user interaction, suitable for trusted automation environments. Remember that this disables all safety prompts, so use it only with verified toolsets.
What happens when a tool execution is rejected by the user?
When rejected, the ApprovalResult.rejection_error() method generates a ToolRejectedError defined in src/kimi_cli/tools/utils.py. This exception propagates back through the call stack, aborting the tool execution and allowing the calling code to handle the rejection gracefully or terminate the operation.
How does Kimi CLI remember my approval decisions across multiple commands?
The approval runtime maintains a session cache stored in src/kimi_cli/approval_runtime/runtime.py. When you select "approve for session", the runtime stores a hash of the tool name and arguments. Subsequent identical calls match this cache entry and receive automatic approval without UI interaction until the session ends.
Can I programmatically check the current permission mode before executing a tool?
Yes. Access the shared Approval instance via Approval.shared() and inspect the current flags using the is_yolo(), is_afk(), or is_runtime_afk() methods available in src/kimi_cli/soul/approval.py. This allows conditional logic that adapts behavior based on the current permission context.
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 →