@minzicat/pi-team
v0.1.0
Published
Multi-agent debate/collaboration harness built on pi RPC mode. Spawn agents with different models in one conversation, observe via tmux, inject as a human.
Maintainers
Readme
pi-team
Two or more LLMs in the same conversation. You can watch, and you can hop in.
Built on pi RPC mode. Each agent is a real pi subprocess with its own model, tools, and session — the orchestrator just routes messages between them.
Install
pnpm add -g @minzicat/pi-team
# or
npm i -g @minzicat/pi-teamRequires: Node 20+, pi on PATH, tmux 3.2+.
Use
pi-team start \
--name emotions \
--agent claude:anthropic/claude-sonnet-4-5 \
--agent codex:openai-codex/gpt-5.4:xhigh \
--topic-file debate.md \
--max-turns 10
tmux attach -t piteam-emotionsThree panes: stream, inject, log tail. Type in the inject pane to hop in — all agents see it at the next turn boundary. Detach with Ctrl+b d.
Agent spec: name:provider/model[:thinking][@plan-id]. The name is used as attribution and persona (skeptic:anthropic/..., optimist:openai-codex/...).
Usage tracking
Pi's per-token dollar display is wrong if you're on a subscription — the real constraint is 5-hour and weekly usage limits. Declare your plan per agent to get window-based tracking:
pi-team start --name x \
--agent claude:anthropic/claude-sonnet-4-5@anthropic-max-20x \
--agent codex:openai-codex/gpt-5.4:xhigh@openai-plus \
--topic-file debate.mdAfter every turn you get a per-agent status line:
claude │ sonnet-4-5 │ 5h: 12/900–4500 msg (1%) · wk: 0.4/800 h anthropic-max-20x
codex │ gpt-5.4 │ 5h: 5/33–168 msg (15%) openai-plusPlans: openai-plus, openai-pro, openai-business, anthropic-pro, anthropic-max-5x, anthropic-max-20x, api. Run pi-team plans to list. Without a plan, pi-team falls back to api mode and shows raw token counts + pay-per-token dollar cost. Fetch snapshots programmatically at GET /usage.
Commands
| | |
|---|---|
| pi-team start | launch session in tmux (observable + injectable) |
| pi-team run | foreground, no tmux |
| pi-team inject | interactive stdin → running session |
| pi-team stop | kill session |
| pi-team list | active and archived sessions |
Inject from anywhere
# interactive
pi-team inject --name emotions
# unix socket
echo "your message" | nc -U ~/.pi/team/sessions/emotions/inject.sock
# HTTP (when --http-port is set)
curl -X POST http://localhost:7682/inject -d "push back on that last point"All three land the same way: queued, delivered at the next turn boundary, visible to every agent.
Container
docker compose up --build:7681— ttyd web terminal on the tmux session:7682— HTTP API (POST /inject,GET /state,GET /transcript,POST /stop)/data— persistent session storage
Env: PITEAM_NAME, PITEAM_AGENTS (comma-separated specs), PITEAM_TOPIC_FILE or PITEAM_TOPIC, PITEAM_MAX_TURNS, PITEAM_TTYD_CREDS (basic auth), PITEAM_HTTP_TOKEN (bearer), PITEAM_HTTP_HOST (defaults to 127.0.0.1; set to 0.0.0.0 only when token is also set).
How it works
┌─ Orchestra ─────────────────────────────┐
│ Transcript (jsonl, single source) │
│ │ │
│ ├─► Agent A (pi --mode rpc) │
│ ├─► Agent B (pi --mode rpc) │
│ └─► Agent N ... │
│ ▲ │
│ │ │
│ ├─ Unix socket ─┐ │
│ ├─ HTTP POST ───┼── human inject │
│ └─ tmux pane ───┘ │
└─────────────────────────────────────────┘Round-robin by default. Each agent's pi session holds its own side; the orchestrator renders everything-since-last-turn with attribution ([claude]: ..., [human]: ...) as the next prompt. Injections drain at turn boundaries.
Every agent gets pi's full stack: tools, skills, extensions, thinking levels. The orchestrator is ~400 lines of TypeScript because pi does the hard work.
License
MIT
