Delegate prompts to specialized Pi subagents, optionally continuing named subagent sessions.
There are many subagent extensions for Pi; this one is mine.
Specialization — Use tailored agents for review, research, testing, documentation, exploration, and other focused work.
Flexible Context — Let specialists start fresh, or give them the current conversation when that helps.
Named Continuation — Continue the same specialist conversation later for multi-step work.
Parallel Execution — Let the main agent ask multiple specialists at the same time.
Small Surface Area — Install the extension, define agents as Markdown, and let the main Pi agent handle delegation.
- Auto-Discovery — Agents are found at startup and listed in the main agent's system prompt.
- Unified Delegation — One extension handles one specialist call or many parallel calls.
- Named Persistent Sessions — Continue specialist subagents across multiple turns when useful.
- Agent Session Guidance — Agent definitions can advise when persistent or ephemeral calls fit best.
- Context Control — Subagents start fresh by default; explicit parent snapshot cloning remains available for exceptional cases.
- Inactivity Watchdog — Stop silent child runs while allowing active RPC streams to continue.
- Depth + Cycle Guards — Prevent runaway recursive delegation.
- Streaming Updates — Watch progress in real time.
- Rich TUI Rendering — Collapsed/expanded views with usage stats, tool calls, markdown output, and session metadata.
Requires Pi 0.80.5 or newer.
pi install npm:@mjakl/pi-subagentpi install git:github.com/mjakl/pi-subagentClone this repository to your Pi extensions directory:
cd ~/.pi/agent/extensions
git clone https://github.com/mjakl/pi-subagent.git
cd pi-subagent
npm installOnce installed, use Pi normally. Ask the main agent for work that benefits from a specialist, such as "review this diff" or "find where authentication is implemented." The main agent decides when to delegate, runs the subagent, and folds the result back into your conversation.
You do not need to call subagent, write JSON, or interact with tools directly.
What to expect:
- Delegated work appears in the TUI with streaming progress and expandable details.
- Each subagent runs in its own isolated
piprocess. - If you have no agents yet,
pi-subagentcreates a starterexploreagent automatically. - Customize agents only when you want different or additional specialists.
pi-subagent works out of the box — on first run it creates a starter explore agent for you. Customize it only if you want different or additional specialists.
Subagents are defined as Markdown files with YAML frontmatter.
User agents: ~/.pi/agent/agents/*.md by default, or $PI_CODING_AGENT_DIR/agents/*.md when PI_CODING_AGENT_DIR is set.
Project agents: .pi/agents/*.md.
Project agents win on name conflicts, but only after explicit project trust recorded in Pi's trust store or supplied with --approve. Implicit or session-only trust does not enable them. They are repo-controlled configuration and execute like user agents.
If no user or project subagents can be found, pi-subagent creates a starter user agent named explore in the active user agents directory:
~/.pi/agent/agents/explore.mdby default$PI_CODING_AGENT_DIR/agents/explore.mdwhenPI_CODING_AGENT_DIRis set
The starter is read-only (read, grep, find, ls) and is meant for focused codebase exploration. It includes an advisory preference for topic-specific persistent sessions so follow-up exploration can reuse context. Existing files are never overwritten.
Small, focused definitions work best. The description helps the main agent choose a subagent; the Markdown body is the subagent's extra system prompt.
The repository and npm package include agents/oracle.md as a full-featured reference definition. It demonstrates:
- a provider-prefixed default
modeland elevatedthinkinglevel; - an explicit tool allowlist;
- a 10-minute inactivity watchdog default;
- advisory
sessionPreferenceandsessionHintguidance for choosing between independent and continued discussions.
The package does not install or activate this agent automatically. Agent definitions can select models and tools, so copy examples into your user or project agents directory only after reviewing them. Adjust or remove the example's model if it is not available in your Pi configuration.
From a repository checkout, install the example as a user agent with:
agents_dir="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}/agents"
mkdir -p "$agents_dir"
cp agents/oracle.md "$agents_dir/oracle.md"A good default for fast codebase reconnaissance. It prefers named sessions because exploration often has follow-up questions.
---
name: explore
description: Codebase exploration specialist for focused searches and evidence-backed summaries.
tools: read,grep,find,ls
sessionPreference: persistent
sessionHint: Prefer a topic-specific named session for iterative codebase exploration, e.g. session="explore-auth". Use ephemeral calls for one-off or parallel independent searches.
---
You are a codebase exploration specialist. Find the relevant files, symbols, and tests for the request. Return concise findings with file paths and line references.A useful complement to explore: stateless by default, judgment-oriented, and configured for deeper reasoning.
---
name: review
description: Pragmatic code reviewer for correctness, regression risk, test coverage, and maintainability.
thinking: high
sessionPreference: ephemeral
sessionHint: Use ephemeral calls for independent reviews; use a named session only when continuing the same review thread.
---
You review code changes. Focus on substantive issues, cite files and lines, and distinguish confirmed problems from suggestions. Keep the report concise.| Field | Required | Default | Description |
|---|---|---|---|
name |
Yes | — | Agent identifier used in tool calls. |
description |
Yes | — | What the agent does; shown to the main agent. |
model |
No | Parent's current Pi model | Sets the default model for this agent. A per-call model overrides it. Supports provider-prefixed values such as anthropic/claude-3-5-sonnet. |
thinking |
No | Parent/default Pi thinking level | Sets the thinking level (off, minimal, low, medium, high, xhigh). |
inactivityTimeout |
No | No inactivity timeout | Positive integer seconds, up to 2,147,483, that a child may produce no RPC stdout activity before its process tree is terminated. A per-call value overrides this default. |
tools |
No | Parent/default Pi tools | Comma-separated allowlist of tool names to enable for this agent. Omitted or empty values inherit the parent configuration. |
noTools |
No | false |
Set to true to disable all built-in, extension, and custom tools for this agent. |
sessionPreference |
No | — | Advisory machine-readable hint for the main agent. One of ephemeral, persistent, or either. |
sessionHint |
No | — | Advisory free-form guidance shown to the main agent when choosing whether to pass session. |
Notes:
- Agent
modelis a default for that agent, not a lock. Amodelsupplied in a subagent call wins. toolsis passed to Pi's--toolsallowlist and can include built-in or extension tool names.noTools: truetakes precedence overtools.inactivityTimeoutobserves child RPC stdout bytes only. Child stderr and parent-generated progress updates do not keep a silent child alive.sessionPreferenceandsessionHintonly guide the main agent. They do not automatically create, require, or name persistent sessions.sessionHintcan be used by itself for free-form guidance; the extension does not infersessionPreferencefrom it.- The Markdown body becomes the agent's system prompt and is appended to Pi's default system prompt.
- Agent files are read when the tool runs; continued named sessions use the current definition of the agent name.
Available tools by default: read, bash, edit, write.
Optional built-in tools:
grep— Search file contentsfind— Find files by glob patternls— List directory contents
For a read-only agent, use tools: read,find,ls,grep. For an agent with no tools at all, use noTools: true.
These sections document the subagent tool interface and runtime behavior. They are for advanced users, extension authors, and maintainers — you do not need them for everyday use.
Each subagent runs in a separate pi process:
- No shared memory/state with the parent process.
- No visibility into sibling subagents.
- Its own model/tool/runtime loop.
- Uses Pi's headless RPC mode so prompts are transported verbatim and completion follows Pi's settlement events.
- Interactive UI requests from inherited extensions are cancelled because subagent processes have no interactive user; non-interactive extension hooks continue normally.
- Started with
PI_OFFLINE=1to skip startup network operations and reduce latency. - Inherits relevant parent configuration such as extensions, theme/skill flags, thinking/tool defaults, and custom session storage when applicable. When neither the call nor agent file sets a model, the child receives the parent session's current effective provider/model at delegation time. Temporary
--approvetrust is inherited only when the child uses the same working directory;--no-approveis always preserved. A per-callmodeloverrides the agent file's default model.
The main agent receives a concise text summary for each subagent call. Tool calls, usage, generated session IDs, and creation metadata are available to the TUI and tool result details; the text summary includes only the logical session handle in the call header when one was provided.
The tool is named subagent and accepts one top-level calls array. Use the same shape for one call and many calls.
{
"calls": [
{
"agent": "explore",
"prompt": "Find where authentication is implemented."
}
]
}A tool invocation accepts between 1 and 8 calls. Each call supports:
| Field | Required | Default | Description |
|---|---|---|---|
agent |
Yes | — | Exact name of an available subagent. |
prompt |
Yes | — | Non-empty prompt sent verbatim to the subagent. |
model |
No | Agent or current parent Pi model | Model to use for this call. Overrides the agent file's default model. |
cwd |
No | Parent cwd | Working directory for this subagent process. |
initialContext |
No | "empty" |
"empty" starts without parent history. "parent" exceptionally clones the current parent snapshot; this is expensive and carries the parent conversation's authority. Prefer empty and pass relevant context deliberately. Existing named sessions ignore this field. |
session |
No | — | Logical handle of at most 120 characters for a persistent child Pi session. Use this for multi-turn specialist work. Requires a persisted parent Pi session. |
inactivityTimeout |
No | Agent default or disabled | Positive integer seconds without child RPC stdout activity before termination (maximum 2,147,483). Overrides the agent frontmatter default. Stderr and parent progress updates do not reset it. |
timeout |
No | Unlimited | Exceptional positive integer absolute wall-clock deadline in seconds (maximum 2,147,483), independent of inactivityTimeout. Omit it for ordinary stuck-run protection. |
{
"calls": [
{
"agent": "explore",
"prompt": "Find where authentication is implemented."
}
]
}{
"calls": [
{
"agent": "review",
"model": "anthropic/claude-sonnet-4",
"prompt": "Review correctness risks in the current diff."
}
]
}If omitted, the agent file's model is used when configured; otherwise the child uses the parent session's current effective provider/model at delegation time. This applies to continued named sessions too, so a parent model change affects their next call.
{
"calls": [
{
"agent": "review",
"prompt": "Review correctness risks in the current diff."
},
{
"agent": "testing-audit",
"prompt": "Find missing test coverage in the current diff."
}
]
}Start a durable subagent conversation:
{
"calls": [
{
"agent": "review",
"session": "api-review",
"prompt": "Start a review plan for the API changes."
}
]
}Continue the same specialist conversation later:
{
"calls": [
{
"agent": "review",
"session": "api-review",
"prompt": "Now review the implementation against your earlier plan."
}
]
}{
"calls": [
{
"agent": "review",
"session": "api-review",
"initialContext": "parent",
"prompt": "Use the current parent conversation as context and start a review plan."
}
]
}If the named session already exists, the subagent continues it and initialContext is ignored. If it does not exist, the new child session is seeded from the parent snapshot. Use this only when the full parent history and authority are genuinely required; normally use empty context and include the relevant facts in prompt.
A session value is a logical handle, not a Pi display name and not a raw Pi session ID.
The extension derives an opaque Pi session ID from:
pi-subagent/v1 + parentSessionId + effectiveCwd + agentName + sessionHandle
The generated Pi session ID looks like:
subagent.<hash>
The human-readable Pi display name is:
subagent: <agent> · <handle>
Important rules:
- Same
sessionhandle + same parent session + same effective cwd + same agent continues the same child session. - A new top-level Pi parent session creates a new subagent session namespace, even in the same repository.
- Same
sessionhandle with different agents resolves to different child sessions. - Same
sessionhandle with different effective cwd resolves to different child sessions. - A persistent child session can be used by only one running call at a time. The extension uses a session lock in the Pi session directory to guard this across parent processes. If a process is killed, a later call may report a stale lock and ask you to remove the lock directory manually after confirming no subagent is still running.
- If two calls in the same tool invocation resolve to the same persistent session, the whole request is rejected before any child process starts.
- Named child sessions require a persisted parent Pi session. If the parent is running with
--no-session, omitsessionfor ephemeral delegation. - Named child sessions are also unavailable from temporary parent-seeded subagent sessions. Use a named parent subagent session first if nested durable delegation is needed.
- To start a fresh durable conversation, choose a new
sessionhandle.
initialContext controls only how a newly-created child conversation starts:
"empty"— start without parent conversation history. This is the default and recommended mode."parent"— exceptionally copy the current parent session branch into the new child conversation before sending the prompt. Cloning can be expensive and carries the parent conversation's accumulated authority and instructions; pass relevant context deliberately in the prompt instead whenever practical.
Existing named sessions always continue their own history and ignore initialContext.
Calls without session are ephemeral:
- no
session,initialContext: "empty"— fresh temporary child conversation - no
session,initialContext: "parent"— temporary child conversation seeded from the parent snapshot - with
session— persistent child Pi session
When multiple calls need initialContext: "parent", they all receive the same parent snapshot captured at the start of the tool invocation.
inactivityTimeout and timeout are independent:
inactivityTimeoutis the normal stuck-run guard. Its countdown starts with the child run and resets only when bytes arrive on the child's RPC stdout. Stderr output and parent synthetic progress updates do not reset it.timeoutis an exceptional absolute wall-clock deadline. Activity never extends it. Omit it for ordinary stuck-run protection.- Either expiry preserves captured partial output and reports a distinct error. On Unix, the child process group receives SIGTERM followed by SIGKILL when needed; on Windows, the existing
taskkill /T /Fprocess-tree termination path is used.
A per-call inactivityTimeout overrides the selected agent's frontmatter value. If neither is configured, there is no inactivity watchdog.
The main agent receives a uniform wrapper for one or many calls:
2/2 succeeded
[1: review session=api-review] completed:
...
[2: testing-audit] completed:
...
If any call fails, the tool result is marked as an error while still returning every call's output:
1/2 succeeded
[1: review session=api-review] completed:
...
[2: testing-audit] failed:
Unknown agent: "testing-audit".
Model-facing output is limited to 50KB or 2000 lines. When a captured result exceeds either limit, every call's status remains visible, captured details remain available in the expanded TUI, and the complete captured summary is written to a mode-0600 temporary file for the lifetime of the parent Pi session.
Process capture is separately bounded to prevent a long-running child from consuming unbounded memory. The runner retains a rolling 5MB window of assistant messages. Earlier messages and oversized tool-only messages may be omitted; oversized final text is retained in truncated form with an explicit marker. The temporary summary artifact contains the complete captured summary, not an unbounded raw event transcript.
Full session metadata, including generated session ID, effective cwd, creation status, and applied initial context, is available in the tool result details and TUI expanded view.
By default, this extension enforces two runtime guards:
- Depth guard (
--subagent-max-depth, default3)- Main agent starts at depth
0. - Delegation is allowed while
currentDepth < maxDepth. - With default depth
3: depth0,1, and2can delegate; depth3cannot.
- Main agent starts at depth
- Cycle guard (
--subagent-prevent-cycles, defaulttrue)- Blocks delegating to any agent name already present in the current delegation stack.
- Prevents self-recursion and loops.
Configure depth with either:
- CLI flag:
--subagent-max-depth <n> - Environment variable:
PI_SUBAGENT_MAX_DEPTH=<n>
Configure cycle prevention with either:
- CLI flag:
--subagent-prevent-cycles/--no-subagent-prevent-cycles - Environment variable:
PI_SUBAGENT_PREVENT_CYCLES=true|false
Internal env vars managed by the extension and propagated to child processes:
PI_SUBAGENT_DEPTHPI_SUBAGENT_MAX_DEPTHPI_SUBAGENT_STACK(JSON array of ancestor agent names)PI_SUBAGENT_PREVENT_CYCLES
Recommended integration note: if another extension needs to detect whether it is running inside a delegated subagent process, check PI_SUBAGENT_DEPTH. Treat PI_SUBAGENT_DEPTH > 0 as "this pi process is a subagent".
Inspired by implementations from vaayne/agent-kit and mariozechner/pi-mono.
MIT