pi-agent-squad
Interactive multi-agent orchestration, messaging, and live sessions for the Pi Coding Agent
Package details
Install pi-agent-squad from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-agent-squad- Package
pi-agent-squad- Version
0.8.4- Published
- Aug 30, 2026
- Downloads
- 331/mo · 331/wk
- Author
- geoffreychen777
- License
- unknown
- Types
- extension
- Size
- 193.1 KB
- Dependencies
- 1 dependency · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
subagents — generic multi-agent messaging extension
Status: fully implemented and verified end-to-end Design principle: generic messaging at the bottom layer, identity defined by prompts
Install
pi install npm:pi-agent-squad
Reload Pi after installation:
/reload
Core design
Bottom layer (generic, no identity concept):
- Two parties communicate:
main(the main agent) and any subagent. - Message primitives:
send_message/read_inbox/reply_message. - Routing:
to=main-> inject into the main session;to=<subagent>-> resolve the active-run registry and forward to the exact live process. - File channel + polling (no process pipes); runtime addresses are resolved by the main-process active-run registry.
Identity (prompt layer):
agents/*.md: defines each subagent's identity, duties, model, tools (e.g. planner/reviewer/actor).orchestrator.md: gives main adaptive authority to choose direct work or any useful combination of planner/actor/reviewer, while weighing each role's value and risks.- The bottom layer never cares who is who — it only delivers messages.
Messaging tools (shared by all agents)
| Tool | Purpose |
|---|---|
subagent({agent, task, as?, readonly?, async?, cwd?, timeoutSeconds?}) |
Start a direct run with a stable identity and optional unique runtime address |
send_message({to, content, wait, timeoutSeconds?}) |
Send a message to any target; wait=true blocks for and returns the reply |
read_inbox() |
Read messages others sent you |
reply_message({message_id, content}) |
Reply to a received message |
to is either main, a logical subagent name, or an exact runtime address such as actor#01ab23cd.
agent is the stable identity and as is an optional per-process address:
subagent(agent="actor", as="actor-frontend", async=true, task="...")
subagent(agent="actor", as="actor-backend", async=true, task="...")
send_message(to="actor-frontend", content="...")
If as is omitted, the plugin generates an address such as
actor#01ab23cd. Sending to the logical name actor selects the newest
active run; use the returned address whenever multiple actor runs exist.
Agent definitions may declare readonly: true. The built-in planner and
reviewer are read-only and may run concurrently. There is deliberately no
cwd or file write lock: the orchestrator owns the write-scope decomposition and
may start multiple actor runs in the same workspace when their briefs describe
independent implementation areas. Actors are instructed to stay within their
brief and report changed files; the main agent reviews and integrates any
overlap afterward. The subagent tool's readonly parameter is orchestration
metadata and does not sandbox filesystem access.
Features
- Delegation:
subagenttool (sync / backgroundasync:true); background results are injected into the main session when done. - Real-time two-way: subagent<->main and subagent<->subagent, via file channel + an active-run registry that covers both direct runs and resident RPC processes.
- Non-blocking: background tasks do not occupy the main session.
- Adaptive orchestration is opt-in:
/orchestrate onenables main's discretion to delegate based on speed, quality, context management, independent judgment, and parallel progress while weighing latency, over-analysis, misunderstanding, duplication, and integration risk. - Explicit control:
/orchestrate offdisables automatic delegation for the session; users can still explicitly request any subagent. - Bounded execution: one-shot and resident tasks have configurable timeouts (default 6 hours, maximum 3 days); omit
timeoutSecondsunless the user explicitly requested a time. Timed-out or crashed resident processes are discarded before the next task. - Reliable messaging:
send_message(wait=true)waits for and returns the target's actual reply;wait=falseremains fire-and-forget. - Deadlock prevention: synchronous wait cycles such as
main -> planner -> main, self-messages, andactor -> reviewer -> actorare detected and rejected immediately with a recovery hint. - Retryable routing: requests are marked delivered only after successful injection/routing; transient delivery failures are retried instead of being silently stranded until timeout.
- Compact transcript events: incoming messages and background completion/failure results use transparent, icon-led Markdown renderers instead of the default colored custom-message box or a synthetic user message.
- Session isolation: message channels use the real pi session id instead of a shared
ephemeraldirectory. - Running widget: while subagents are active, a compact widget above the editor shows their names, elapsed times, execution mode, and a shortened task/message summary; it disappears automatically when the last activity finishes.
- Session navigation: Shift+Up/Down selects a running subagent, Enter opens the exact RPC session behind that activity, and Esc returns to main while the subagent keeps running.
Running subagent widget
The TUI-only widget is installed above the editor while at least one subagent is running:
⠋ Subagents · 2 running · ⇧+↑/↓ select · Enter open
› actor [bg] · 12s · Implement the login flow and run tests…
└ reviewer [msg] · 4s · Review the current changes…
- No suffix: synchronous
subagenttask. [bg]: backgroundsubagent(async=true)task. The tool returns an address such asactor#01ab23cd; use it when several runs share the same logical identity.[msg]: routed task started throughsend_messageor subagent-to-subagent routing (it may target either a direct run or the resident fallback).- At most four activities are shown; additional concurrency is summarized as
… +N more, and the visible window follows the selected activity. - Task summaries are dimmed and capped at 40 terminal columns so they do not dominate the widget.
- The title includes dim keyboard hints. Before selection it shows
⇧+↑/↓ select · Enter open; with an active selection it changes to⇧+↑/↓ move · Enter open · Esc clear. Narrow terminals progressively shorten the hint and hide it when the title itself needs the space. - The elapsed time and spinner refresh once per second while work is active, avoiding hot-loop rerenders on very large sessions.
- Normal completion, failure, timeout, cancellation, crash, and session shutdown all remove the matching activity. The widget itself is removed when no activities remain.
- JSON/RPC/print modes do not install the widget.
Keyboard navigation
Shift+Down: select the first activity, then move down (wraps).Shift+Up: select the last activity, then move up (wraps).Enter: open the selected subagent session.Esc: clear widget selection.- Without a selected activity, normal Enter/arrow input remains owned by the main editor.
- Duplicate Shift+arrow reports arriving within 150ms are coalesced, preventing terminals that emit the same physical keypress more than once from skipping activities.
The session view is a focused overlay connected to the exact process/session that is running the selected task—not a new conversation with another copy of the same agent.
The overlay uses 96% of the terminal width and 85% of its height (with no outer margin). Its transcript viewport grows with terminal height instead of being fixed to a small number of rows.
╭──────────────────────── actor session · working… ────────────────────────╮
│ Initial delegated task │
│ │
│ ⠋ tool calling... │
│ └ ⠋ bash npm test (4.2s) │
│ │
│ Working on the implementation… │
│ │
│ › additional instruction │
│ Enter send · Esc main · Ctrl+O expand · PgUp/PgDn scroll │
╰────────────────────────────────────────────────────────────────────────────╯
- Enter sends a prompt when idle or a steering message while streaming.
- Esc closes only the overlay and returns focus to main; the subagent continues.
- Ctrl+X aborts the selected subagent's current operation.
- Ctrl+O expands/collapses every compact thinking/tool block.
- PageUp/PageDown scroll the transcript; End returns to live output.
- History is loaded on entry and early streaming events are buffered to avoid a startup race.
- Tool calls show their arguments, streaming output, and final
[done]/[error]status. Accumulated progress updates are converted to new output only, so previously shown lines are not duplicated. - User and assistant messages use pi's normal Markdown styling. Assistant fenced code blocks use compact-mode's bordered syntax-highlighted rendering.
- Thinking and consecutive tool calls are merged into isolated compact-mode blocks with the same rails, colors, token estimates, collapsed limits, expanded result previews, and visible-text boundaries as the main transcript.
- If Enter is pressed before the RPC process is ready, the requested session opens automatically as soon as its handle becomes available.
Main transcript message rendering
Subagent-originated events use transparent backgrounds with one column of left padding. Protocol metadata stays in the underlying model message but is hidden from the visible transcript:
← reviewer [msg] • reply requested
│ Please verify the cancellation behavior.
└ Include the timeout recovery case.
✓ actor [bg] • completed · 42s
│ Implemented and tested the requested changes.
└ All checks pass.
✗ planner [bg] • failed · 10s
└ Subagent timed out after 10 seconds.
←marks a message entering the main session.✓and✗mark background completion and failure.- A dim
│rail marks every body row and changes to└on the final row, making each subagent event's exact transcript range immediately visible. - Agent names are emphasized;
[msg]/[bg], status, and elapsed time remain compact. - Message bodies render as Markdown and reuse compact-mode's bordered, syntax-highlighted fenced-code style.
- Visible rows omit message IDs, routing paths, run IDs, and
reply_messageprotocol instructions. - Fire-and-forget messages do not ask the main agent to call
reply_message; their request files are removed immediately after successful injection. - Background results are delivered as custom messages with
triggerTurn: trueanddeliverAs: "steer", preserving the former synthetic-user-message behavior without inheritinguserMessageBg.
Architecture
Main agent (primary outcome owner; optional specialist workflow defined by prompt)
|
|-- subagent tool (sync/background spawns an RPC-backed run session)
| `-- widget selection / interactive overlay attach to that exact session
|-- active-run registry (logical names and temporary addresses -> exact process)
|-- prompt-owned parallel actor scopes (no cwd/file write mutex)
|-- RPC resident process pool (resident fallback / receives inter-subagent messages)
|-- message router (500ms poll)
| |-- to=main -> inject into main session -> reply_message replies
| |-- to=subagent -> registry -> exact direct/resident process -> reply written back
|
Subagents (separate processes, child mode):
|-- send_message / read_inbox / reply_message tools
|-- file channel: /tmp/pi-subagents-messages/<session>/<run>/<agent>/<idx>/{requests,replies}/
Layout
subagents/
|-- package.json
|-- index.ts # main (subagent tool + message router + background) / child (messaging tools)
|-- agents.ts # agent discovery (frontmatter parsing)
|-- agents/*.md # subagent identity definitions (planner / reviewer / actor)
|-- spawn.ts # RPC-backed interactive runs + legacy JSON one-shot compatibility
|-- pool.ts # RPC resident process pool (inter-subagent message routing)
|-- message.ts # generic messaging (file channel + send/reply/read + main-side router)
|-- session.ts # common interactive session-handle interface
|-- session-ui.ts # focused overlay for live transcript + interactive input
|-- orchestrator.md # main-agent adaptive delegation prompt (enabled with /orchestrate on)
`-- README.md
Usage
# optional CLI equivalent of forcing adaptive orchestration on
pi --append-system-prompt ~/.pi/agent/extensions/subagents/orchestrator.md
# or in-session
/orchestrate # enable adaptive orchestration
/orchestrate off # require explicit user requests before using subagents
/orchestrate status # check adaptive orchestration state
# in conversation
"Resolve this architecture decision, then implement it" # planner is used when a Decision Brief is needed
"Use subagent async=true, agent=actor, task=..." # explicit background delegation
"Use subagent agent=reviewer timeoutSeconds=120 ..." # override the default 6h task timeout (only when the user asked)
"Have reviewer review the recent changes" # main agent delegates to reviewer
Main is not required to follow a fixed planner → actor → reviewer chain. It may work directly, use only actor for high-throughput implementation, ask planner for a decision and implement it itself, or request reviewer only when an independent pass is worth its latency and false-positive risk.