Evan Reichard 5c5cdb3aec refactor(subagent): split responsibilities and isolate child prompt
- Extract validateAgent, toToolResult, runAgentWithRetries so index.ts
  is wiring only; orchestration, validation, and result shaping each own
  their concern.
- Separate runner internals: createRunState, handleEvent (pure event
  reducer), spawnPi (process lifecycle), runOnce (single attempt).
- Track attempt/maxAttempts on SubagentStatus; surface "try x/y" in the
  UI without overwriting the user-facing task with the retry preamble.
- Replace pi's default system prompt (--system-prompt) instead of
  appending, so the subagent .md body is authoritative.
- Document prompt-replacement and retry/cache semantics in AGENTS.md.
2026-05-12 15:02:49 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00
2026-05-11 17:20:02 -04:00

pi-subagents

Pi extension that registers a subagent tool. Subagents are defined by markdown prompts in prompts/*.md.

Prompt format

---
name: scout
description: Fast codebase reconnaissance
approved_tools:
  - read
  - bash
---
System prompt for the subagent goes here.
  • approved_tools / allowed_tools is whitelist mode: the subagent receives only those tools.
  • denied_tools is blacklist mode: the subagent inherits currently active tools except subagent and internal tools.
  • Do not define whitelist and blacklist fields together; the extension rejects ambiguous configs.

Tool usage

{
  "agent": "scout",
  "task": "Find where authentication middleware is registered"
}

The tool returns the subagent's finalized result as normal text with a compact status/session header for clients that hide structured tool metadata:

**Status:** SUCCESS  
**Session ID:** `550e8400-e29b-41d4-a716-446655440000`

---

...

Metadata also includes the sticky session id:

{
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "finalized": {
    "status": "SUCCESS",
    "result": "..."
  }
}

To continue the same child subagent context, pass the returned sessionId:

{
  "agent": "scout",
  "sessionId": "550e8400-e29b-41d4-a716-446655440000",
  "task": "Keep going and inspect the registration path"
}

If sessionId is omitted, a new child session is created.

Sticky sessions

Subagent sessions persist under:

~/.pi/subagent-sessions/<cwd-hash>/<agent>_<sessionId>.jsonl

Session identity is scoped by working directory, agent name, and session id. Reusing the same sessionId with the same agent and cwd resumes that child context.

Finalization

Subagents do not return final answers as free-form assistant text. Child runs get an internal subagent_finalize tool and must call it as their final action:

subagent_finalize({
  status: "SUCCESS" | "ERROR",
  result?: string,
  error?: string,
})

Rules:

  • SUCCESS requires a non-empty result.
  • ERROR requires a non-empty error.
  • ERROR.result may contain partial findings.
  • If the child exits without valid finalization, the extension continues the same session with corrective feedback, up to a small retry limit.
  • subagent_finalize is registered only in child subagent processes, never in the parent context.

How it runs

The extension spawns an isolated child pi process in JSON mode with the resolved tools and a persistent session file:

pi --mode json -p --session <session-file> --tools <resolved-tools> <task>
Description
No description provided
Readme 131 KiB
Languages
TypeScript 98.1%
Nix 1.9%