How Runtime and Agent Classes Interact in Kimi-CLI: Dependency Injection and Multi-Agent Architecture
The Runtime class acts as a service container that provides execution-time dependencies to the Agent class, which encapsulates system prompts and toolsets, while sub-agents receive deep-copied runtimes via copy_for_subagent to maintain shared state with role-specific isolation.
The interaction between Runtime and Agent classes forms the architectural backbone of the MoonshotAI/kimi-cli project. This design pattern decouples service management from agent logic, enabling sophisticated multi-agent workflows through runtime composition and inheritance. Understanding how these classes collaborate is essential for extending the framework or implementing custom agent behaviors.
The Runtime Service Container
Core Responsibilities
The Runtime dataclass serves as a comprehensive service locator that aggregates all execution-time dependencies a Kimi agent requires. It encapsulates session handling, configuration management, OAuth credentials, LLM access, notification systems, and background task management. When an agent needs to interact with external services or access configuration state, it retrieves these capabilities through its stored Runtime instance rather than instantiating them directly.
Factory Initialization via Runtime.create
The framework constructs runtimes through the Runtime.create class method defined in src/kimi_cli/soul/agent.py (lines 71-104). This factory method initializes a fully-populated runtime containing:
- Configuration objects and logger instances
- OAuth manager for authentication flows
- LLM client for model interactions
- Session state management
- Built-in system prompt arguments (
builtin_args) - Skill discovery mechanisms
- Notification and background task managers
from kimi_cli.soul.agent import Runtime
from kimi_cli.config import Config
from kimi_cli.auth.oauth import OAuthManager
from kimi_cli.llm import LLM
from kimi_cli.session import Session
runtime = await Runtime.create(
config=Config(...),
oauth=OAuthManager(...),
llm=LLM(...),
session=Session(...),
yolo=False,
)
Agent Class Integration with Runtime Services
The load_agent Bridge Function
The load_agent function in src/kimi_cli/soul/agent.py (lines 84-92) serves as the primary bridge between Runtime and Agent classes. This function receives a Runtime instance and uses it to:
- Render the system prompt via
_load_system_promptusing the runtime'sbuiltin_args - Register built-in sub-agent types in the runtime's
LaborMarket - Construct a dependency map (
tool_deps) that includes the runtime itself and its fields
The resulting Agent dataclass stores the original Runtime object directly, giving it persistent access to all underlying services throughout its lifecycle.
Dependency Injection Through tool_deps
The runtime propagates its services to individual tools through the tool_deps parameter. When KimiToolset initializes, it consumes this dependency map, allowing tools to access runtime fields such as configuration, session state, and LLM clients. This injection pattern ensures tools remain stateless while accessing shared resources.
from kimi_cli.tools.base import BaseTool
class EchoTool(BaseTool):
name = "echo"
async def run(self, message: str) -> str:
logger = self.runtime.config.logger
logger.info("EchoTool called")
return f"ECHO: {message}"
Sub-Agent Architecture and Runtime Inheritance
Deep Copying with copy_for_subagent
When the /agent tool spawns sub-agents, it invokes Runtime.copy_for_subagent (defined in src/kimi_cli/soul/agent.py, lines 39-70). This method creates a new Runtime instance that preserves the parent agent's execution context while enabling role-specific customization. The method accepts parameters for agent_id, subagent_type, and optional llm_override configurations.
Shared State vs Role-Specific Isolation
The copy_for_subagent method implements a sophisticated sharing strategy:
- Shared references: Immutable fields such as
config,oauth, andsessionare reused across parent and child agents - Mutable collection sharing: Collections like
additional_dirsare shared by reference so changes propagate across the agent hierarchy - Isolated components: Each sub-agent receives a distinct
DenwaRenjiinstance and a role-specificBackgroundTaskManager
# Inside a tool implementation (e.g., the /agent tool)
sub_runtime = agent.runtime.copy_for_subagent(
agent_id="sub-123",
subagent_type="my-subtype",
llm_override=None,
)
sub_agent = await load_agent(
agent_file=Path("agents/sub.yaml"),
runtime=sub_runtime,
mcp_configs=[],
)
Implementation Examples
Creating a Root Runtime and Loading the Main Agent
This example demonstrates the standard initialization pattern for a primary agent:
from pathlib import Path
from kimi_cli.soul.agent import Runtime, load_agent
# Initialize the service container
runtime = await Runtime.create(
config=my_config,
oauth=my_oauth,
llm=my_llm,
session=my_session,
yolo=False,
)
# Load agent with runtime injection
agent = await load_agent(
agent_file=Path("agents/default.yaml"),
runtime=runtime,
mcp_configs=[],
)
Spawning a Sub-Agent from a Running Agent
Sub-agents inherit the parent's runtime state while maintaining isolation:
# Within an agent tool execution context
sub_runtime = agent.runtime.copy_for_subagent(
agent_id="helper-001",
subagent_type="analyzer",
)
sub_agent = await load_agent(
agent_file=Path("agents/analyzer.yaml"),
runtime=sub_runtime,
mcp_configs=[],
)
Summary
- The
Runtimeclass functions as a comprehensive service container managing all execution-time dependencies including configuration, LLM access, and session state. - The
Agentclass stores aRuntimereference and consumes its services through theload_agentinitialization process andtool_depsinjection. Runtime.createbuilds fully populated runtime instances, whileload_agentbridges the runtime services with agent-specific configuration.Runtime.copy_for_subagentenables multi-agent hierarchies by deep-copying runtimes with selective state sharing and role-specific isolation.- Tools access runtime services through dependency injection, maintaining clean separation between tool logic and service management.
Frequently Asked Questions
What services does the Runtime class actually provide to Agents?
The Runtime class provides session management, OAuth authentication, LLM client access, configuration objects, notification systems, background task management, and built-in system prompt arguments. According to the kimi-cli source code, these services are aggregated in src/kimi_cli/soul/agent.py and passed to agents during the load_agent initialization phase.
How do sub-agents share state with their parent agents?
Sub-agents share state through the copy_for_subagent method, which creates a new runtime that reuses references to immutable fields like config and session while sharing mutable collections such as additional_dirs. This ensures that file system changes or configuration updates propagate across the agent hierarchy while maintaining separate execution contexts for background tasks.
Where is the Agent class defined and what does it store?
The Agent dataclass is defined in src/kimi_cli/soul/agent.py (lines 72-80). It stores the agent name, rendered system prompt, a KimiToolset instance, and the Runtime object passed during initialization. This structure allows the agent to maintain its specific configuration while delegating service access to the runtime.
How does dependency injection work for custom tools?
Custom tools receive runtime access through the tool_deps dependency map constructed during load_agent execution. The KimiToolset passes these dependencies to each tool instance, allowing tools to access self.runtime and its fields (such as config.logger or session) without direct instantiation, as implemented in src/kimi_cli/soul/agent.py.
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 →