@minzicat/pi-team 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile ADDED
@@ -0,0 +1,82 @@
1
+ # syntax=docker/dockerfile:1.7
2
+
3
+ # pi-team container image
4
+ # - Node 20 base
5
+ # - pi coding agent (global install)
6
+ # - tmux for session layout
7
+ # - ttyd for web-based tmux observation
8
+ # - pi-team (from this repo)
9
+ #
10
+ # Runtime:
11
+ # docker run --rm -it \
12
+ # -e ANTHROPIC_API_KEY=... \
13
+ # -e OPENAI_API_KEY=... \
14
+ # -e PITEAM_NAME=emotions \
15
+ # -e PITEAM_AGENTS='claude:anthropic/claude-sonnet-4-5,codex:openai-codex/gpt-5.4:xhigh' \
16
+ # -e PITEAM_TOPIC_FILE=/topics/debate.md \
17
+ # -v $(pwd)/topics:/topics:ro \
18
+ # -p 7681:7681 -p 7682:7682 \
19
+ # ghcr.io/minzique/pi-team:latest
20
+ #
21
+ # Then:
22
+ # open http://localhost:7681/ (watch tmux in the browser)
23
+ # curl -X POST http://localhost:7682/inject -d 'human message' (inject)
24
+
25
+ FROM node:20-slim AS build
26
+ WORKDIR /app
27
+
28
+ # Install build deps first for layer caching
29
+ COPY package.json pnpm-lock.yaml* ./
30
+ RUN corepack enable && corepack prepare pnpm@10.18.2 --activate \
31
+ && pnpm install --frozen-lockfile=false
32
+
33
+ COPY tsconfig.json ./
34
+ COPY src ./src
35
+ COPY bin ./bin
36
+ RUN pnpm build
37
+
38
+ # ---- runtime image ----
39
+ FROM node:20-slim AS runtime
40
+ WORKDIR /app
41
+
42
+ # System deps: tmux, ttyd (for web observation), netcat (socket inject), tini (PID 1)
43
+ RUN apt-get update \
44
+ && apt-get install -y --no-install-recommends \
45
+ tmux \
46
+ netcat-openbsd \
47
+ tini \
48
+ ca-certificates \
49
+ curl \
50
+ bash \
51
+ && curl -fsSL https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.$(uname -m) -o /usr/local/bin/ttyd \
52
+ && chmod +x /usr/local/bin/ttyd \
53
+ && rm -rf /var/lib/apt/lists/*
54
+
55
+ # Install pi globally
56
+ RUN npm install -g @mariozechner/pi-coding-agent@latest
57
+
58
+ # Copy app artifacts
59
+ COPY --from=build /app/node_modules ./node_modules
60
+ COPY --from=build /app/dist ./dist
61
+ COPY --from=build /app/bin ./bin
62
+ COPY --from=build /app/package.json ./package.json
63
+
64
+ # Symlink the CLI onto PATH
65
+ RUN ln -sf /app/bin/pi-team.js /usr/local/bin/pi-team \
66
+ && chmod +x /app/bin/pi-team.js
67
+
68
+ # Minimal tmux config for clean rendering
69
+ RUN printf 'set -g extended-keys on\nset -g extended-keys-format csi-u\nset -g mouse on\nset -g history-limit 50000\nset -g default-terminal "tmux-256color"\n' > /root/.tmux.conf
70
+
71
+ ENV PITEAM_HTTP_PORT=7682 \
72
+ PITEAM_TTYD_PORT=7681 \
73
+ PITEAM_SESSIONS_DIR=/data/sessions \
74
+ PATH=/usr/local/bin:/app/bin:$PATH
75
+
76
+ EXPOSE 7681 7682
77
+ VOLUME ["/data"]
78
+
79
+ COPY docker/entrypoint.sh /entrypoint.sh
80
+ RUN chmod +x /entrypoint.sh
81
+
82
+ ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"]
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 minzique
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # pi-team
2
+
3
+ Two or more LLMs in the same conversation. You can watch, and you can hop in.
4
+
5
+ Built on [pi](https://github.com/badlogic/pi-mono) RPC mode. Each agent is a real pi subprocess with its own model, tools, and session — the orchestrator just routes messages between them.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add -g @minzicat/pi-team
11
+ # or
12
+ npm i -g @minzicat/pi-team
13
+ ```
14
+
15
+ Requires: Node 20+, `pi` on PATH, `tmux` 3.2+.
16
+
17
+ ## Use
18
+
19
+ ```bash
20
+ pi-team start \
21
+ --name emotions \
22
+ --agent claude:anthropic/claude-sonnet-4-5 \
23
+ --agent codex:openai-codex/gpt-5.4:xhigh \
24
+ --topic-file debate.md \
25
+ --max-turns 10
26
+
27
+ tmux attach -t piteam-emotions
28
+ ```
29
+
30
+ Three 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`.
31
+
32
+ Agent spec: `name:provider/model[:thinking][@plan-id]`. The name is used as attribution and persona (`skeptic:anthropic/...`, `optimist:openai-codex/...`).
33
+
34
+ ## Usage tracking
35
+
36
+ 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:
37
+
38
+ ```bash
39
+ pi-team start --name x \
40
+ --agent claude:anthropic/claude-sonnet-4-5@anthropic-max-20x \
41
+ --agent codex:openai-codex/gpt-5.4:xhigh@openai-plus \
42
+ --topic-file debate.md
43
+ ```
44
+
45
+ After every turn you get a per-agent status line:
46
+
47
+ ```
48
+ claude │ sonnet-4-5 │ 5h: 12/900–4500 msg (1%) · wk: 0.4/800 h anthropic-max-20x
49
+ codex │ gpt-5.4 │ 5h: 5/33–168 msg (15%) openai-plus
50
+ ```
51
+
52
+ Plans: `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`.
53
+
54
+ ## Commands
55
+
56
+ | | |
57
+ |---|---|
58
+ | `pi-team start` | launch session in tmux (observable + injectable) |
59
+ | `pi-team run` | foreground, no tmux |
60
+ | `pi-team inject` | interactive stdin → running session |
61
+ | `pi-team stop` | kill session |
62
+ | `pi-team list` | active and archived sessions |
63
+
64
+ ## Inject from anywhere
65
+
66
+ ```bash
67
+ # interactive
68
+ pi-team inject --name emotions
69
+
70
+ # unix socket
71
+ echo "your message" | nc -U ~/.pi/team/sessions/emotions/inject.sock
72
+
73
+ # HTTP (when --http-port is set)
74
+ curl -X POST http://localhost:7682/inject -d "push back on that last point"
75
+ ```
76
+
77
+ All three land the same way: queued, delivered at the next turn boundary, visible to every agent.
78
+
79
+ ## Container
80
+
81
+ ```bash
82
+ docker compose up --build
83
+ ```
84
+
85
+ - `:7681` — ttyd web terminal on the tmux session
86
+ - `:7682` — HTTP API (`POST /inject`, `GET /state`, `GET /transcript`, `POST /stop`)
87
+ - `/data` — persistent session storage
88
+
89
+ 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).
90
+
91
+ ## How it works
92
+
93
+ ```
94
+ ┌─ Orchestra ─────────────────────────────┐
95
+ │ Transcript (jsonl, single source) │
96
+ │ │ │
97
+ │ ├─► Agent A (pi --mode rpc) │
98
+ │ ├─► Agent B (pi --mode rpc) │
99
+ │ └─► Agent N ... │
100
+ │ ▲ │
101
+ │ │ │
102
+ │ ├─ Unix socket ─┐ │
103
+ │ ├─ HTTP POST ───┼── human inject │
104
+ │ └─ tmux pane ───┘ │
105
+ └─────────────────────────────────────────┘
106
+ ```
107
+
108
+ 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.
109
+
110
+ 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.
111
+
112
+ ## License
113
+
114
+ MIT
package/bin/pi-team.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli.js";
package/dist/agent.js ADDED
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Agent: a thin wrapper around a `pi --mode rpc` subprocess.
3
+ *
4
+ * Each agent runs its own pi instance with its own model and session file.
5
+ * The orchestrator calls `prompt(text)` and awaits the assistant's full reply.
6
+ *
7
+ * Wire format: JSONL. Every line to stdin is a command, every line from stdout
8
+ * is either a response (to a command) or an event (streamed during execution).
9
+ * We wait for `agent_end` to know a prompt turn is fully complete, then fetch
10
+ * the last assistant text via `get_last_assistant_text`.
11
+ */
12
+ import { spawn } from "node:child_process";
13
+ import { EventEmitter } from "node:events";
14
+ import { mkdirSync } from "node:fs";
15
+ import { dirname } from "node:path";
16
+ /**
17
+ * Events emitted:
18
+ * - "delta" (agentName, text): streaming token from the assistant
19
+ * - "tool_start" (agentName, toolName, args)
20
+ * - "tool_end" (agentName, toolName, isError)
21
+ * - "error" (agentName, message)
22
+ * - "exit" (agentName, code)
23
+ */
24
+ export class Agent extends EventEmitter {
25
+ opts;
26
+ name;
27
+ spec;
28
+ proc;
29
+ buffer = "";
30
+ nextReqId = 1;
31
+ pending = new Map();
32
+ streaming = false;
33
+ currentTurnText = "";
34
+ turnResolver = null;
35
+ turnRejector = null;
36
+ constructor(opts) {
37
+ super();
38
+ this.opts = opts;
39
+ this.name = opts.spec.name;
40
+ this.spec = opts.spec;
41
+ }
42
+ async start() {
43
+ mkdirSync(dirname(this.opts.sessionPath), { recursive: true });
44
+ const args = [
45
+ "--mode",
46
+ "rpc",
47
+ "--provider",
48
+ this.spec.provider,
49
+ "--model",
50
+ this.spec.model,
51
+ "--session",
52
+ this.opts.sessionPath,
53
+ ];
54
+ if (this.spec.thinking) {
55
+ args.push("--thinking", this.spec.thinking);
56
+ }
57
+ if (this.opts.systemPromptFile) {
58
+ args.push("--append-system-prompt", this.opts.systemPromptFile);
59
+ }
60
+ this.proc = spawn("pi", args, {
61
+ stdio: ["pipe", "pipe", "pipe"],
62
+ env: { ...process.env, ...(this.opts.env ?? {}) },
63
+ });
64
+ this.proc.stdout.on("data", (chunk) => this.onStdout(chunk));
65
+ this.proc.stderr.on("data", (chunk) => {
66
+ const text = chunk.toString("utf8");
67
+ // pi can be chatty to stderr during startup; only emit as error if prefixed
68
+ if (/error|Error|ERROR/.test(text)) {
69
+ this.emit("stderr", this.name, text);
70
+ }
71
+ });
72
+ this.proc.on("exit", (code) => {
73
+ this.emit("exit", this.name, code);
74
+ for (const pending of this.pending.values()) {
75
+ pending.reject(new Error(`pi process for "${this.name}" exited with code ${code}`));
76
+ }
77
+ this.pending.clear();
78
+ if (this.turnRejector) {
79
+ this.turnRejector(new Error(`agent "${this.name}" exited mid-turn`));
80
+ }
81
+ });
82
+ // Wait for the process to be ready. We send a cheap get_state ping.
83
+ await this.waitForReady();
84
+ }
85
+ async waitForReady() {
86
+ // pi RPC mode is ready as soon as it reads stdin. Send get_state and wait
87
+ // up to 30s for a response. If it fails, start() rejects.
88
+ const deadline = Date.now() + 30_000;
89
+ while (Date.now() < deadline) {
90
+ try {
91
+ await this.sendCommand("get_state", {}, 5_000);
92
+ return;
93
+ }
94
+ catch {
95
+ await new Promise((r) => setTimeout(r, 500));
96
+ }
97
+ }
98
+ throw new Error(`agent "${this.name}" did not become ready within 30s`);
99
+ }
100
+ onStdout(chunk) {
101
+ this.buffer += chunk.toString("utf8");
102
+ while (true) {
103
+ const nl = this.buffer.indexOf("\n");
104
+ if (nl === -1)
105
+ break;
106
+ let line = this.buffer.slice(0, nl);
107
+ this.buffer = this.buffer.slice(nl + 1);
108
+ if (line.endsWith("\r"))
109
+ line = line.slice(0, -1);
110
+ if (!line.trim())
111
+ continue;
112
+ try {
113
+ const msg = JSON.parse(line);
114
+ this.handleRpcMessage(msg);
115
+ }
116
+ catch (e) {
117
+ // Not JSON — pi sometimes prints warnings to stdout. Ignore.
118
+ }
119
+ }
120
+ }
121
+ handleRpcMessage(msg) {
122
+ const type = msg.type;
123
+ // Response to a command
124
+ if (type === "response") {
125
+ const id = msg.id;
126
+ if (id && this.pending.has(id)) {
127
+ const p = this.pending.get(id);
128
+ this.pending.delete(id);
129
+ if (msg.success) {
130
+ p.resolve(msg.data);
131
+ }
132
+ else {
133
+ p.reject(new Error(msg.error ?? "rpc error"));
134
+ }
135
+ }
136
+ return;
137
+ }
138
+ // Streaming events — we care about text deltas and turn boundaries
139
+ if (type === "agent_start") {
140
+ this.streaming = true;
141
+ this.currentTurnText = "";
142
+ return;
143
+ }
144
+ if (type === "message_update") {
145
+ const evt = msg.assistantMessageEvent;
146
+ if (evt?.type === "text_delta" && evt.delta) {
147
+ this.currentTurnText += evt.delta;
148
+ this.emit("delta", this.name, evt.delta);
149
+ }
150
+ return;
151
+ }
152
+ if (type === "tool_execution_start") {
153
+ this.emit("tool_start", this.name, msg.toolName, msg.args);
154
+ return;
155
+ }
156
+ if (type === "tool_execution_end") {
157
+ this.emit("tool_end", this.name, msg.toolName, msg.isError);
158
+ return;
159
+ }
160
+ if (type === "agent_end") {
161
+ this.streaming = false;
162
+ const text = this.currentTurnText;
163
+ this.currentTurnText = "";
164
+ if (this.turnResolver) {
165
+ this.turnResolver(text);
166
+ this.turnResolver = null;
167
+ this.turnRejector = null;
168
+ }
169
+ return;
170
+ }
171
+ }
172
+ sendCommand(type, payload, timeoutMs = 120_000) {
173
+ const id = `req-${this.nextReqId++}`;
174
+ const cmd = { id, type, ...payload };
175
+ return new Promise((resolve, reject) => {
176
+ const timer = setTimeout(() => {
177
+ if (this.pending.has(id)) {
178
+ this.pending.delete(id);
179
+ reject(new Error(`rpc timeout on ${type}`));
180
+ }
181
+ }, timeoutMs);
182
+ this.pending.set(id, {
183
+ resolve: (data) => {
184
+ clearTimeout(timer);
185
+ resolve(data);
186
+ },
187
+ reject: (err) => {
188
+ clearTimeout(timer);
189
+ reject(err);
190
+ },
191
+ });
192
+ this.proc.stdin.write(`${JSON.stringify(cmd)}\n`);
193
+ });
194
+ }
195
+ /**
196
+ * Send a user message and await the full assistant response text.
197
+ * Returns the concatenated assistant text for this turn (excluding tools).
198
+ */
199
+ async prompt(message, timeoutMs = 20 * 60 * 1000) {
200
+ if (this.streaming) {
201
+ throw new Error(`agent "${this.name}" is already streaming`);
202
+ }
203
+ const textPromise = new Promise((resolve, reject) => {
204
+ this.turnResolver = resolve;
205
+ this.turnRejector = reject;
206
+ });
207
+ const timer = setTimeout(() => {
208
+ if (this.turnRejector) {
209
+ const rej = this.turnRejector;
210
+ this.turnResolver = null;
211
+ this.turnRejector = null;
212
+ rej(new Error(`turn timeout for "${this.name}"`));
213
+ }
214
+ }, timeoutMs);
215
+ try {
216
+ await this.sendCommand("prompt", { message });
217
+ const text = await textPromise;
218
+ return text;
219
+ }
220
+ finally {
221
+ clearTimeout(timer);
222
+ }
223
+ }
224
+ async abort() {
225
+ try {
226
+ await this.sendCommand("abort", {}, 5_000);
227
+ }
228
+ catch {
229
+ /* ignore */
230
+ }
231
+ }
232
+ async getSessionStats() {
233
+ return this.sendCommand("get_session_stats", {});
234
+ }
235
+ stop() {
236
+ try {
237
+ this.proc.stdin.end();
238
+ }
239
+ catch {
240
+ /* ignore */
241
+ }
242
+ setTimeout(() => {
243
+ try {
244
+ this.proc.kill("SIGTERM");
245
+ }
246
+ catch {
247
+ /* ignore */
248
+ }
249
+ }, 2000);
250
+ }
251
+ }
252
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}