Forensic investigation of MoonshotAI's kimi-code: prompt lineage, agentic loops, subagent swarms, tool parallelism, compaction engine
The monorepo structure and 16 packages composing the complete coding agent system.
graph TB
TUI["pi-tui - Terminal UI"] --> K["klient"]
ACP["acp-adapter"] --> K
K --> AG["agent-core - Main Engine"]
K --> AG2["agent-core-v2 - Next Gen"]
AG --> KA["kaos - Process Mgmt"]
AG --> KO["kosong - Provider API"]
AG2 --> KA
AG2 --> KO
| Package | Share | Description |
|---|---|---|
| agent-core | ~35% | Main engine: loop, tools, prompts, compaction, subagents |
| agent-core-v2 | ~25% | Next-gen engine with DI container, wire protocol |
| klient | ~10% | Multi-transport client (WS, HTTP, IPC, memory) |
| kaos | ~8% | Process management — local + SSH execution |
| pi-tui | ~7% | Custom terminal UI framework |
| kap-server | ~5% | Agent Protocol Server for editor integration |
| kosong | ~4% | LLM provider abstraction (OpenAI/Anthropic) |
| others | ~6% | protocol, minidb, oauth, acp-adapter, telemetry, migration-legacy |
Complete path from template files through profile resolution to the final system prompt sent to the LLM.
graph LR
A["system.md - Jinja2 Template"] -->|"?raw import"| B["profile/default.ts - PROFILE_SOURCES"]
B -->|"loadAgentProfilesFromSources()"| C["resolveAgentProfiles() - resolve.ts"]
C -->|"extends chain merge"| D["MergedAgentProfile - Template + promptVars"]
D -->|"createSystemPromptRenderer()"| E["SystemPromptRenderer - Closure"]
E -->|"Agent.useProfile()"| F["buildTemplateVars() - Runtime context"]
F -->|"renderPrompt()"| G["Final System Prompt - Sent to provider"]
| Variable | Source | Example |
|---|---|---|
| {{ KIMI_OS }} | kaos.osEnv.osKind | Linux / macOS / Windows |
| {{ KIMI_SHELL }} | kaos.osEnv.shellName | Bash (/bin/bash) |
| {{ KIMI_NOW }} | context.now | ISO 8601 timestamp |
| {{ KIMI_WORK_DIR }} | config.cwd | /home/user/project |
| {{ KIMI_WORK_DIR_LS }} | context.cwdListing | Directory tree view |
| {{ KIMI_AGENTS_MD }} | context.agentsMd | AGENTS.md project instructions |
| {{ KIMI_SKILLS }} | skills registry | Available skill listing |
| {{ ROLE_ADDITIONAL }} | promptVars + context.roleAdditional | Subagent-specific role |
graph TD
AGENT["agent - Base Profile - system.md - Full tool set"]
CODER["coder - extends agent - + subagent ROLE_ADDITIONAL - + Agent/AgentSwarm"]
EXPLORE["explore - extends agent - + read-only enforcement - no Bash write"]
PLAN["plan - extends agent - + planning-only - no Bash, no writes"]
AGENT -->|"extends:"| CODER
AGENT -->|"extends:"| EXPLORE
AGENT -->|"extends:"| PLAN
Two-level architecture governing turn execution and step-by-step provider interaction.
flowchart TD
START(["runTurn(turnId, signal, llm, tools)"]) --> CHECK{"signal aborted? maxSteps exceeded?"}
CHECK -->|"continue"| STEP["executeLoopStep() - turn-step.ts"]
CHECK -->|"abort/max"| END(["return TurnResult"])
STEP --> LLM["LLM.chat() - Provider API Call"]
LLM --> TOOLS{"stopReason?"}
TOOLS -->|"tool_use"| CONT(["continue loop"])
TOOLS -->|"end_turn / max_tokens / refusal"| HOOKS["shouldContinueAfterStop?"]
CONT --> CHECK
HOOKS -->|"true"| CHECK
HOOKS -->|"false"| END
loop/turn-step.ts — One provider step: hooks, message build, LLM call, tool-call handoff
loop/tool-call.ts — Tool-call batch lifecycle: classification, preparation, scheduling, results
loop/README.md — Architecture contracts: ownership, event dispatch, test boundaries
Sophisticated read/write conflict model enabling safe parallel execution while preventing race conditions.
flowchart LR
subgraph Sched["ToolScheduler"]
A["add(task with accesses)"] --> B{"conflictsWithAny(active + queued)?"}
B -->|"No conflict"| C["start() → activeTasks"]
B -->|"Conflict"| D["queuedTasks.push()"]
C --> E["task.start()"]
E --> F["await result"]
F --> G["finish() → remove from active"]
G --> H["startQueuedTasks() → re-evaluate"]
H --> B
end
Bash (no conflict), Read, Glob, Grep, WebFetch, WebSearch, AskUserQuestion, AskUserChoice, Agent, AgentSwarm
Edit (same file), Write (same file), Bash starting background process, any manual_edit
Two-tier subagent system: single Agent tool for focused delegation, AgentSwarm for massive parallel batch operations.
flowchart TB
MAIN["Main Agent - Full tool set"]
AGENT["Agent Tool - Single subagent"]
SWARM["AgentSwarm Tool - Parallel batch"]
HOST["SessionSubagentHost - Lifecycle Manager"]
CODER["coder - Full dev: read + write + bash"]
EXPLORE["explore - Read-only: search + grep + read"]
PLAN["plan - Planning-only: read + web"]
MAIN --> AGENT
MAIN --> SWARM
AGENT --> HOST
SWARM --> HOST
HOST --> CODER
HOST --> EXPLORE
HOST --> PLAN
session/subagent-batch.ts — SubagentBatch scheduler: dual-phase operation, capacity management (~680 loc)
session/subagent-host.ts — SessionSubagentHost: spawn, resume, retry, background draining (~599 loc)
Multi-level context window management system that decides when and how to compress the conversation history.
flowchart TD
TRIGGER{"shouldCompact? tokenCount > threshold"} -->|"yes"| BEGIN["FullCompaction.begin()"]
BEGIN --> WORKER["compactionWorker()"]
WORKER --> ROUND["compactionRound() - retry loop"]
ROUND --> SUMMON["LLM Summarizer - system prompt + history + instruction"]
SUMMON -->|"overflow / 413"| OVERFLOW["shrink history - drop dynamic-tool context - media-strip if needed"]
OVERFLOW --> SUMMON
SUMMON -->|"success"| REBUILD["Post-compaction: - refreshSystemPrompt() - re-inject tool manifests - re-append goals/todo"]
REBUILD --> FINISH["markCompleted() - emit compaction.completed"]
The renderPrompt() function returns a closure over the template + variables. This means the prompt is re-evaluated on every render call, allowing dynamic variables (current time, working directory state, agent status) to be injected fresh each turn without template recompilation.
| Metric | Value |
|---|---|
| Default threshold | ~120,000 tokens |
| Compaction time (avg) | 2-5 seconds |
| History retention | Configurable summarization depth |
| Media handling | Stripped on 413 overflow |
Dynamic template rendering via closures — template + variables captured into a render function. Re-evaluated each turn for fresh context injection.
Fine-grained read/write conflict detection enables safe parallel execution. Same-file edits serialize; read-only tools run in parallel.
Up to 128 parallel subagents with dual-phase scheduling, exponential backoff on rate limits, and automatic capacity recovery.
Progressive context compression: summary → drop dynamic → media-strip. LLM-driven summarization preserves critical information.
YAML-based profile system with extends chain — agent → coder/explore/plan. Each profile gets tailored tool sets and ROLE_ADDITIONAL.
klient supports WS, HTTP, IPC, and in-memory transports. Agent Protocol Server (kap-server) enables editor integration.