The shipped subagent example could say a child was done while it was still working, lose the useful part of process failures, and return a normal-looking tool result when the delegated work had actually failed. Single and chain output could also exceed the normal tool limit. This also adds a dedicated regression suite covering progress state, cancellation, process failures, output limits, cwd-based agent selection, and persisted tool-result error state. After this change: - queued, running, completed, failed, and aborted work stay distinct throughout the run; - interrupting the parent run preserves partial child results, stops queued work from starting, and escalates when a child ignores SIGTERM; - signal exits, spawn failures, provider errors, stderr, and assistant output remain visible instead of collapsing to `(no output)`; - failed subagents become failed tool results, so the parent model can react instead of treating them as successful calls; - single and chain results stay within the normal 50 KB / 2,000-line limit; - project agents are selected and confirmed from each task's actual working directory rather than the dispatcher's directory. ## Further potential improvements These are useful follow-ups, but they are separate product and storage decisions rather than part of the failure-handling fixes in this PR. <details> <summary>Potential follow-ups</summary> ### Keep persisted transcripts bounded Subagent tool results persist the full child message history in `details`, which can make parent session files large and slow to reload. A follow-up could compact that history or spill it to disk. ### Define an aggregate parallel-output budget Parallel mode still gives every task its own 50 KB budget. A follow-up could keep every task represented while enforcing one overall tool-result limit. ### Report child usage to the calling session Per-child token and cost usage is visible in result cards but is not added to the calling session's totals. ### Isolate malformed agent definitions One malformed YAML agent can still break discovery for every valid agent in the same directory. ### Limit subagent recursion A nesting limit would prevent accidental process and paid-request multiplication when subagents can invoke the subagent tool again. * https://github.com/earendil-works/pi/issues/8195 ### Add a configurable timeout Unattended runs would benefit from a generous opt-in timeout for children that never complete. </details> ## Related issues ### Spawn failures lose their diagnostics This directly addresses the reported case where a nonexistent child working directory produces `(no output)` instead of the actual spawn error. The regression suite includes that same reproduction. * https://github.com/earendil-works/pi/issues/8129 ### Persisted child history can bloat sessions This PR intentionally keeps full child history in tool-result details, so session compaction or spill-to-disk remains follow-up work rather than something fixed here. * https://github.com/earendil-works/pi/issues/7452
6.7 KiB
Subagent Example
Delegate tasks to specialized subagents with isolated context windows.
Features
- Isolated context: Each subagent runs in a separate
piprocess - Streaming output: See tool calls and progress as they happen
- Parallel streaming: All parallel tasks stream updates simultaneously
- Markdown rendering: Final output rendered with proper formatting (expanded view)
- Usage display: Shows turns, tokens, cost, and context usage inside each subagent result
- Abort support: Ctrl+C propagates to kill subagent processes
Structure
subagent/
├── README.md # This file
├── index.ts # The extension (entry point)
├── agents.ts # Agent discovery logic
├── agents/ # Sample agent definitions
│ ├── scout.md # Fast recon, returns compressed context
│ ├── planner.md # Creates implementation plans
│ ├── reviewer.md # Code review
│ └── worker.md # General-purpose (full capabilities)
└── prompts/ # Workflow presets (prompt templates)
├── implement.md # scout -> planner -> worker
├── scout-and-plan.md # scout -> planner (no implementation)
└── implement-and-review.md # worker -> reviewer -> worker
Installation
From the repository root, symlink the files:
# Symlink the extension (must be in a subdirectory with index.ts)
mkdir -p ~/.pi/agent/extensions/subagent
ln -sf "$(pwd)/packages/coding-agent/examples/extensions/subagent/index.ts" ~/.pi/agent/extensions/subagent/index.ts
ln -sf "$(pwd)/packages/coding-agent/examples/extensions/subagent/agents.ts" ~/.pi/agent/extensions/subagent/agents.ts
# Symlink agents
mkdir -p ~/.pi/agent/agents
for f in packages/coding-agent/examples/extensions/subagent/agents/*.md; do
ln -sf "$(pwd)/$f" ~/.pi/agent/agents/$(basename "$f")
done
# Symlink workflow prompts
mkdir -p ~/.pi/agent/prompts
for f in packages/coding-agent/examples/extensions/subagent/prompts/*.md; do
ln -sf "$(pwd)/$f" ~/.pi/agent/prompts/$(basename "$f")
done
Security Model
This tool executes a separate pi subprocess with a delegated system prompt and tool/model configuration.
Project-local agents (.pi/agents/*.md) are repo-controlled prompts that can instruct the model to read files, run bash commands, etc.
Default behavior: Only loads user-level agents from ~/.pi/agent/agents.
To enable project-local agents, pass agentScope: "both" (or "project"). Only do this for repositories you trust.
When running interactively, the tool prompts for confirmation before running project-local agents unless the session trust context reports trusted and the agents come from that session project's .pi/agents directory. Agents loaded from another task cwd still require confirmation. Set confirmProjectAgents: false to disable confirmation.
Usage
Single agent
Use scout to find all authentication code
Parallel execution
Run 2 scouts in parallel: one to find models, one to find providers
Chained workflow
Use a chain: first have scout find the read tool, then have planner suggest improvements
Workflow prompts
/implement add Redis caching to the session store
/scout-and-plan refactor auth to support OAuth
/implement-and-review add input validation to API endpoints
Tool Modes
| Mode | Parameter | Description |
|---|---|---|
| Single | { agent, task } |
One agent, one task |
| Parallel | { tasks: [...] } |
Multiple agents run concurrently (max 8, 4 concurrent) |
| Chain | { chain: [...] } |
Sequential with {previous} placeholder |
Output Display
Collapsed view (default):
- Status icon (✓/✗/⏳) and agent name
- Last 5-10 items (tool calls and text)
- Usage stats:
3 turns ↑input ↓output RcacheRead WcacheWrite $cost ctx:contextTokens model
Expanded view (Ctrl+O):
- Full task text
- All tool calls with formatted arguments
- Final output rendered as Markdown
- Per-task usage (for chain/parallel)
Parallel mode streaming:
- Shows all tasks with live status (⏳ running, ✓ done, ✗ failed)
- Updates as each task makes progress
- Distinguishes pending, running, completed, failed, and aborted tasks
- Returns each completed task summary to the parent model with its own 50 KB limit
- Returns failure diagnostics from stderr/error messages when a child exits before producing output
Tool call formatting (mimics built-in tools):
$ commandfor bashread ~/path:1-10for readgrep /pattern/ in ~/pathfor grep- etc.
Agent Definitions
Agents are markdown files with YAML frontmatter:
---
name: my-agent
description: What this agent does
tools: read, grep, find, ls
model: claude-haiku-4-5
---
System prompt for the agent goes here.
When model is omitted, the subagent inherits the dispatching session's active model and thinking level.
Locations:
~/.pi/agent/agents/*.md- User-level (withagentScope: "user"or"both").pi/agents/*.md- Project-level (only withagentScope: "project"or"both")
Project agents override user agents with the same name when agentScope: "both".
Sample Agents
| Agent | Purpose | Model | Tools |
|---|---|---|---|
scout |
Fast codebase recon | Haiku | read, grep, find, ls, bash |
planner |
Implementation plans | Sonnet | read, grep, find, ls |
reviewer |
Code review | Sonnet | read, grep, find, ls, bash |
worker |
General-purpose | Sonnet | (all default) |
Workflow Prompts
| Prompt | Flow |
|---|---|
/implement <query> |
scout → planner → worker |
/scout-and-plan <query> |
scout → planner |
/implement-and-review <query> |
worker → reviewer → worker |
Error Handling
- Exit code != 0 or signal termination: Tool returns an error with preserved stderr/output
- Spawn errors: Tool returns the spawn diagnostic
- stopReason "error": LLM error is propagated with its error message
- Abort: Ctrl+C sends SIGTERM, escalates to SIGKILL after five seconds if needed, and preserves partial details/usage
- Chain mode: Stops at the first failing step and reports which step failed
Limitations
- Output truncated to last 10 items in collapsed view (expand to see all)
- Single and chain output is capped at 50 KB/2,000 lines; full results remain in tool details
- Parallel output keeps a separate 50 KB budget per task, allowing up to roughly 400 KB across eight tasks
- Child usage is displayed in tool details but is not added to the calling session's usage totals
- Agents are snapshotted from each task's effective cwd when the tool invocation starts; relative task cwd values resolve from the session cwd
- Parallel mode limited to 8 tasks, 4 concurrent