How to Build Custom Subagents (Coder, Explore, Plan) in Kimi Code
Building custom subagents in Kimi Code requires creating a YAML profile in packages/agent-core/src/profile/default/, registering it in default.ts, and spawning it via the Agent tool or AgentSwarm for parallel execution.
Kimi Code, the open-source agentic framework from MoonshotAI, enables parent agents to delegate tasks to specialized subagents through a declarative profile system. Whether you need a read-only explorer, a file-editing coder, or a planning reviewer, custom subagents extend core capabilities while maintaining strict isolation and observability. This guide walks through the exact implementation steps found in the MoonshotAI/kimi-code repository.
Step 1: Declare a Subagent Profile
Every subagent starts as a YAML profile stored in packages/agent-core/src/profile/default/. Each profile extends the base agent configuration and defines the subagent's identity, capabilities, and strict tool constraints.
A profile contains five critical fields:
- extends: Inherits from the base agent template (typically
agent) - name: The unique identifier used as the
subagent_typeparameter - promptVars.roleAdditional: System instructions that constrain behavior (e.g., read-only enforcement)
- whenToUse: Human-readable description for UI context
- tools: An explicit allowlist of callable tools that enforces security boundaries
Here is the built-in explore profile that demonstrates read-only constraints:
# packages/agent-core/src/profile/default/explore.yaml
extends: agent
name: explore
promptVars:
roleAdditional: |
You are now running as a subagent. You are a read-only agent.
Do not modify files; only search and read code.
whenToUse: |
Fast agent specialized for exploring codebases.
Use "quick", "medium", or "thorough" to control search depth.
tools:
- Bash
- Read
- ReadMediaFile
- Glob
- Grep
- WebSearch
- FetchURL
The coder profile (which permits editing) and plan profile (review-only) follow identical structures but include tools like Write or Replace where appropriate. You can find these at packages/agent-core/src/profile/default/coder.yaml and packages/agent-core/src/profile/default/plan.yaml.
Step 2: Register the Profile in DEFAULT_AGENT_PROFILES
After creating the YAML file, expose it to the runtime through the central registry in packages/agent-core/src/profile/default.ts. This file exports the DEFAULT_AGENT_PROFILES map that resolves subagent_type strings to configuration objects.
The TypeScript file imports each YAML as a raw string and parses it into the registry:
// packages/agent-core/src/profile/default.ts
import exploreYaml from './default/explore.yaml?raw';
import coderYaml from './default/coder.yaml?raw';
import planYaml from './default/plan.yaml?raw';
export const DEFAULT_AGENT_PROFILES = {
agent: parseYaml(agentYaml),
coder: parseYaml(coderYaml),
explore: parseYaml(exploreYaml),
plan: parseYaml(planYaml),
};
The build pipeline automatically generates these imports, or you can manually add entries for custom profiles. Once registered, the engine can resolve any string passed to subagent_type against this map.
Step 3: Spawn Subagents from a Parent Agent
With the profile registered, parent agents instantiate subagents using the Agent tool implemented in packages/agent-core/src/tools/builtin/collaboration/agent.ts. This tool accepts a subagent_type argument that must match a key in DEFAULT_AGENT_PROFILES.
The tool delegates to SessionSubagentHost to create isolated agent instances:
// packages/agent-core/src/tools/builtin/collaboration/agent.ts
const profileName = args.subagent_type?.length ? args.subagent_type : 'coder';
const handle = await this.subagentHost.spawn({
subagent_type: profileName,
prompt: args.prompt,
// Optional: timeout, resume flags, etc.
});
Example: Launching an explore subagent from a parent coder agent
import { Agent } from '@moonshot-ai/kimi-code-sdk';
const result = await Agent({
subagent_type: 'explore',
prompt: `
thoroughness: medium
Search the repository for any function named "handleRequest"
and list the files where it appears.
`,
});
console.log('Explore subagent finished:', result.output);
Parallel Execution with AgentSwarm
For batch operations across multiple inputs, use AgentSwarm from packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts. This fans out multiple subagents in parallel across an items array:
import { AgentSwarm } from '@moonshot-ai/kimi-code-sdk';
const swarmResult = await AgentSwarm({
subagent_type: 'explore',
items: ['src/**/*.ts', 'tests/**/*.ts'],
prompt_template: `
thoroughness: quick
Read {{item}} and extract all exported class names.
`,
});
console.log('Swarm results:', swarmResult.output);
The parent agent receives consolidated results once all subagents complete, with lifecycle events (subagent.spawned, subagent.completed) recorded in the transcript for full observability.
Subagent Architecture and Lifecycle
Understanding the execution model helps debug custom subagents. The orchestration happens in packages/agent-core/src/session/subagent-host.ts through SessionSubagentHost, which manages four critical responsibilities:
- Profile resolution: Validates
subagent_typeagainstDEFAULT_AGENT_PROFILES - Instance isolation: Creates a new
Agentinstance with separate task and turn queues while sharing the parent's model context - Lifecycle tracking: Emits events (
subagent.spawned,subagent.started,subagent.completed,subagent.failed) to the transcript - Result bubbling: Marks subagent turns with
PromptOrigin={ kind: 'system_trigger', name: 'subagent' }and appends summaries to the parent's context
This architecture ensures that even if a subagent fails or times out, the parent agent receives structured feedback without state corruption.
Complete Custom Subagent Example
Here is a complete implementation pattern for a documentation generation subagent:
Step A: Create the profile (packages/agent-core/src/profile/default/docgen.yaml):
extends: agent
name: docgen
promptVars:
roleAdditional: |
You are a documentation specialist. Generate JSDoc comments
for functions but do not modify implementation logic.
whenToUse: |
Use when you need to generate API documentation for TypeScript files.
tools:
- Read
- Write
- Glob
Step B: Register in default.ts (add to imports and DEFAULT_AGENT_PROFILES):
import docgenYaml from './default/docgen.yaml?raw';
export const DEFAULT_AGENT_PROFILES = {
// ... existing profiles
docgen: parseYaml(docgenYaml),
};
Step C: Spawn from parent:
const docs = await Agent({
subagent_type: 'docgen',
prompt: 'Generate JSDoc for all functions in src/utils/',
});
Summary
- Create YAML profiles in
packages/agent-core/src/profile/default/to define subagent capabilities, system prompts, and strict tool constraints. - Register new profiles in
packages/agent-core/src/profile/default.tsby adding them to theDEFAULT_AGENT_PROFILESexport map. - Spawn individual subagents using the
Agenttool for sequential delegation, or useAgentSwarmfor parallel processing across multiple inputs. - Subagent isolation is enforced by
SessionSubagentHostinpackages/agent-core/src/session/subagent-host.ts, which manages separate task queues and lifecycle events while bubbling results back to the parent transcript.
Frequently Asked Questions
What is the difference between the coder, explore, and plan subagent types?
The coder profile includes editing tools like Write and Replace for file modification, explore restricts operations to read-only search and discovery via Read, Glob, and Grep, while plan enables architectural review and planning without mutations. Each profile configures distinct tool sets in their respective YAML files under packages/agent-core/src/profile/default/.
How do I restrict a subagent to read-only operations?
Limit the tools array in the profile YAML to non-mutating tools like Read, Glob, Grep, and FetchURL. Additionally, set promptVars.roleAdditional to explicitly instruct the LLM that it cannot modify files, and document these constraints in the whenToUse field for UI clarity.
Can I run multiple subagents simultaneously?
Yes. Use the AgentSwarm tool from packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts to fan out multiple subagents across a collection of items. The parent agent receives consolidated results once all parallel subagents complete, with each subagent operating in isolation.
Where are subagent profiles stored in the Kimi Code repository?
Built-in profiles reside in packages/agent-core/src/profile/default/ as YAML files (e.g., coder.yaml, explore.yaml, plan.yaml). The registration logic lives in packages/agent-core/src/profile/default.ts, which generates the DEFAULT_AGENT_PROFILES map used by the Agent tool to resolve subagent_type strings.
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 →