Subagents Reference
This document is devkit-pi Subagents module's public overview/reference. For subagent tool parameters and return values, see subagent-tool.md; for agent file format, see agent-definition.md; for result structure, see result-schema.md.
Overview
The Subagents module lets the main agent delegate a focused task to a dedicated child pi session. It is not a full multi-agent framework; currently only supports foreground, single subagent execution, with the main agent remaining the sole orchestrator.
Suitable use cases:
- Code exploration: find files, symbols, call chains, and architecture locations
- Documentation/external research: hand off to researcher with Web/convert tools
- Implementation suggestions: generate implementation plans, not write code directly
- Review: isolate code review output and evidence collection
- Testing: generate test strategies, edge cases, and coverage suggestions
- Large output isolation: subagent's intermediate tool calls and context won't directly fill the main agent's reasoning flow
- Context compression: subagent returns focused summaries, main agent receives organized results
Differences from other capabilities:
- Regular prompt: still completed in main agent context; subagent starts an independent child session.
- Web/convert tools:
web_search/fetch_content/convert_contentare tools; researcher subagent uses them for research and document conversion. - LSP tools:
lspis a code intelligence tool; some built-in subagents can use readonly LSP actions. /toolkitcommands: user manual diagnostics/status viewing; does not replacesubagenttool.
Public surface
| Surface | Purpose | Usage | Output | Limitations | Source |
|---|---|---|---|---|---|
subagent tool | Delegate a focused task to specified agent | subagent({ agent, task }) | pi tool result, content + details | Only single agent foreground execution; no chain/parallel/background | src/modules/subagents/register.ts |
| Built-in agents | 5 preset readonly dedicated agents | explorer / researcher / reviewer / implementer / tester | agent prompt and tool allowlist | Prompt text may iterate; capabilities depend on available tools | agents/*.md |
| Custom agent definitions | user/project markdown agents | ~/.pi/agent/agents/, .pi/agents/, .agents/ | Merged into agent list by discovery | Only simple frontmatter supported; project > user > builtin dedup | src/modules/subagents/agents.ts, frontmatter.ts |
| Delegation policy injection | Hints to main agent when to delegate | Default subagents.injectDelegationPolicy=true | system prompt appended with policy/examples | Is a hint strategy, not a forced dispatcher | src/shared/delegation-policy.ts |
/toolkit agents | View discovered agents | Manual command | TUI report panel | Does not start subagents | src/modules/subagents/commands/list.ts |
/toolkit doctor | Diagnose config, agents, providers, permissions, LSP, etc. | Manual command | doctor report | report fail/warn are diagnostic items, not command failure | src/modules/subagents/commands/doctor.ts |
/toolkit logs / /toolkit activity | View toolkit activity logs/stats | Manual command | text log / TUI panel | Primarily for Web/convert tool observability, not subagent execution log | src/modules/subagents/commands/logs.ts, activity.ts |
| Output collection | Collect final result, usage, errors from child pi JSONL/stdout | Automatic internal execution | details.results[], content[0].text | Internal helper, not public tool | src/modules/subagents/collect-output.ts, execution.ts |
Built-in agents
Built-in agents come from the repository's agents/ directory. They all declare readonly: true, designed for read-only analysis/planning/research without writing files.
| Agent | Role / purpose | Expected use cases | Tools declared | Source |
|---|---|---|---|---|
explorer | Read-only codebase navigator | Find files, patterns, definitions, references, architecture locations | read, grep, find, ls, lsp | agents/explorer.md |
researcher | Read-only web researcher | External documentation/API/resource search, source synthesis, document conversion | web_search, fetch_content, get_search_content, convert_content | agents/researcher.md |
reviewer | Read-only code reviewer | Review code, diffs, plans, tests, and documentation | read, grep, find, ls, lsp | agents/reviewer.md |
implementer | Read-only implementation planner | Analyze requirements and code structure, produce implementation plans | read, grep, find, ls, lsp | agents/implementer.md |
tester | Read-only test planner | Design test strategies, scenarios, edge cases, and coverage | read, grep, find, ls, lsp | agents/tester.md |
Note: Output format, work rules, and suggestions in agent prompts are behavioral guidance and should not be understood as strong security boundaries or protocol guarantees. Actual tool availability is also affected by configuration, pi runtime, subagent process environment, and tool registration.
Routing hints from delegation policy:
explorer: locate, navigate, search code/filesresearcher: external resources/API/technology comparison/resource synthesisreviewer: code quality, risk, architecture reviewimplementer: implementation planning, solution designtester: test strategies, edge cases, coverage planning
Custom agents
Custom agents use markdown frontmatter + prompt body. Detailed format: agent-definition.md.
Discovery paths
Current discovery loads:
- Built-in: repository
agents/ - User:
~/.pi/agent/agents/ - Project: search upward from cwd for
.pi/agents/or.agents/
Deduplication priority:
project > user > builtinThat is, a project agent can override same-named user/builtin agents; user agent can override same-named builtin agents.
Supported frontmatter fields
The current parser is a simple key: value parser, not a full YAML parser. Supported fields:
| Field | Required | Behavior |
|---|---|---|
name | Yes | Agent name; if missing, the file is not loaded |
description | No | Description; defaults to empty string |
readonly | No | Only string true or 1 parses as true; otherwise false |
tools | No | Comma-separated tool name list |
model | No | Passed to child pi as --model |
Prompt body becomes systemPrompt. If body is empty, uses description; if also empty, child prompt falls back to default role text.
Fields with no special behavior currently:
packageinheritSkillsdefaultContexttagsroutingHintsdisabledpermissionstoolsYAML list syntax
Example
---
name: docs-researcher
description: Project documentation researcher
readonly: true
tools: web_search, fetch_content, get_search_content, convert_content
---
You research external documentation and return concise findings.
Focus only on the delegated task. Do not call other subagents.Recommendations:
- Use lowercase, hyphen-separated naming, e.g.,
api-reviewer. - Explicitly write "only handle delegated task".
- Explicitly write "do not call additional subagents".
- Explicitly state how to report uncertainty.
- Readonly agents should only declare readonly tools.
Delegation behavior
Current call chain:
Main agent calls subagent({ agent, task })
→ Validate depth/config/input
→ discoverAgents(cwd, "both")
→ Select agent definition
→ filterToolsForReadonly(agent, config)
→ buildChildPrompt(...)
→ buildSubagentChildArgs(...)
→ runSync() starts foreground child pi process
→ collectOutput() collects JSONL/stdout final assistant output, usage, errors
→ sanitizeOutput() sanitizes
→ truncateOutput() truncates
→ Returns content + details to main agentExecution mode:
- Foreground: parent agent waits for subagent to complete.
- Single: one tool call starts only one child agent.
- Depth guarded: default
maxDepth=1, subagent process does not registersubagenttool, prompt also requires not delegating further. - Child pi uses
--mode json, writes to independent session file. - Long tasks exceeding internal threshold write to temporary task file and pass to child pi via
@file. - System prompt writes to temporary prompt file, best-effort cleanup after execution.
Context inheritance:
- Current executor calls
buildChildPrompt()withparentMessages: [], i.e., does not actively pass parent message list. - prompt-runtime has internal logic for stripping inherited context/skills, but this is not a public-facing API.
- Subagent receives role prompt, tools list, delegated task, and boundary instructions.
Output isolation:
- Subagent intermediate JSONL events, tool calls, usage are collected as display/usage information.
- Main agent ultimately receives focused text result and
details, not the full child session context. - Session file path is recorded in result for debugging.
Readonly / write boundary
Writable custom subagents are currently an experimental capability. The default and recommended mode is readonly. subagents.allowWrite=true only indicates relaxed delegation policy; it does not imply a complete permission sandbox, audit logging, automatic rollback mechanism, or stable write-capability contract. Use only in trusted repositories, and all changes must be human-reviewed.
Current boundary based on source code:
- All 5 built-in agents declare
readonly: true, and prompts explicitly require no editing or file writing. filterToolsForReadonly()filters tools for readonly agents, retaining only readonly tool sets:read,grep,find,lsweb_search,fetch_content,get_search_content,convert_contentlsp(only whensubagents.allowLspTools=trueandallowedLspActionsis non-empty)
- For custom agents with
readonly: false:- If
subagents.allowWrite=false, still filters to readonly tools. - If
subagents.allowWrite=true, retains tools declared in agent frontmatter.
- If
Important notes:
subagents.allowWrite=truedoes not mean built-in agents will automatically write files; built-in agents remain readonly definitions and do not declareedit/write.allowWrite=trueonly affects tool filtering for non-readonly custom agents.- Subagent's actual tool availability depends on child pi runtime, current tool registration, execution environment, and configuration; do not assume all tools will automatically be inherited by subagents in the future.
- Main agent process registers
subagentand/toolkit; subagent process does not registersubagentor/toolkit. - LSP privileged actions are always disabled in subagents.
- Web and convert tools can be used for research, reading information, and converting supported documents to Markdown.
- File writing, command execution, project modification, and other write-like behaviors should not be understood as default-safe capabilities.
- Prompt/policy is behavioral guidance; real strong constraints mainly come from tool filtering, subagent not registering
subagent, LSP privileged actions always disabled in subagents, etc.
There is currently no stable automatic rollback guarantee. If users enable writable behavior, they should use Git workspaces, pre-commit diffs, human review, and test commands as safety nets.
To formally support writable custom subagents in the future, at least the following should be supplemented:
- When
allowWrite=false, write-like / privileged capabilities are blocked or not exposed. - When
allowWrite=true, allowed scope matches expectations. - LSP privileged actions remain disabled in subagents.
- Subagents do not register
subagent, preventing recursive delegation. - Subagents do not register
/toolkit. - Custom agent
readonlyfrontmatter and global config priority are clear. - Execution results record sufficient information for auditing.
- Failures do not masquerade as success.
Result schema and output collection
Detailed structure: result-schema.md. Current subagent tool returns pi tool result:
{
content: Array<{ type: "text"; text: string }>;
details: {
mode: "single" | "management";
runId?: string;
results: Array<{
agent: string;
task: string;
exitCode: number;
usage: Usage;
error?: string;
sessionFile?: string;
output?: string;
displayItems?: Array<{ type: "text"; text: string } | { type: "toolCall"; name: string; args: Record<string, unknown> }>;
}>;
error?: {
code: SubagentErrorCode;
message: string;
};
streaming?: StreamingDisplay;
};
}Semantics:
- Successful execution:
exitCode === 0,details.results[0].outputholds sanitized full output,content[0].textmay be truncated version. - Execution failure:
exitCode !== 0,details.error.codeis usuallySUBAGENT_FAILEDorSUBAGENT_TIMEOUT. - Output truncation: execution may succeed, but
details.error.codemay beSUBAGENT_OUTPUT_TRUNCATED. - Streaming: during execution,
details.streamingmay be returned viaonUpdate; final results typically do not retain streaming fields. collectOutput()extracts final assistant text, usage, provider/runtime error, and partial output from child pi JSONL.sanitizeOutput()masks common tokens, secrets, user paths, and overly long stack traces.
Logs/activity:
/toolkit logsand/toolkit activitycurrently display toolkit activity logs/stats for Web and convert tools, not subagent execution history.- Subagent session file is a debugging clue, but not a stable external API.
Machine parsing:
detailstop-level shape can be used for programmatic judgment, but human-readablecontent[0].text, agent prompt output format, and display rendering may change.- External scripts should not depend on complete natural language output format.
Relationship with Web / LSP / toolkit
Web / convert tools
- Web and convert tools can be registered in both main agent and subagent processes.
- Built-in
researcherdeclaresweb_search,fetch_content,get_search_content,convert_content. - Custom agents can also declare these tools in
tools. - Web tools details:
web-tools.md. Convert tool details:convert-tools.md.
LSP tools
- Built-in
explorer,reviewer,implementer,testerdeclarelsp. - Whether subagents can use
lspis affected bysubagents.allowLspToolsandsubagents.allowedLspActions. - Subagents only allow readonly-safe LSP actions;
rename,codeAction,restartare always disabled in subagent processes. - LSP details:
lsp-tools.md.
/toolkit commands
/toolkit agents: view discovered agents./toolkit doctor: diagnose agents, providers, permissions, Web/LSP status./toolkit logs//toolkit activity: view toolkit activity logs/stats./toolkitis only registered in main agent process, not in subagent processes.- Commands details:
toolkit-commands.md.
Configuration
Complete configuration: configuration.md#subagents-configuration.
Default configuration summary:
{
"subagents": {
"enabled": true,
"maxDepth": 1,
"timeoutMs": 900000,
"idleTimeoutMs": 180000,
"allowWrite": false,
"allowLspTools": true,
"allowedLspActions": [
"definition", "references", "hover", "signature",
"symbols", "diagnostics", "workspace-diagnostics", "servers"
],
"injectDelegationPolicy": true,
"retry": {
"enabled": true,
"maxAttempts": 2
}
}
}Configuration effects:
subagents.enabled=false:registerSubagentsModule()does not registersubagenttool.subagents.maxDepth=1: default prohibits nested subagents.subagents.timeoutMs: single child execution hard cap. It starts when the child process is spawned and does not reset on activity.subagents.idleTimeoutMs: maximum idle time since the last valid structured child activity event, such asmessage_end,tool_result_end, orturn_end. Plain stdout text does not reset this timer. Default: 180000ms.subagents.allowWrite: experimental/advanced/unsafe switch; only affects tool filtering for non-readonly custom agents, does not change built-in agents' readonly definition, does not provide complete permission sandbox, audit log, automatic rollback, or stable write-capability contract.subagents.allowLspTools/allowedLspActions: controls whether subagents can use readonly LSP actions.subagents.injectDelegationPolicy: controls whether to inject delegation policy into main agent prompt.subagents.retry.*: limited retry for subagent transient failures.
Custom agents discovery paths are currently not configurable, fixed to user/project directory lookup.
Error and failure semantics
Current subagent error code canonical source is SUBAGENT_ERROR_CODES in src/shared/types.ts.
| Code | Current semantics |
|---|---|
INVALID_INPUT | Missing agent or task |
SUBAGENTS_DISABLED | Subagent feature disabled by configuration |
UNKNOWN_AGENT | Cannot find specified agent; returns available agent names |
SUBAGENT_DISABLED | Defined but currently has no direct return path; reserved for future per-agent disable semantics |
SUBAGENT_DEPTH_EXCEEDED | Depth exceeded; subagents cannot continue calling subagents |
SUBAGENT_TIMEOUT | Child execution timed out; may be caused by the hard cap (timeoutMs) or idle timeout (idleTimeoutMs). Use timeoutReason in details to distinguish them when present |
SUBAGENT_FAILED | spawn, session directory, child process, or provider/runtime failure, uncategorized failures |
SUBAGENT_OUTPUT_TRUNCATED | Output too long, truncated; also used when child stdout/stderr/JSONL output exceeds execution hard limits and the child is stopped |
Failure behavior:
- Invalid input / disabled / unknown agent / depth exceeded usually returns as
content[0].text+details.error, not necessarily throwing exception. - Spawn failure is wrapped as
SUBAGENT_FAILED. - Child process non-0 exit forms failure summary including exit code, error, partial output, and session file.
- Agent definition parse failure or files missing
nameare silently skipped;/toolkit doctormay report user agents skipped.
Stability notes
Public contract:
- Tool name:
subagent - Input fields:
agent,task - Built-in agent names:
explorer,researcher,reviewer,implementer,tester - Custom agent discovery paths and simple frontmatter supported fields
- Default foreground single execution
- Subagent process does not register
subagenttool or/toolkit - Subagent LSP privileged actions always disabled
details.mode,details.results[],details.errorbasic structureSUBAGENT_ERROR_CODESstring values
Internal implementation / may change:
- Built-in agent prompt text and output templates
- Delegation policy text and examples
- Child prompt specific concatenation method
- Session file directory layout
- Streaming display item format details
- Retry transient error pattern
- Sanitize/truncate specific rules
- Renderer UI display format
External scripts should not strongly depend on natural language output, box/TUI rendering, or session file layout; if a stable machine interface is needed, prefer reading structured fields from details.
Source map
| Topic | Source |
|---|---|
| Tool registration / renderer / session hooks | src/modules/subagents/register.ts |
| Agent discovery | src/modules/subagents/agents.ts |
| Foreground execution | src/modules/subagents/execution.ts |
| Executor / tool filtering / retry / result assembly | src/modules/subagents/executor.ts |
| Output collection | src/modules/subagents/collect-output.ts |
| Agent frontmatter parser | src/modules/subagents/frontmatter.ts |
| Pi args / temp prompt/task files | src/modules/subagents/pi-args.ts |
| Pi spawn command resolution | src/modules/subagents/pi-spawn.ts |
| Runtime prompt helpers | src/modules/subagents/prompt-runtime.ts |
| Output sanitization | src/modules/subagents/sanitize.ts |
| Schemas | src/modules/subagents/schemas.ts |
| Subagent-related toolkit commands | src/modules/subagents/commands/ |
| Delegation policy | src/shared/delegation-policy.ts |
| Session identity | src/shared/session-identity.ts |
| Shared result/error/config types | src/shared/types.ts |
| Built-in agent definitions | agents/*.md |
| Tests | tests/subagents/, tests/subagents/commands/ |