@howarewoo/pi-subagents
Pi-native single-assignment delegation with explicit profiles and parent-owned SDK children
Package details
Install @howarewoo/pi-subagents from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@howarewoo/pi-subagents- Package
@howarewoo/pi-subagents- Version
0.2.1- Published
- Nov 13, 2026
- Downloads
- 253/mo · 253/wk
- Author
- howarewoo
- License
- MIT
- Types
- extension
- Size
- 671.4 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./src/pi-extended-subagents.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@howarewoo/pi-subagents
Delegate work to subagents in Pi, follow their progress, and steer or stop them from Subagent Hub. Subagents use your selected model by default, with their own assignments and explicit tool grants.
Pinned Subagents widget at default capacity: 16 running tasks and 32 queued. Counts and nested-agent progress stay visible above the editor. Synthetic demo data, not a live load test.
Installation
Requires Node 22.19+ and stable Pi 1.5.2 or newer. Tested host: Pi 1.5.2; newer stable versions are allowed, not guaranteed compatible. Prerelease, older, malformed and unknown host versions are rejected before task reads, allocation or model requests. Wildcard host peer dependencies follow Pi's package format, not a compatibility promise. See host support for version rules.
If the host is unsupported, let active tasks drain, update Pi and restart. Status, stop/cleanup and diagnostics remain available where the extension can load; arbitrary older SDKs may fail at module load. The minimum-host restriction is a breaking change in 0.2.0. When upgrading from 0.1.x, drain active tasks, install stable Pi 1.5.2 or newer, update the extension and restart Pi.
Install from npm:
pi install npm:@howarewoo/pi-subagents
Alternatively, install from Git with pi install git:github.com/howarewoo/pi-subagents.
Use only one source: when switching between npm, Git or a local checkout, remove the
previously registered source first so Pi does not load the extension twice.
Restart Pi and run /subagent-profiles to check the installation.
Migrate from the old package
If you installed the former unscoped package, follow the 0.1.1 migration instructions before installing the current package.
Use delegation
Choose a model through Pi's /login and /model setup. Delegation uses that provider and may incur charges; it does not automatically switch to a cheaper model.
Ask Pi:
Use delegate_task with profile scout to locate the startup lifecycle code and report source locations. Run it in the foreground.
The corresponding tool call is:
{
"assignment": "Locate startup lifecycle code and report source locations",
"profile": "scout",
"background": false
}
Or submit a batch:
{
"tasks": [
{ "assignment": "Locate startup code", "profile": "scout" },
{ "assignment": "Review lifecycle tests", "profile": "review", "limits": { "requests": 20 } }
],
"background": false
}
The default is 16 concurrent tasks, a 32-item queue and up to 16 tasks per batch. Every item passes preflight before any starts. One failed task does not cancel its siblings.
scout and review allow up to read, grep, find and ls. general and implementation also allow write, edit and bash. Each role receives only the builtins already callable in the parent. With Pi's default tools, scouts get read only. Tool calls retain the parent's permission hooks; incompatible tool overrides are rejected.
general inherits available parent skills, not parent instructions or history. Its role prompt and assignment remain intact. Operator/trusted-project tools and skills settings can narrow inheritance; [] removes grants. General can write when its effective tool set allows it.
Extension/MCP tools require operator review. Set general.leafTools to exact names only for trusted tools that never call other Pi tools or change the tool/model/session loadout. Descriptions and annotations do not grant trust. Orchestrating/reaching tools, codemode, tool search, owned controls, hidden/model-only tools and builtin replacements cannot be forwarded. Leaf tools require the global writer lease and the root workspace; only builtins support cwd adaptation. See restricted inheritance.
Foreground calls return the final results. Set background:true to return immediately and receive one ordered completion message after the batch drains. Use the returned task ID and generation for controls:
/subagent-profiles
/subagent-status
/subagent-status <id> <generation>
/subagent-steer <id> <generation> <text>
/subagent-stop <id> <generation>
/subagent-hub
Native orchestration
Pi discovers the native subagent tool at startup through its tool description and coding-worker guidance; no enable call is needed. For replacement use, load only one extension providing subagent: Pi uses the first registration, not an automatic provider preference. Switching providers does not migrate or remove old runs.
{
"agent": "worker",
"task": "Implement the approved change; follow the supplied repository guidelines and task references",
"cwd": "/absolute/path/to/task-worktree"
}
workermaps to the configuredimplementationprofile;scout,reviewandgeneralare also available.- Calls are async by default and wake the parent after drain. Set
async:falseto wait; usetasks:[{agent,task,cwd?}]for a batch. - Control a task with its returned
idandaction:"status","steer","stop"or"resume". Steer/resume also requiremessage. - Resume keeps a paused conversation in the same generation. Completed idle/parked work gets a fresh generation, so include needed prior conclusions.
The coordinator supplies an existing workspace and the complete handoff, including accessible skill/reference paths. The extension does not create or manage worktrees. This is the supported orchestration interface, not compatibility with every competing workflow script or custom agent definition.
Subagent Profiles
Run /subagent-profiles to inspect the resolved profiles for the current workspace: bundled definitions, operator delegation.json, then trusted-project narrowing. It opens a read-only list/details overlay, not an editor. Reopen it after configuration changes to refresh the snapshot.
Use ↑/↓ to select a role; j/k, PgUp/PgDn and Home/End scroll details; Esc closes (configured selection bindings also apply). Narrow terminals stack the list above details; tiny terminals ask you to resize. Details show the description, prompt, builtin tool ceiling, exact skill paths, spawn/coordination ceilings and model/prewalk policy.
Ceilings are not callable tools. Pi's command context has no callable-tool dispatcher, so the viewer reports effective tools as unknown rather than treating active declarations as executable grants. Admission performs the real intersection and remaining checks; inspect a task's tools in /subagent-status or Hub Details. RPC, JSON and print modes retain the structured {toolPolicy, profiles} message instead of opening an overlay. Invalid configuration or missing/invalid granted skills fails resolution, as at admission.
Synthetic native-component output; not a terminal screenshot or live-provider verification.
Subagent Hub
Subagent Hub shows the task list beside the selected conversation using Pi's native renderers. On narrow terminals, the conversation takes the full width. Details shows results, artifacts, grants and usage; Tools shows full sanitized arguments and result text.
The thread follows new output until you scroll up. Press End to follow again. The pinned Subagents widget appears after the first task starts. Closing Subagent Hub does not stop the work.
The Hub and widget illustrations use native renderer output with a synthetic fleet filling the default 16 concurrent slots and 32-item queue. Four read-only audit leads each have three foreground descendants, reaching the default nesting depth of two. The queue represents two further 16-task root batches, not one oversized batch. These are illustrations, not terminal screenshots or live-provider stress-test evidence. Regenerate them with node scripts/render-hub-hero.ts and node scripts/render-hub-hero.ts --widget.
Subagent Hub at default capacity: tasks and conversations side by side, with nested scouts/reviewers at depth two. The roster scrolls through all 48 tasks.
| Key | Action |
|---|---|
| ↑ / ↓ | Select a subagent or historical generation |
| j / k | Scroll down / up one line |
| Ctrl+u/d or PgUp/PgDn | Scroll a page |
| Home / End | Top / latest output |
| Tab | Switch between thread, details and tools |
| / | Filter the subagent list |
| s / m | Steer / send an inbox message |
| x, then y | Stop the selected subtree; Enter does not confirm |
| w / p | Wait briefly for an outcome / park an idle task |
| Esc | Cancel input or close the Hub |
Mouse-wheel scrolling works in fullscreen mode. In regular mode, use the keyboard controls because the terminal owns mouse scrollback. Actions stay pinned to the original task and generation; controls refuse to submit if the window cannot show the full target.
Messages and follow-up work
Use delegate_coordinate to message a running subagent, wait for an outcome or assign follow-up work. Include it in any explicit tool allowlist alongside delegate_task.
{"action":"message","target":{"id":"<task-id>","generation":1},"text":"Check the shutdown path too","mode":"steer"}
{"action":"wait","target":{"id":"<task-id>","generation":1},"timeoutMs":30000}
{"action":"followup","target":{"id":"<task-id>","generation":1},"assignment":"Now review the cancellation path"}
Each line is a separate call. An accepted or queued message is not a delivery confirmation; even a delivered receipt does not prove the model understood it. Follow-ups start a new generation without replaying the old conversation, so include the context it needs. Follow-up and revival are model-tool operations, unavailable directly in Subagent Hub. Child messaging is off until explicitly granted. See the coordination reference.
Task files and structured results
Use taskFile instead of assignment to read instructions from a workspace-relative text file. Add resultSchema when you need a validated JSON value:
{
"taskFile": "tasks/review.txt",
"profile": "review",
"resultSchema": {
"type": "object",
"properties": { "summary": { "type": "string" } },
"required": ["summary"],
"additionalProperties": false
}
}
Task files must be regular UTF-8 files of 1 to 50000 bytes, outside hidden paths and node_modules. Reads use the parent's permission hooks. Schema-required children call submit_result({value:...}); missing or invalid results fail visibly. See supported schemas and task-file checks.
Configuration
No configuration is needed for the bundled roles. To change prompts or narrow tools, use ~/.pi/agent/delegation.json:
{
"review": {
"tools": ["read", "grep"],
"skills": ["/absolute/operator-reviewed/review/SKILL.md"],
"prompt": "Review this assignment and report concrete findings with source locations."
}
}
All bundled profiles may delegate to scout and review by default, within a total depth of two (root 0, child 1, grandchild 2). Other nested targets and child messaging need explicit operator grants. Set spawn: [] to revoke nesting. General inherits available parent skills; other roles need explicit skill grants. Trusted project configuration in .pi/delegation.json can narrow grants, never expand them. Children do not load ambient extension/MCP runtimes or context files; general can forward only the reviewed leaf tools described above.
Default task limits are 30 minutes, 100 model requests and 100 tool calls:
- A deadline pauses the active subtree after tool/provider drain, releasing capacity and writer leases but retaining sessions and conversations.
- Use
subagentresume or root-onlydelegate_coordinate{action:"resume",target:{id,generation},assignment:"Continue…"}to continue the same identity and conversation. Only the deadline resets; request/tool/spawn counters remain cumulative. - Resume the parent first, then explicitly selected children. Descendants never resume automatically.
- Stop, shutdown and hard request/tool limits cancel and dispose. Unresponsive code must drain before pause or cancellation can release resources.
See limits and nesting, profile grants, and model selection and prewalk.
Shared checkout and lifetime
Subagents use your checkout unless you supply an existing directory as cwd. Parent permission hooks still apply and may deny access. Writers serialize even across worktrees, and workspace selection is not a sandbox. Manual commands, external editors and other sessions are uncoordinated: avoid conflicting edits. See workspace safety.
Keep the parent runtime alive until work finishes. Shutdown or reload aborts and drains children; there is no restart recovery or cross-parent revival. Saved transcripts and results may contain sensitive task, tool and model output; protect them like your main Pi transcripts.
Why worktrees are managed externally
Create or select a workspace externally, then pass cwd as in the
native orchestration example. The caller owns it throughout the
assignment, including inspection, integration and removal. Automatic worktree creation,
commits, apply and cleanup are intentionally outside scope, not planned features.
Separate worktrees neither bypass writer serialization nor provide a sandbox. See workspace ownership and writer coordination.
Why workflows and scheduling stay external
Separate packages can compose the public delegation tools and own when and how to run assignments within the parent runtime. This does not grant automatic tool/context inheritance or promise compatibility with existing third-party workflow packages. See orchestration boundaries.
Updates and rollback
Let active subagents finish before updating, then restart Pi. Shutdown or /reload aborts
and drains children; active tasks are not migrated to the new version. There is no extension-owned
auto-updater.
# Update an unpinned npm installation
pi update npm:@howarewoo/pi-subagents
# Or update all installed extension packages
pi update --extensions
Plain pi update updates Pi itself, not installed extension packages. For a Git installation,
use pi update git:github.com/howarewoo/pi-subagents, matching the source you registered.
An unpinned Git source tracks the repository's default branch, including unreleased commits.
For a reproducible npm installation or rollback, select an exact published version:
pi install npm:@howarewoo/pi-subagents@0.2.0
For Git, select a published tag, for example
pi install git:github.com/howarewoo/pi-subagents@v0.2.0.
Exact npm versions and Git tags stay pinned; updating does not advance them to the next release.
Install a different version explicitly to change the pin.
CHANGELOG.md lists user-facing changes and migrations. Pi shows new package changelog entries on the next fresh launch after a version increase. See the maintainer release guide for publishing and recovery.
Feature comparison
Compared with two community alternatives using their documentation, checked on 2026-11-11. Tintinweb's messaging scope was additionally checked against source at revision b72b414 (2026-11-12). This is a feature comparison, not a performance or reliability benchmark. UI cells name documented surfaces; they do not imply other features are absent.
| Feature | @howarewoo/pi-subagents | nicobailon/pi-subagents | tintinweb/pi-subagents |
|---|---|---|---|
| Background tasks | ✅ Parent-bound by design; until exit or reload | ✅ Supported | ✅ Supported |
| Nested delegation | ✅ Supported | ✅ Supported | ✅ Supported |
| Task list / conversation | ✅ Subagent Hub: split panes; full-width thread on narrow terminals | ✅ Fleet inspector: roster and output pane | ✅ FleetView opens a separate conversation viewer |
| Message / tool rendering | ✅ Native Pi message and tool components | ✅ Structured Markdown/tool transcripts | ✅ Markdown + session-registered tool renderers |
| Bi-directional agent messaging | ✅ Supported; parent/child and siblings | ⚠️ Child/supervisor requests and replies | ⚠️ Parent-to-child steering + result return; no built-in child-initiated or sibling messaging |
| Live follow / scrollback | ✅ Scroll up to pause; End to follow | ✅ Scroll away to pause; bottom resumes | ✅ Scroll up to pause; End to follow |
| In-UI task controls | ✅ Hub: steer, inbox, stop, wait, park | ✅ Inspector: steer/follow-up and stop async runs | ✅ Viewer: steer, stop, foreground-to-background handoff |
| Tool / usage inspection | ✅ Tools: sanitized arguments/results; Details: direct usage | ✅ Expandable tool details + token counts | ✅ Expandable tool output + tokens; optional cost |
| Schema-validated results | ✅ Supported | ✅ Supported | ⚠️ Workflow agents only |
| Managed Git worktrees | 🚫 By design; caller-managed worktrees supported | ✅ Supported | ✅ Supported |
| Workflow scripts | 🚫 By design; caller-owned | ✅ Supported | ✅ Supported |
| Scheduled runs | 🚫 By design; no scheduler | ✅ Supported | ⚠️ Session-scoped agents only |
Legend: ✅ Supported (stated design boundaries apply) · ⚠️ Supported with scope restrictions · 🚫 By design.
🚫 marks a deliberate product boundary, not a missing implementation within the current contract. Linked explanations describe the trade-offs behind this repo's choices.
Sources: our contract; nicobailon's README, agents, workflows and observability; tintinweb's README and workflows.
Architectural decisions
These choices define the current execution contract and its trade-offs. They are not claims that other designs are unsafe or impossible. Deferred capabilities are identified separately; an unsupported feature is not automatically a permanent exclusion.
Why background tasks are parent-bound
Background tasks belong to the live parent Pi runtime. Shutdown or /reload cancels
children and drains their tools and descendants before releasing capacity and writer
leases. Closing Subagent Hub does not stop work. This prevents replacement writers
from overlapping tools that are still stopping.
Keep Pi running until tasks finish: there is no detached runner or restart recovery. Unresponsive provider, permission or tool code can delay drain; abrupt process death cannot guarantee cleanup. Saved transcripts are inspection records, not restart state.
In the cited versions, nicobailon uses detached background processes. Tintinweb stops agents on shutdown but supports persisted conversation resume and foreground-to-background handoff. Persisted conversations do not keep jobs running after exit. See the delegation contract for continuation semantics.
Why nested delegation is foreground-only
Nested calls require explicit profile grants and wait for their children while retaining their execution slot. Work that cannot start immediately is rejected rather than queued behind waiting ancestors or given extra capacity. A writing child cannot spawn another writer beneath itself.
This keeps capacity and ownership predictable but limits fan-out. Parent completion or stop drains descendants; there are no detached grandchildren. See lifecycle and scheduling.
Why permissions and resources are explicit
Profiles cap tools at what the parent can call. Builtin calls retain the parent's permission hooks; operator grants set authority, and trusted-project configuration and task requests can only narrow it. Selecting another workspace does not load its trust policy.
Children receive their assignment, role prompt and granted skills, not parent instructions, history or ambient context. General also inherits available skills and may use exact operator-reviewed leaf tools. Full extension/MCP runtime inheritance and tool-to-tool forwarding are unsupported, so provide a complete handoff. Tool grants and cwd adaptation are not an OS sandbox. See permission and resource boundaries.
Why model routing is exact
Children use the parent's selected model and effort by default. Overrides require exact operator-approved provider/model/effort grants. Unavailable selections and unsupported effort fail visibly; there is no automatic cheaper-model or provider fallback. Authentication stays with the parent's registry, not child task directories.
A configured role prewalk can make one approved model switch after an edit/write call; it adds no hidden planning inference. See models and authentication.
Why workspaces are caller-managed and writers serialize
Pass an existing directory as cwd, including a caller-created worktree. The extension
adapts builtin paths and shell cwd through parent permission hooks. Worktree creation,
branch/base selection, integration and cleanup stay with the caller or separate tooling,
keeping this extension focused on subagent execution, coordination and UI.
Workspace selection is not containment: paths and shell commands can reach outside the directory when parent permissions allow. Effective writing tasks share one global lease, even across worktrees; coordinated parent model-tool mutations cannot overlap a child writer. The lease lasts through actual drain, sacrificing parallel writing throughput rather than assuming different directories isolate every write.
Manual !/!! commands, external editors, other sessions and arbitrary extension
JavaScript are not coordinated. Avoid conflicting edits while a subagent writes.
See tool execution and workspaces
and explicit working directory.
Why structured results require explicit submission
Schema-required children must call submit_result with a value matching the supported
bounded JSON Schema subset. Final prose is not parsed. Submission is provisional until
execution and descendants drain: it cannot override cancellation or failure, and a
missing required submission fails the task.
Whole batches pass preflight before admission. Results keep input order, and a failed child does not cancel unrelated siblings. Background batches send one outcome after drain, so fast results may wait for slower siblings. See results and persistence.
Why the UI observes one native registry
Hub, the widget and result cards observe the same coordinator; viewers do not start another executor. Pi's native components render sanitized conversations, using split panes or a full-width thread on narrow terminals.
Usage is reported directly per generation, without recursive parent totals or estimates for missing provider usage. Display sanitization does not redact saved files. See observation and terminal UI.
Why controls are identity-pinned
Controls target a UUID and generation, so stale selections cannot change newer assignments. Paused continuation keeps its conversation; follow-up or revival of completed work starts a fresh generation under current, narrowed authority. Supply needed prior conclusions: old transcripts are not replayed.
Hub uses the same registry authority as the tools, but cannot start new generations: its command context lacks Pi's permission-preserving tool dispatcher. Use model-issued tool calls for those actions. See coordination, presence and generations.
Why agent messaging is family-scoped
Explicit grants allow parent/child messages in both directions and sibling messages within the same exact parent generation. Senders must know the recipient's UUID and generation. Children cannot enumerate the registry, address arbitrary sessions or read peer transcripts.
delegate_coordinate supports inbox, steering/follow-up delivery and bounded event-driven
waits. Recipients must be running; inbox delivery does not trigger parent inference.
Receipts distinguish acceptance, queuing and visibility, not model acknowledgment.
Mailboxes and waits are finite, waits retain capacity, and cycles are rejected. Callers
must arrange identities and replies; this is not a durable broker or blocking supervisor
interview.
Nicobailon documents child contact_supervisor requests and parent subagent_supervisor
replies, including nested supervision. Tintinweb implements steering and result return.
At b72b414, its nested steering tool
targets only owned children; its completion outbox
returns results, not child-initiated dialogue. No built-in upstream or sibling messaging
was found in that source inspection.
See the coordination contract.
Why orchestration stays with the caller
The caller owns the larger plan and workspace preparation. This extension provides bounded assignments, batches and live coordination, not a workflow-script runtime or scheduling service. Scripts and recurring jobs need separate tooling and must respect the live-parent lifetime.
The native subagent interface uses the same executor; it does not interpret competitors'
workflow scripts or custom agent definitions.
See entry points and runtime ownership.
Documentation
- Delegation contract: tools, permissions, lifecycle and storage.
- Advanced policies: models, prewalk and unsupported capabilities.
- Verification: checks, terminal evidence and known limits.
- Parity inventory, provenance, third-party notices.
Local development
From a source checkout:
npm ci --ignore-scripts
npm run lint
npm run format:check
npm run typecheck
npm test
npm run exercise
npm pack --dry-run
npm run test:package
npm run check runs lint, formatting, typecheck, tests and the controlled SDK exercise.
npm run test:package packs and installs the tarball in a temporary directory, then checks
that Pi loads the production entrypoint and registers its tools. It needs registry access
for runtime dependencies, does not use model credentials and leaves your Pi settings unchanged.
Oxlint checks correctness rules; warnings fail the lint command. Control-character regexes are allowed in terminal rendering code and tests because they match ANSI escape sequences. Run npm run lint:fix for safe lint fixes and npm run format to apply Oxfmt formatting. Formatting skips the generated lockfile and the managed Pullfrog workflow.
Load the production entrypoint with pi -e /absolute/path/to/src/pi-extended-subagents.ts. Tests and examples use controlled providers without credentials or live inference.
Offline CLI walkthrough
Run this from the checkout in a disposable workspace. The controlled example deliberately starts a long background child; normal print-parent exit aborts it.
repo="$PWD"
root="$(mktemp -d)"
node_bin="$(command -v node)"
mkdir -p "$root/home" "$root/workspace"
(
cd "$root/workspace"
env -i PATH="$PATH" HOME="$root/home" PI_CODING_AGENT_DIR="$root/agent" PI_OFFLINE=1 \
"$node_bin" "$repo/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js" \
--offline --no-extensions --no-mcp --no-skills --no-prompt-templates \
--no-themes --no-context-files --tools read,grep,find,ls,delegate_task \
--session-dir "$root/sessions" -e "$repo/src/pi-extended-subagents.ts" \
-e "$repo/examples/controlled-parent.ts" -p 'delegate example' </dev/null
)
# Inspect only these new files before removing the temporary walkthrough root:
find "$root/sessions/delegation" -name '*.jsonl'
rm -rf -- "$root"
The child's JSONL records stopReason:aborted. Do not install the controlled example as a production provider. This checks the SDK lifecycle, not live-provider reliability.
For the UI exercise, create input.txt in a disposable cwd. Run the local CLI with --offline --no-extensions --no-mcp --no-skills --no-prompt-templates --no-context-files, -e /absolute/path/src/pi-extended-subagents.ts -e /absolute/path/examples/controlled-fleet.ts, and tools read,grep,find,ls,write,edit,bash,delegate_task,delegate_coordinate. Enter fleet example, then /subagent-hub. /fleet-theme dark and /fleet-theme light switch themes. fleet coordinate <JSON> calls the coordination tool. The example writes fleet-output.txt; it is not loaded by the package manifest.
Saved output
New files live under the parent session directory:
delegation/<parent-session-id>/<task-id>/
agent/ # scoped child runtime cache location, no copied credentials
transcripts/<new-id>.jsonl # actual SDK messages/tool results
result.txt # complete last-assistant text after drain (when referenced)
structured.json # accepted JSON value, if supplied (when referenced)
Completed generations keep their own immutable files. New generations use <task-id>-g<generation>/. Old extended-subagents-proof data is left untouched and is not loaded or migrated. SDK hosts must emit the public shutdown lifecycle before disposal; bare session.dispose() does not perform that cleanup.