# pi-subagents Package Source: https://pi.dev/packages/pi-subagents (docs: `https://github.com/nicobailon/pi-subagents/tree/main/docs`) Delegate work to focused child Pi sessions: code review, scouting, implementation, parallel audits, saved workflows, background jobs. Installing the extension does not start anything automatically — it gives Pi a `subagent` delegation tool. ```bash pi install npm:pi-subagents ``` Users normally ask in plain language ("Use reviewer to review this diff", "Run parallel reviewers for correctness, tests, and complexity"). Pi decides whether to call the tool, which agent to use, and how to compose the work. ## Built-in Agents | Agent | Purpose | |---|---| | `scout` | Fast local codebase recon: relevant files, entry points, data flow, risks, where to start | | `researcher` | Web/docs research with sources; needs `pi-web-access` for `web_search`/`fetch_content`/`get_search_content` | | `worker` | Implementation, including approved oracle handoffs; escalates unapproved decisions | | `reviewer` | Code review and small fixes against task/plan, tests, edge cases, simplicity | | `oracle` (alias `advisor`) | Second opinion before acting; challenges assumptions, no edits | | `delegate` | Lightweight general delegate close to parent behavior (append prompt mode) | Builtins load at the lowest priority and inherit the current Pi default model unless `subagents.defaultModel` or an override says otherwise. Packaged `worker`, `oracle`, and `advisor` default to `context: "fork"`; others default to `fresh`. Builtins opt into project-instruction inheritance so they follow repo rules. Recommended implementation loop: **clarify → scout → worker → fresh reviewers → worker**. ## Execution: workflowScript All model-facing execution goes through `workflowScript` — an ordinary JavaScript statement body with an explicit `return`. The legacy `/chain`, `/parallel`, `/run-chain`, and `/chain-prompts` commands are no longer registered, and `.chain.md`/`.chain.json` files exist only as durable legacy chains. ```javascript // One child subagent({ workflowScript: `return runs.run("main", { agent: "scout", task: "Analyze the auth flow" })` }) // Sequential subagent({ workflowScript: ` const scan = await runs.run("scan", { agent: "scout", task: "Analyze auth" }); return (await runs.run("implement", { agent: "worker", task: "Implement from: " + scan.output })).output; ` }) // Parallel subagent({ workflowScript: ` const reviews = await runs.all([ { key: "correctness", agent: "reviewer", task: "Review correctness" }, { key: "tests", agent: "reviewer", task: "Review tests" } ]); return reviews.map(r => r.output); ` }) ``` Globals inside the script: `runs.run(key, opts)`, `runs.all([items])`, `runs.ref`, `state.get/set` (durable mission JSON state), and `prompts.render(ref, vars?)`. For long task text containing Markdown fences or shell blocks, build the string from quoted lines joined with `\n` rather than a raw template literal. Workflows default to background execution; pass `async: false` for a watched foreground run with a live in-chat card (`chatProgress` forces `auto`/`off`/`live-card`). Foreground workflows default to a 30-minute timeout; async workflows have no default top-level timeout. `prompts.render` needs an explicit scope: `package:`, `user:`, or `project:`, each naming a top-level `.md`. Frontmatter is stripped, scalar `{{name}}` placeholders are substituted, and unknown placeholders stay unchanged. Rendering returns text only — pass it explicitly as `task`. ### Key Tool Parameters `agent`, `action`, `topic`, `chainName`, `config`, `context` (`fresh`/`fork` — an explicit value overrides every workflow child; otherwise each child uses its own `defaultContext`), `missionId`, `mission` (object or `false`), `handoffPath`, `view` (`fleet`/`transcript`), `lines` (default 80, max 500), `agentScope`, `async`, `chatProgress`, `timeoutMs`/`maxRuntimeMs`, `toolTimeoutMs`, `turnBudget`, `toolBudget`, `usageBudget`, `cwd`, `maxOutput` (200 KB / 5000 lines), `artifacts`, `includeProgress`, `share`, `sessionDir`, `acceptance`, `gate`, plus per-item `output`, `outputMode`, `skill`, `model`, `worktree`, `resume`. Budgets: `turnBudget` is `{ maxTurns, graceTurns }` (warn at `maxTurns`, terminate at the next assistant boundary after the grace window); `toolBudget` is `{ soft?, hard, block? }` (block defaults to `read`/`grep`/`find`/`ls`; `"*"` blocks everything, final assistant text never blocked); `usageBudget` is root-only `{ tokens?: { soft?, hard }, costUsd?: { soft?, hard } }` where soft limits are status-only and hard limits prevent later child launches without stopping running ones. **Do not** set turn, hard tool, or tight usage budgets on mutation-capable children (implementation workers, fix workers, reviewers with edit authority) — none of those measure whether a delivery slice is buildable, and a default tool budget blocks read/search tools rather than mutations. Bound writers with a narrow task and an outer `timeoutMs` instead, and request a checkpoint via `steer` before the deadline. `context: "fork"` fails fast when the parent session is not persisted, the leaf is missing, or the branched session cannot be created — it never silently downgrades to `fresh`. Forking strips signed Anthropic `thinking`/`redacted_thinking` blocks from the child session and forces thinking `off` when the child's effective primary or fallback model resolves to the Anthropic provider or `anthropic-messages` API (unresolved models are treated conservatively). Use `fresh` when an Anthropic child needs thinking. `outputMode: "file-only"` returns a compact pointer (`Output saved to: /abs/report.md (48.2 KB, 2847 lines)…`) instead of inline text; failed runs and save errors still return inline output for debugging. A read-only child does not need filesystem access for `output` — it returns the artifact in its final response and the runtime persists it. ### Retained Children Completed workflow children from the current parent session stay addressable. `{ action: "children.list" }` lists up to the last 10 with run ids; a later workflow continues one by passing `resume` instead of `agent`: ```javascript subagent({ workflowScript: ` let writer = await runs.run("implement", { agent: "worker", task: "Implement the accepted contract" }); for (const pass of [1, 2]) { const task = await prompts.render("project:writer-followup", { pass, previous: writer.output }); writer = await runs.run("followup-" + pass, { resume: writer.runId, task }); } return writer; ` }) ``` Each resume can return a new retained run id, so loops must continue from the latest `runId`. `resume` and `agent` are mutually exclusive, the revived child keeps its stored agent/model/tool contract, and `gate` is rejected on resume items. Top-level `{ action: "resume" }` stays detached and returns a background receipt — use it for a simple challenge outside a script; use `runs.run({ resume })` only when the script must await the revived output. `steer` with `mode: "follow_up"` only queues text for the next `resume`; it does not revive a completed child. ## Commands ```bash /run [task] [--bg] [--fork] # one child /subagents-fleet # live fleet inspector /subagents-stop [run-id] # stop a top-level async run /subagents-detach [run-id] # leave a foreground run running /subagents-doctor # read-only setup diagnostics /subagents-guide [topic] # packaged docs for the installed version /subagents-refine # project-local refinement overlay /subagents-models [agent] # live runtime model mapping /subagents-watchdog [status|on|off|recommend-model|model ...|session model ...|check] /subagents-refresh-provider-models [--force] /subagents-generate-profiles | /subagents-load-profile | /subagents-check-profile /prompt-workflow