pi-agentteam
Multi-agent team orchestration for pi — leader-coordinator pattern with researcher, planner, and implementer teammates in tmux panes
Package details
Install pi-agentteam from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-agentteam- Package
pi-agentteam- Version
0.6.8- Published
- Jun 4, 2026
- Downloads
- 559/mo · 308/wk
- Author
- linys77
- License
- MIT
- Types
- extension
- Size
- 646.8 KB
- Dependencies
- 0 dependencies · 4 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
🤝 pi-agentteam
Multi-agent team orchestration for pi
Coordinate a leader with specialized teammates — researcher, planner, and implementer — each running in a visible tmux pane, collaborating through shared tasks and typed messages.
✨ Highlights
| Feature | ||
|---|---|---|
| 🖥️ | tmux-native teamwork | Each teammate is a real pi session in its own pane — watch them work in real time |
| 📋 | Leader-gated task board | Leader-owned task facts with worker report_done/report_blocked reports and review |
| 💬 | Typed messaging | assignment · question · inform; task reports handle done/blocked outcomes |
| 🎯 | Role-based tool guard | Researcher/Planner (read-only) → Implementer (full tools) — least privilege by default |
| 📡 | Event-driven delivery | Teammates are notified for actionable messages when tasks are unblocked; mailbox reads stay explicit |
| 📊 | Unified /team console |
Browse state, recover old teams, remove stale teammates, and cleanup without memorizing extra commands |
| 🔗 | Peer context handoff | Workers communicate through mailboxes with compact TaskMessageRef task audit refs/diagnostics; leader reviews attention signals and explicitly starts downstream work |
| 🧹 | Zero footprint | One folder, file-based state, no database — delete and it's gone |
📦 Install
pi install npm:pi-agentteam
Requirements: pi ≥ 0.60 · tmux. The leader pi session must run inside tmux.
pi install npm:pi-agentteam installs the npm latest version. GitHub-only vNext notes in this README can appear before an npm publish is explicitly performed, so do not assume unreleased GitHub changes are available from npm until a package release is published. If v0.6.8 is promoted to npm, it may sync npm users from pi-agentteam@0.6.3 across several GitHub-only releases; see Package Surface Tiers for the release-notes-only compatibility posture.
🚀 Quick Start
You (leader):
Create a team and ask the leader to handle the routing work.
> Create an agentteam for this project.
> Spawn one researcher to analyze the build pipeline.
> When the research task is done, ask a planner for an optimization plan.
The leader should create/assign shared tasks, choose the matching teammate
from the roster, send short task-id based assignments, then receive and
synthesize task reports.
Equivalent low-level tool flow when you need it:
> agentteam_create({ team_name: "my-project", description: "Optimize the build pipeline" })
> agentteam_spawn({ name: "research", role: "researcher" })
> agentteam_task({ action: "create", title: "Analyze build pipeline",
description: "Report bottlenecks with evidence", owner: "research" })
> agentteam_send({ taskId: "T001", message: "Analyze the build pipeline and report bottlenecks",
type: "assignment" })
> agentteam_receive()
Because T001 has owner research, the assignment can omit to. Explicit to is still available when you need to override task-owner routing.
Or open the unified local console:
/team ← local console for status, recovery, and cleanup
🧭 Recommended Workflows
Use agentteam when work benefits from visible role separation, not for every small edit.
| Want | Suggested flow |
|---|---|
| Understand unfamiliar code | Spawn researcher → report_done creates a durable TaskReport with files, facts, risks → leader receives/reviews → leader synthesizes |
| Plan a risky change | Leader assigns researcher fact-finding first → researcher reports to leader → leader receives the inbox report and reviews task history/reports → leader creates/assigns a separate planner planning task |
| Execute an approved plan | Assign one focused task to implementer → run checks → worker report_done with files changed → leader close when accepted |
| Keep a handoff from stalling | Ask the leader to route a task-id based inform or assignment to the right teammate |
| Resolve uncertainty | Worker sends question or an agentteam_task blocker report → leader agentteam_receive() → decide next step |
| Check team health | Open /team for status, mailbox attention, stale panes, recovery, or cleanup |
Recommended loop:
clarify → create task with owner when clear → send task-id assignment → teammate works visibly → receive full inbox text → inspect task history/reports when needed → synthesize
Use natural language first:
Let a researcher inspect this area. Create the task, choose the matching teammate, send the assignment, then summarize the result when it reports back.
The leader should not make you memorize teammate names when the intent is clear. If one teammate matches the requested role, reuse it. If several could match, ask a short clarification. If none exists, ask before spawning. Once a task has an owner, agentteam_send can omit to and route through taskId. Never broadcast by default.
Keep the leader as coordinator: teammates produce facts, plans, edits, and reports; the leader decides what to adopt and how to answer the user.
🎮 /team Console
/team is the only slash command exposed by agentteam. It opens a local console instead of a pile of maintenance commands.
Attached to a team:
/team
→ two-box master-detail console
→ tabs: Cockpit · Tasks · Mailbox · Members
→ Enter opens selected-item context actions
→ a opens team maintenance actions
The Cockpit tab is an interactive attention queue for active tasks and unread mailbox items, not a passive status box. The Tasks tab surfaces compact v0.6.2 history: latest TaskReport id/type/author/summary, latest TaskEvent/TaskMessageRef activity, and counts for reports/events/messageRefs. It does not hydrate full report text or task-bound message bodies; use agentteam_task action=report reportId=<id> or agentteam_receive for explicit full-text reads.
Not attached to a team:
/team
→ global two-box master-detail console
→ tabs: Teams · Panes
→ Enter opens selected-team/pane context actions
→ a opens global maintenance actions
| Key | Action |
|---|---|
Tab / Shift+Tab |
Cycle tabs |
1..4 |
Attached tabs: Cockpit, Tasks, Mailbox, Members |
1..2 |
Global tabs: Teams, Panes |
↑ ↓ |
Move list selection, or scroll details when detail focus is active |
→ / e |
Move scroll focus from list to detail |
← / Esc |
Return detail scroll focus to list; then collapse details or close |
Enter |
Open selected-item context actions / choose action |
a |
Open team/global maintenance actions |
q |
Close |
The panel intentionally does not focus tmux panes, perform task/message CRUD, or mark mailbox items delivered/read. Use tmux for pane navigation, and use tools for collaboration work. /team is for local runtime visibility, recovery, and cleanup. Expanded Details use an internal reader so long descriptions and compact history summaries remain readable without flooding terminal scrollback.
Action menus keep selected-item actions separate from maintenance and destructive operations. Sections render as SELECTED ITEM, MAINTENANCE, and DANGER ZONE; the footer shows the selected action description, and destructive confirmation defaults to No, Cancel operation.
Available action-menu operations include:
- selected-item context actions such as inspecting details, recovering a selected team, deleting a selected team, or removing a selected teammate;
- team/global maintenance actions such as refresh/reconcile, compact leader mailbox projection sync without marking messages read or delivered, deleting the current team, and cleanup of all agentteam state/stale panes while keeping the current pane alive and clearing its agentteam label.
💬 Messages & Wake Behavior
Public collaboration vocabulary is intentionally small: task status is open | blocked | done, worker health is offline | idle | busy | error, agentteam_send types are assignment | question | inform, and task reports are report_done | report_blocked.
Messages carry an implicit wake hint that controls whether AgentTeam creates a bridge delivery/projection request. Mailbox read state is simple: messages remain unread until agentteam_receive({ markRead: true }), which is the explicit read boundary and the only normal full-text mailbox entry point. Single-message receive output stays clear/full; when multiple unread messages are returned, the human-facing receive text folds them by task/thread with compact ids/types/from/summary previews while details.messages remains the full returned mailbox payload with full text unchanged. tmux is the visible pane/container layer only; AgentTeam has a single bridge-only delivery policy and uses durable Outbox effects, durable bridge worker requests, compact durable leader mailbox projection, and bounded leader attention wakes. deliveryMode is not a vNext config key; remove it from config or roll back by pinning npm pi-agentteam@0.5.0 instead of selecting legacy terminal transport. Worker-to-leader signals use compact native/idempotent projection plus compact bounded leader attention for question to leader and owner report_done/report_blocked. Projection and attention are reminders/wake signals with message id, task, type, summary, and a receive instruction; they do not carry the full message body. inform never requests leader attention. If bridge/projection is unavailable, work remains visible as public busy/error worker health plus diagnostics; AgentTeam does not silently fall back to terminal key injection. Native submit/projection/attention never marks mailbox readAt or deliveredAt; explicit receive owns those transitions.
agentteam_send type |
Purpose | Wake | Typical Flow |
|---|---|---|---|
assignment |
Leader → worker task assignment | hard | Leader delegates unblocked actionable work |
question |
Clarification request | soft | Anyone asks a question |
inform |
Informational update | none | Context sharing; does not wake a worker by default |
report_doneandreport_blockedare task-report outcomes, notagentteam_sendtypes. Non-leaders may useagentteam_task action=report_doneoragentteam_task action=report_blockedonly for tasks they own; non-owners should useinformorquestionfor context.Bounded leader attention means one compact native leader wake that should
agentteam_receive, review, decide, and stop. It must not auto-spawn, auto-create downstream tasks, broadcast, or start worker-to-worker chains.Task-bound sends keep the recipient mailbox as the communication source of truth. The task stores only compact
TaskMessageRefaudit/index rows (taskId,mailboxMessageId, sender/recipient/type/thread/summary metadata) and does not copy the message body into task history. Legacytask.notesare migrated into TaskReport/TaskEvent/TaskMessageRef history and removed from active state; new task-bound sends produce zero hidden communication-ref notes./teamnow shows compact TaskReport/TaskEvent/TaskMessageRef summaries and counts instead of latest-note/folded-ref primary UI. Refs do not count as ordinary/latest notes and do not bump task recency.Peer
informhandoffs are mailbox communication plus compactTaskMessageReftask audit refs/diagnostic event refs only; diagnostic refs are compact, do not copy the full body, and do not create ordinary panel/prompt context. They do not create worker delivery requests or authorize downstream work. For researcher→planner chains, the leader should review the researcher report and then create/assign a separate planner task or direct question.Task-based routing: when
taskIdis provided andtois omitted, leader messages route to the task owner; messages from the task owner route back toteam-lead. Unowned, missing, or ambiguous tasks return an error instead of falling back to broadcast.
✅ Leader-Gated Task Governance
Task facts are leader-gated. By default, only team-lead factually changes task.status, task.owner, task.blockedBy, title, or description. Planner is advisory by default, not a second leader: it can report findings and recommendations, while the leader decides what to create, assign, block/unblock, or close.
Non-leader task actions are report/history-oriented:
agentteam_task action=report_donefrom the task owner creates a durable TaskReport, creates a compact leader mailbox notification, requests compact leader projection plus bounded leader attention, and leaves the task open until leader review. The leader closes accepted work withaction=close.agentteam_task action=report_blockedfrom the task owner creates a durable blocked TaskReport, creates a high-priority compact leader mailbox notification, requests compact leader projection plus bounded leader attention, and does not factually mutatestatusorblockedBy. Unread blocked reports appear as panel attention; after the report mailbox item is read, long-lived panel attention comes from factual blocked tasks (status/blockedBy) instead. The leader blocks/unblocks withaction=block blockedBy=[...]oraction=unblock.agentteam_task action=progressrecords compact local TaskEvent progress/history only. It does not append legacy task-note rows, notifyteam-lead, create mailbox/projection/attention side effects, or create linked communication refs. If someone needs to know, useagentteam_send; usereport_done/report_blockedfor durable report artifacts/action requests.blockedByis a hard actionability gate: blocked tasks cannot receive actionableassignmentsends or worker delivery. Non-actionagentteam_sendcommunication such asinformandquestionremains allowed so the team can converge; done/blocked reports useagentteam_task.- In worker delivery prompts, same-task assigned task facts and task-bound mailbox messages are merged into one task-centric block so the instruction/question appears once; unscoped or different-task messages still appear separately in Messages.
Rollback/migration baseline remains npm pi-agentteam@0.5.0; do not treat local WIP versions as a stable runtime fallback.
👥 Built-in Roles
agentteam intentionally keeps a small fixed role set for predictable permissions and prompts.
🔬 researcher — read grep find ls + collab
Fact finding: relevant files, constraints, risks, and evidence-backed findings
📋 planner — read grep find ls + collab
Advisory planning for complex work: options, risks, dependencies, and acceptance criteria
🛠 implementer — read grep find ls bash edit write + collab
Focused code changes, checks, and validation evidence
collab =
agentteam_send+agentteam_receive+agentteam_task
⚙️ Model Configuration
npm/pi install does not create runtime config files. To assign models per subagent role, run:
/team config init
/team config show
/team config validate
/team config init creates ${PI_AGENTTEAM_HOME || ~/.pi/agent/agentteam}/config.json from the bundled config.example.json and refuses to overwrite an existing file. You can also copy config.example.json manually:
{
"agentModels": {
"planner": null,
"researcher": null,
"implementer": null
}
}
Set a role value to a pi model selector, preferably the fully qualified selector you use in pi (for example openai/gpt-5.3-codex or your configured alias). null, empty string, or a missing key means use the current default model. Configuration is role-level only (planner, researcher, implementer); per-member overrides and live model switching are intentionally not supported. Spawn output and /team member details show the effective launch model (model: <selector> or model: default). Changes apply only to future teammate spawns/respawns; existing workers keep the model they were launched with. The leader always uses your current session model.
Runtime state is stored under ~/.pi/agent/agentteam/ (teams/<team>/team.json, teams/<team>/inboxes/, teams/<team>/outbox.json, teams/<team>/runtime.json, sessions/, and worker-sessions/). config.json lives in the same directory. Set PI_AGENTTEAM_HOME for testing or temporary sandboxes; /team config show displays the effective path and role models.
🛠 Tools & Commands
Tools
| Tool | Description |
|---|---|
agentteam_create |
Create a new team |
agentteam_spawn |
Spawn a teammate (omit task for idle) |
agentteam_send |
Send typed communication to a specific teammate, an owned task, or explicit broadcast |
agentteam_receive |
Pull unread mailbox messages; this is the full-text read boundary; multi-message human output is compactly grouped while details keep full text |
agentteam_task |
Leader-gated shared task facts plus TaskReport/TaskEvent/TaskMessageRef history queries; owner-only report_done/report_blocked create durable report action requests |
Command
| Command | Description |
|---|---|
/team |
Unified local console for status, recovery, teammate removal, team deletion, and cleanup |
🏗 Architecture
Current boundary layout: api/app/adapters/core/runtime/state are explicit; removed root facades are not part of the package surface.
index.ts ← Extension entry point
├── api/ ← Pi-facing registration entrypoints for tools/commands composition
├── tools/ ← Thin tool registrations plus team/message/task/worker services, routing, and policy helpers
├── commands/ ← /team console command and runtime action handlers
├── hooks/ ← Thin hook registrations plus lifecycle/context services and tool guard
├── teamPanel/ ← Interactive console (layout, view model, input, actions)
├── types.ts ← Public vocabulary/types (Task, Message, Worker)
├── internalTypes.ts ← Internal persisted/runtime store shapes (not public API)
├── config.ts / agents.ts / session.ts / protocol.ts / policy.ts / renderers.ts
├── state/ ← Focused file-based stores (team, inbox, sessions, runtime, outbox, quarantine)
├── adapters/ ← Explicit runtime/tmux/bridge adapters used by hooks, tools, commands, and panel
│ ├── runtime/ ← Session attachment, team lookup, storage readiness, naming/spawn rules, runtime service
│ ├── bridge/ ← Bridge delivery/projection/lifecycle adapter surface
│ └── tmux/ ← Patchable tmux visibility adapter and team pane reconcile/cleanup
├── runtime/ ← Focused bridge/projection/outbox runtime internals; no top-level runtime facade
├── protocol.ts ← Message type defaults & wake hints
├── orchestration.ts ← Leader digest (coordination counters)
├── policy.ts ← Leader delegation policy
├── agents.ts ← Role discovery & agent loading
├── tmux/ ← Low-level tmux client, pane/window/process/label helpers
├── messageLifecycle.ts ← Mailbox delivered/read helpers
└── agents/ ← Bundled role prompts (markdown)
├── researcher.md
├── planner.md
└── implementer.md
Package Surface Tiers
Packed runtime files are not all stable public API. The package intentionally has no restrictive exports map at this surface tier, so existing deep imports are not newly blocked yet, but only the surfaces below should be treated as stable promises.
- Public/stable promises
- Pi extension default entrypoint is
package.json#pi.extensionspointing at./index.ts;index.tsis the extension facade. - Public collaboration vocabulary and simple public shapes live in
types.ts. - User-facing Pi tool/command schemas and behavior are the primary product API.
deliveryPolicy.tsbridge-only helpers document the supported delivery policy surface.
- Pi extension default entrypoint is
- Compatibility/composition surfaces
api/tools.tsandapi/commands.tsare extension composition helpers for wiring AgentTeam into a Pi extension; they are kept stable, but they are not a broad end-user API.adapters/bridge/index.tsis a bridge runtime adapter compatibility surface for worker bridge composition, not a broad user API.
- Internal/packed-for-runtime paths
app/,runtime/,state/,teamPanel/,commands/,hooks/,tmux/, mosttools/,adapters/runtime/, andadapters/tmux/are packed so the extension can run, not because every subpath is stable API.package.json#filesis a runtime packaging allow-list, not a promise that every packed subpath is stable API.docs/andscripts/remain local-only and excluded from the package by default.
v0.6.8 npm sync compatibility note
If v0.6.8 is promoted to npm, npm latest may jump from pi-agentteam@0.6.3 to v0.6.8 after several GitHub-only releases. The package comparison against npm 0.6.3 is additive: 8 internal runtime/source files added and 0 packed files removed.
No root compatibility facades/wrappers were added: commands.ts, tools.ts, state.ts, tmux.ts, runtime*.ts, and runtimeWake.ts were not packed in npm 0.6.3 and remain absent. Adding those paths would expand the public-looking surface rather than restore npm 0.6.3 compatibility.
Stable/public entries remain present: index.ts, types.ts, deliveryPolicy.ts, api/tools.ts, api/commands.ts, and adapters/bridge/index.ts. Packed implementation dirs are included so the TypeScript Pi extension can run, but they are not all stable subpath APIs. Unsupported deep imports into internals may need adjustment.
Release notes are the compatibility path for v0.6.8. Targeted shims/wrappers are considered only with concrete external-user evidence for a specific broken import path that existed in npm 0.6.3; absent that evidence, AgentTeam will not add broad compatibility wrappers.
Public behavior remains behavior-preserving: agentteam_receive is the full-text/read boundary; /team stays compact/read-mostly and does not mark mailbox read/delivered; delivery stays bridge-only with no terminal-key fallback; AgentTeam does not add autopilot, hidden workers, worker-spawns-worker, automatic downstream task creation, or other downstream automation.
Design Principles
- Removable — delete the folder and reload; no core modifications
- Observable — each teammate is a visible tmux pane you can watch
- Minimal prompt burden — role behavior in markdown, not inflated system prompts
- File-based state — JSON + lock files + atomic writes; no database
- Event-driven — teammates wake on actionable messages, not polling
✅ Checks & Release Readiness
npm test # unit/package smoke suites
npm run typecheck # tsc --noEmit
npm run check:boundaries # import/public-surface boundary guard
npm run check # test + typecheck + git diff --check + boundaries
npm run release:check # npm run check + npm pack --dry-run --ignore-scripts
npm run test:e2e # optional manual tmux smoke; requires real tmux/pi runtime
release:check is safe for local CI: it does not publish, install, tag, bump versions, or edit user settings. It intentionally does not run test:e2e because the e2e smoke requires a real tmux/pi environment and is best run manually in a clean PI_AGENTTEAM_HOME sandbox.
The package surface is intentionally explicit: package.json#files lists required top-level files plus api/, app/, adapters/, commands/, hooks/, core/, runtime/, state/, teamPanel/, tmux/, tools/, and bundled agents/. It does not use broad *.ts, and removed root facades/wrappers are explicitly excluded/guarded.
Current automated/source-level status: FULL PASS only after npm test, npm run typecheck, git diff --check, npm run check:boundaries, npm run check, and npm run release:check pass in the working tree. This is local validation, not publishing.
| Suite | Covers |
|---|---|
| Tools + state flow | create → spawn → send → receive → task lifecycle |
| Command | /team unified console |
| Protocol + orchestration | Wake defaults, leader digest injection |
| Panel rendering | Visual output across terminal widths |
| Delivery + permission guards | Role-based access control |
| Service unit helpers | Pure worker/message/task/context helper behavior |
🧪 Manual smoke checklist
These checks are release-readiness notes for the current working tree; they do not imply a package has been published.
- Current vNext layout sanity
- Fresh state should use
teams/<team>/team.json,teams/<team>/inboxes/<member>.json,teams/<team>/outbox.json,teams/<team>/runtime.json,sessions/session-<sha>.json, andworker-sessions/. - Active old layout files such as
state.json,mailboxes/,outbox-state.json,bridge-state.json,delivery-state.json, andleader-projection-state.jsonshould quarantine rather than load.
- Fresh state should use
- Package surface sanity
npm run release:checkshould finish withnpm pack --dry-run --ignore-scriptsonly; do not runnpm publish, do not bumpversion, do not tag/commit, and do not edit~/.pi/agent/settings.json.docs/remains local design notes andscripts/remains local development helpers; neither directory is included in the npm packagefileslist by default.
- Stable fallback remains documented
- Compare or roll back with npm
pi-agentteam@0.5.0when needed; do not treat unpublished local vNext work as a stable fallback.
- Compare or roll back with npm
- Internal delivery diagnostics sanity
- Evidence: unit coverage in
tests/suites/service-units.cjsfor expired/stale request handling, recovery, and no-resend behavior. These are runtime diagnostics, not public task/worker states.
- Evidence: unit coverage in
- PushMailbox failure evidence
- Evidence: unit coverage in
tests/suites/tools-state.cjsfor leader mailbox push failure warnings/details on non-leaderreport_doneandreport_blocked.
- Evidence: unit coverage in
- Bridge-only delivery remains in effect
- Confirm no tmux terminal-key fallback is used; mailbox read still happens only through
agentteam_receive.
- Confirm no tmux terminal-key fallback is used; mailbox read still happens only through
⚠️ Limitations
- Workers are separate visible
pisessions in tmux panes, but tmux is only the visible container/labels/reconcile/cleanup/debug layer. AgentTeam uses one bridge-only delivery policy: bridge requests/projection only, with no automatic fallback to terminal key injection. - Durable Outbox plus runtime adapter diagnostics are production delivery diagnostics (
outbox.json,outbox-diagnostics.json, andruntime.jsonsections for bridge lease, delivery request, leader projection, and leader attention state). Internal request/projection/attention lifecycles such as pending, claimed, submitted, started, completed, projected, or failed may appear only in diagnostics/details; inbox read state remains owned byagentteam_receive. - In diagnostics, the durable bounded-leader-attention Outbox effect kind is
leader_attention_requested. Task-bound send indexing usestask_message_ref_append_requested. Legacy pendingtask_note_append_requestedeffects are migrated/cleaned before validation when possible; otherwise unsupported legacy state is quarantined. Legacy active persisted outbox effects usingleader_triage_requestedhave no compatibility path; they quarantine as unsupported legacy state instead of being normalized or executed. - Rollback/migration: pin or reinstall a rollback package version (for example npm
pi-agentteam@0.5.0) and respawn workers. There is no automatic in-process switch from bridge-only delivery to terminal transport; bridge unavailable appears as publicbusy/errorworker health with diagnostics. For manual smoke, use a cleanPI_AGENTTEAM_HOMEand respawn old workers so bridge leases exist. agentteam_task action=createcan includeownerwhen the responsible teammate is already clear; this assigns shared state only and does not send/wake by itselfagentteam_task action=progressrecords compact local TaskEvent progress/history only; it is not a leader notification channel and active team state has no legacy task-note rowsagentteam_sendcan omittoonly whentaskIdsafely routes through an owned task; it never falls back to implicit broadcast- Passing
tasktoagentteam_spawnstarts work immediately; omitting it creates an idle teammate for latersend/taskfollow-up - State is local to one machine (no remote/distributed support)
- Requires tmux; Windows terminals not supported (WSL works)
📄 License
MIT © 2026 linys77