@henryqw/pi-subagent
Delegate bounded single, parallel, or chained tasks to isolated Pi roles.
Package details
Install @henryqw/pi-subagent from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@henryqw/pi-subagent- Package
@henryqw/pi-subagent- Version
5.0.0- Published
- Aug 28, 2026
- Downloads
- 5,266/mo · 3,987/wk
- Author
- henrywang
- License
- MIT
- Types
- extension, skill
- Size
- 224.9 KB
- Dependencies
- 3 dependencies · 4 peers
Pi manifest JSON
{
"extensions": [
"./extensions/subagent.ts"
],
"skills": [
"./skills"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@henryqw/pi-subagent
Delegate bounded work to isolated Pi child processes. Generic delegate_task selects one flat single, parallel, or chain mode. Package-owned delegate_flow runs a fixed Git implementation-and-review Flow. Package authors can reuse the same Role launch policy and active-Pi executor from JavaScript.
Why
- Created for: Pi users who need to delegate bounded work to isolated child Pi processes without losing Main's context.
- Advantage: Generic bounded delegation plus a deterministic package-owned Git Flow, with reusable Role launch policies for package authors.
Install
pi install npm:@henryqw/pi-task-models
pi install npm:@henryqw/pi-multi-codex
pi install npm:@henryqw/pi-subagent
With
| Package | Why |
|---|---|
@henryqw/pi-task-models |
Required shared fast / balanced / frontier / fav routes. |
@henryqw/pi-multi-codex |
Required so children can use Main's active Codex slot. |
Use
| Surface | Type | Purpose |
|---|---|---|
delegate_task |
tool | Generic bounded delegation in one single, parallel, or chain mode. |
delegate_flow |
tool | Package-owned parallel implementation and declared-order Git integration for 1–8 independent units. |
delegate_flow_continue |
tool | Repair the blocked Flow unit once in its existing worktree. |
delegate_task
Select exactly one shape:
// Single
{ role, task, model?, modelClass?, thinking?, background? }
// Parallel: 1–8 independent delegations
{ tasks: [{ role, task, model?, modelClass?, thinking? }], background? }
// Chain: 1–8 dependent delegations
{ chain: [{ role, task, model?, modelClass?, thinking? }], background? }
model is provider/modelId and overrides modelClass. modelClass is fast, balanced, frontier, or fav; omission uses the shared pi-subagent/delegateTask assignment. background applies to the entire selected mode and is never a per-delegation field.
Parallel mode starts entries concurrently, waits for every entry, and reports them in input order. Chain mode is sequential and fail-fast; every literal {previous} receives only the immediately preceding successful assistant output. Foreground failures throw after retaining bounded sibling and recovery evidence. One tool call has one aggregate 50 KiB Main-visible transport cap, not 50 KiB per child.
Background workflows are session-scoped. Session shutdown or reload aborts them and may deliver only recoverable-work evidence or no follow-up message.
The transient status widget owns live progress: spinner or terminal state, wrapped task summary, model, thinking level, tokens, and duration; at capacity, it evicts the oldest terminal row so new active work remains visible, and terminal rows otherwise clear on the next real user input. The final delegate_task block is deliberately minimal: bounded final summaries, role attribution for parallel/chain, and only retained-worktree recovery paths. It has no expanded view.
Each delegation resolves its own Role, resources, route, and optional worktree request. When available, isolation: worktree gives each entry a deterministic separate worktree; non-Git or unborn-HEAD contexts may use Main's cwd. Siblings and chain steps never implicitly share one created worktree.
See Orchestration, isolation, and the public API for generic delegation, Flow behavior, and JavaScript composition examples.
delegate_flow
Use Flow only for independent, commuting Git changes. It accepts 1–8 uniquely identified units, each with a bounded task and direct command/argument validation gate:
delegate_flow({ units: [{ id, task, validation: [{ command, args }] }] })
delegate_flow_continue({ guidance })
One memory-only Flow may be active. At start it resolves the effective implementer and reviewer Roles, including same-named user overrides, and freezes them through any continuation. Overrides must remain compatible with Flow: Implementers commit scoped work, and Reviewers inspect the exact packet and emit exactly PASS only with zero findings. It creates one Unit Worktree per unit, runs Implementers in parallel, then processes settled results in declared order. For each unit, Flow rebases onto the current Flow Main when needed, runs its declared validation, gives the Reviewer the exact {base, tip, patchPath} packet in that same worktree, and only exact PASS permits git merge --ff-only of the full reviewed OID. It removes the worktree and branch non-forcibly after integration; a refusal is a completion warning with the retained worktree path and/or branch.
A rebase that drops all unit commits is a no-op: Flow validates it, skips Reviewer and merge, then cleans up ordinarily. Implementer, validation, or review blocks can be repaired once through delegate_flow_continue in the same worktree. Rebase and infrastructure failures are terminal. A reported fast-forward failure completes with its diagnostic as a warning only when Git left Main clean at the exact reviewed tip; otherwise it is terminal and retains the affected worktree. Flow has no graph, saved recovery, automatic retry, aggregate review, or post-merge gate.
delegate_task remains generic with its ordinary isolation behavior. Flow uses the same effective Role resolution for implementer and reviewer; without user overrides, the package-shipped Roles remain the defaults.
Config
pi-subagent owns the extension-named config directory ~/.pi/agent/config/pi-subagent/, which holds two kinds of user-owned configuration: one Markdown file per Role (see Roles) and its own optional JSON file below. Model routing is not configured here; children resolve routes through the shared @henryqw/pi-task-models config at ~/.pi/agent/config/pi-task-models.json.
~/.pi/agent/config/pi-subagent/pi-subagent.json controls the ephemeral child pool and timeouts. All fields are optional; a missing file uses defaults.
| Field | Required | Possible values | Default |
|---|---|---|---|
maxSubagents |
No | Safe integer ≥ 1 | 5 |
timeout.idleMinutes |
No | Positive number of minutes where minutes × 60 000 ms ≤ 2,147,483,647 | 10 |
timeout.maxMinutes |
No | Positive number within the same ms cap that must be greater than timeout.idleMinutes, otherwise the whole timeout object falls back to defaults |
30 |
Excess children wait FIFO without consuming child timeout. PI_SUBAGENT_MAX_SUBAGENTS overrides maxSubagents for the session (positive integer; an invalid value prevents the extension from loading, leaving delegate_task unavailable).
This JSON is read leniently: malformed JSON, a non-object root, unknown keys, or invalid values are collected into one warning and the affected settings fall back to defaults; the file is never rewritten.
Role frontmatter
Each Role .md file in the same directory accepts these frontmatter fields:
| Field | Required | Possible values | Default |
|---|---|---|---|
name |
Yes | Non-empty text; unique across roles | — |
description |
Yes | Non-empty text | — |
tools |
Yes | YAML array of non-empty tool names | [] activates no base built-ins; trusted extension tools and caller additions still activate |
isolation |
No | worktree |
None |
extensions |
Yes | YAML array of absolute paths, ~/…, file://, or package sources (npm:, git:, github:, https?:, ssh:) |
[] selects no Role extension bundle |
skills |
Yes | YAML array of non-empty Skill names | [] selects no separately named Role Skills; trusted extension Skills still load |
| body | Yes | System-prompt Markdown after the frontmatter | — |
An unreadable or invalid Role file fails role loading fast; duplicate role names are rejected.
Roles
The package ships two working built-in Roles, always available without any configuration:
implementer: focused edits requesting worktree isolation; commits completed scoped changes locally and never pushes or opens PRs without authorizationreviewer: read-only correctness review of supplied plans/files, or of Flow's exact{base, tip, patchPath}packet in its Unit Worktree; never edits or commits
A same-named Markdown file in ~/.pi/agent/config/pi-subagent/ explicitly overrides the built-in default.
The repository also includes optional inert samples:
scout: read-only discoverysynthesizer: reconcile supplied reports
Copy them manually from your installed @henryqw/pi-subagent package (npm installs ship the examples/roles/ directory) if you want them as a starting point:
mkdir -p ~/.pi/agent/config/pi-subagent
cp <package-install-dir>/examples/roles/scout.md ~/.pi/agent/config/pi-subagent/
Locate the install directory with npm root inside your project, or via Pi's package installation path.
The package never installs or writes Role configuration. Sample names are not built-ins; after copying, edit or replace them as your own Roles.
Skill
The bundled pi-subagent-delegated-development Skill is Main-side policy only. delegate_flow owns its fixed Git mechanics; the Skill adds no runtime code, configuration, or Role installation. Generic orchestration remains outside the executor under ADR 001.
A Role explicitly owns base tools, extensions, named Skills, instructions, and optional isolation: worktree. Every launch installs its Role tool policy: tools: [] activates no base built-ins, while trusted selected extension tools and explicit caller tool additions still activate. skills: [] selects no separately named Role Skills, while trusted selected extension Skills still load; extensions: [] selects no Role extension bundle. Ambient extension and Skill discovery is disabled in children. Selecting an extension explicitly is selecting a trusted atomic capability bundle, not just a provider path: every tool it registers and every Skill supplied through its Pi package metadata or dynamic resources_discover loads alongside separately named Role Skills. This is intentional because an extension may depend on its own tools, Skills, lifecycle, and prompt behavior; loading it permits that executable behavior and is not sandboxing. To scope a child, select fewer trusted extensions. Finer-grained selection requires separate extension entry points/configuration or an upstream split—pi-subagent does not infer or externally narrow undocumented dependencies. Parent-only recursive orchestration tools stay excluded. Explicit Role or caller tool names are verified against the child’s final filtered active registry after provider extensions finish session_start; all unavailable names fail before the first model turn with provider-extension guidance, while unavailable named Skills warn and skip.
Library API
The package root exports Role loading and launch resolution, createEphemeralSubagentExecutor, worktree helpers, and generic managed Herdr lifecycle helpers. The ephemeral executor is for code already running inside active Pi; it does not provide standalone Node.js Pi discovery or launch support. After Pi itself exits, it drains inherited stdout/stderr normally but destroys streams still held by escaped descendants after a short inactivity deadline or one-second hard deadline, so they cannot retain a pool permit.
Use docs/orchestration.md for exact API behavior and a post-permit prepare example using resolveRoleLaunch against the latest Pi context.