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_type parameter
  • 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:

  1. Profile resolution: Validates subagent_type against DEFAULT_AGENT_PROFILES
  2. Instance isolation: Creates a new Agent instance with separate task and turn queues while sharing the parent's model context
  3. Lifecycle tracking: Emits events (subagent.spawned, subagent.started, subagent.completed, subagent.failed) to the transcript
  4. 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.ts by adding them to the DEFAULT_AGENT_PROFILES export map.
  • Spawn individual subagents using the Agent tool for sequential delegation, or use AgentSwarm for parallel processing across multiple inputs.
  • Subagent isolation is enforced by SessionSubagentHost in packages/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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →