pi-messenger 0.9.0 → 0.10.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/CHANGELOG.md +12 -0
- package/README.md +91 -346
- package/crew/agents.ts +38 -3
- package/install.mjs +120 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0] - 2026-02-05
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Crew spawner applies agent definitions** — Spawned crew workers now receive the agent's system prompt (`--append-system-prompt`), tool restrictions (`--tools`), and model override from their `.md` definitions. Previously a phantom `--agent` flag was passed that pi-core silently ignored, the agent name leaked into the prompt as noise, and the system prompts (worker's 6-phase protocol, reviewer's rubric, planner's exploration workflow) were never delivered. Tool restrictions also take effect: reviewers and interview generators are now limited to `read,bash` instead of getting all default builtins including `write` and `edit`.
|
|
7
|
+
- **Crew spawner session cleanup** — Spawned workers now pass `--no-session` to avoid writing ephemeral session files to disk.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`--crew-install` / `--crew-uninstall` CLI flags** — `npx pi-messenger --crew-install` copies crew agent `.md` files and the `pi-messenger-crew` skill to user directories. `--crew-uninstall` removes them. Reads from the npm package (not the installed extension) to avoid version skew.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **README rewrite** — Installation section now shows real CLI commands instead of tool-call syntax. "How It Works" section explains pi extension API hooks (`pi.on()`, `pi.sendMessage()`, `{ block: true }`, `ctx.ui.custom()`) instead of listing directory trees.
|
|
14
|
+
|
|
3
15
|
## [0.9.0] - 2026-02-05
|
|
4
16
|
|
|
5
17
|
### Added
|
package/README.md
CHANGED
|
@@ -6,106 +6,76 @@
|
|
|
6
6
|
|
|
7
7
|
**What if multiple agents in different terminals sharing a folder could talk to each other like they're in a chat room?** Join, see who's online and what they're doing. Claim tasks, reserve files, send messages. Built on [Pi's](https://github.com/badlogic/pi-mono) extension system. No daemon, no server, just files.
|
|
8
8
|
|
|
9
|
+
[](https://www.npmjs.com/package/pi-messenger)
|
|
9
10
|
[](LICENSE)
|
|
10
11
|
[]()
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Pi-messenger adds a `pi_messenger` tool that **agents use** for coordination. You don't type these commands - you ask your agent to do things, and it calls `pi_messenger` behind the scenes.
|
|
15
|
-
|
|
16
|
-
## Quick Start
|
|
17
|
-
|
|
18
|
-
### Multi-Agent Coordination
|
|
19
|
-
|
|
20
|
-
Once joined (manually or via auto-join config), agents can coordinate:
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
pi_messenger({ action: "reserve", paths: ["src/auth/"], reason: "Refactoring" })
|
|
24
|
-
// → Reserved src/auth/ - other agents will be blocked
|
|
25
|
-
|
|
26
|
-
// ... does the work ...
|
|
13
|
+
## Installation
|
|
27
14
|
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
```bash
|
|
16
|
+
pi install npm:pi-messenger
|
|
30
17
|
```
|
|
31
18
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
### Crew Task Orchestration
|
|
35
|
-
|
|
36
|
-
Ask your agent to plan and execute from a PRD:
|
|
37
|
-
|
|
38
|
-
```typescript
|
|
39
|
-
pi_messenger({ action: "plan" })
|
|
40
|
-
// → Planner analyzes codebase, creates tasks
|
|
19
|
+
Crew agents and the `pi-messenger-crew` skill are auto-installed on first use of `plan`, `work`, or `review`. To install them ahead of time:
|
|
41
20
|
|
|
42
|
-
|
|
43
|
-
|
|
21
|
+
```bash
|
|
22
|
+
npx pi-messenger --crew-install
|
|
44
23
|
```
|
|
45
24
|
|
|
46
|
-
|
|
25
|
+
This copies `crew/agents/*.md` to `~/.pi/agent/agents/` and `skills/pi-messenger-crew/` to `~/.pi/agent/skills/`.
|
|
47
26
|
|
|
48
|
-
|
|
27
|
+
To remove the extension:
|
|
49
28
|
|
|
50
29
|
```bash
|
|
51
|
-
|
|
30
|
+
npx pi-messenger --remove
|
|
52
31
|
```
|
|
53
32
|
|
|
54
|
-
To remove:
|
|
33
|
+
To also remove crew agents and skill:
|
|
55
34
|
|
|
56
35
|
```bash
|
|
57
|
-
npx pi-messenger --
|
|
36
|
+
npx pi-messenger --crew-uninstall
|
|
58
37
|
```
|
|
59
38
|
|
|
60
|
-
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
Once joined (manually or via `autoRegister` config), agents can coordinate:
|
|
61
42
|
|
|
43
|
+
```typescript
|
|
44
|
+
pi_messenger({ action: "join" })
|
|
45
|
+
pi_messenger({ action: "reserve", paths: ["src/auth/"], reason: "Refactoring" })
|
|
46
|
+
pi_messenger({ action: "send", to: "GoldFalcon", message: "auth is done" })
|
|
47
|
+
pi_messenger({ action: "release" })
|
|
62
48
|
```
|
|
63
|
-
|
|
49
|
+
|
|
50
|
+
For multi-agent task orchestration from a PRD:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
pi_messenger({ action: "plan" }) // Planner analyzes codebase, creates tasks
|
|
54
|
+
pi_messenger({ action: "work", autonomous: true }) // Workers execute tasks in waves until done
|
|
55
|
+
pi_messenger({ action: "review", target: "task-1" }) // Reviewer checks implementation
|
|
64
56
|
```
|
|
65
57
|
|
|
66
58
|
## Features
|
|
67
59
|
|
|
68
|
-
**Living Presence** -
|
|
60
|
+
**Living Presence** - Status indicators (active, idle, away, stuck), tool call counts, token usage, and auto-generated status messages like "on fire" or "debugging...". Your agent name appears in the status bar: `msg: SwiftRaven (2 peers) ●3`
|
|
69
61
|
|
|
70
|
-
**Activity Feed** -
|
|
62
|
+
**Activity Feed** - Unified timeline of edits, commits, test runs, messages, and task events. Query with `{ action: "feed" }`.
|
|
71
63
|
|
|
72
64
|
**Discovery** - Agents register with memorable themed names (SwiftRaven, LunarDust, OakTree). See who's active, what they're working on, which model and git branch they're on.
|
|
73
65
|
|
|
74
|
-
**Messaging** - Send messages between agents. Recipients wake up immediately and see the message as a steering prompt.
|
|
66
|
+
**Messaging** - Send messages between agents. Recipients wake up immediately and see the message as a steering prompt.
|
|
75
67
|
|
|
76
68
|
**File Reservations** - Claim files or directories. Other agents get blocked with a clear message telling them who to coordinate with. Auto-releases on exit.
|
|
77
69
|
|
|
78
|
-
**Stuck Detection** - Agents idle too long with an open task or reservation are flagged as stuck.
|
|
79
|
-
|
|
80
|
-
**Human as Participant** - Your interactive pi session appears in the agent list with `(you)`. Same activity tracking, same status messages. You can chat from the overlay.
|
|
70
|
+
**Stuck Detection** - Agents idle too long with an open task or reservation are flagged as stuck. Peers get a notification.
|
|
81
71
|
|
|
82
|
-
**
|
|
72
|
+
**Human as Participant** - Your interactive pi session appears in the agent list with `(you)`. Same activity tracking, same status messages. Chat from the overlay.
|
|
83
73
|
|
|
84
74
|
## Chat Overlay
|
|
85
75
|
|
|
86
76
|
`/messenger` opens an interactive overlay with agent presence, activity feed, and chat:
|
|
87
77
|
|
|
88
|
-
|
|
89
|
-
╭─ Messenger ── 3 agents ── myapp ────────────────────╮
|
|
90
|
-
│ │
|
|
91
|
-
│ 🟢 SwiftRaven (you) │
|
|
92
|
-
│ editing login.ts - 12 tools - 31.0k - on fire 🔥 │
|
|
93
|
-
│ │
|
|
94
|
-
│ 🟡 GoldFalcon idle 2m │
|
|
95
|
-
│ 8 tools - 24.1k - 📁 src/api/ │
|
|
96
|
-
│ │
|
|
97
|
-
│ 🔴 IronKnight stuck │
|
|
98
|
-
│ 3 tools - 16.4k │
|
|
99
|
-
│ │
|
|
100
|
-
│ Activity │
|
|
101
|
-
│ 10:42 SwiftRaven editing login.ts │
|
|
102
|
-
│ 10:40 GoldFalcon → SwiftRaven: "auth done?" │
|
|
103
|
-
│ 10:38 SwiftRaven committed "feat: add OAuth" │
|
|
104
|
-
│ 10:35 [Crew] GoldFalcon started task-03 │
|
|
105
|
-
├──────────────────────────────────────────────────────┤
|
|
106
|
-
│ > @GoldFalcon almost done [Tab] [Enter]│
|
|
107
|
-
╰──────────────────────────────────────────────────────╯
|
|
108
|
-
```
|
|
78
|
+
<img width="722" height="351" alt="pi-messenger chat overlay" src="https://github.com/user-attachments/assets/4d0f1db7-90dd-4ffb-9463-560426edebd9" />
|
|
109
79
|
|
|
110
80
|
Chat input supports `@Name msg` for DMs and `@all msg` for broadcasts. Text without `@` broadcasts from the Agents tab or DMs the selected agent tab.
|
|
111
81
|
|
|
@@ -118,120 +88,19 @@ Chat input supports `@Name msg` for DMs and `@all msg` for broadcasts. Text with
|
|
|
118
88
|
|
|
119
89
|
## Crew: Task Orchestration
|
|
120
90
|
|
|
121
|
-
Crew
|
|
91
|
+
Crew turns a PRD into a dependency graph of tasks, then executes them in parallel waves.
|
|
122
92
|
|
|
123
|
-
###
|
|
93
|
+
### Workflow
|
|
124
94
|
|
|
125
|
-
1. **Plan**
|
|
126
|
-
2. **Work**
|
|
127
|
-
3. **Review**
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
// Plan from your PRD (auto-discovers PRD.md, SPEC.md, etc.)
|
|
131
|
-
pi_messenger({ action: "plan" })
|
|
132
|
-
|
|
133
|
-
// Or specify PRD path explicitly
|
|
134
|
-
pi_messenger({ action: "plan", prd: "docs/PRD.md" })
|
|
135
|
-
|
|
136
|
-
// Execute tasks (spawns parallel workers)
|
|
137
|
-
pi_messenger({ action: "work" })
|
|
138
|
-
|
|
139
|
-
// Or run autonomously until done/blocked
|
|
140
|
-
pi_messenger({ action: "work", autonomous: true })
|
|
141
|
-
|
|
142
|
-
// Review a specific task
|
|
143
|
-
pi_messenger({ action: "review", target: "task-1" })
|
|
144
|
-
// → SHIP ✅ or NEEDS_WORK 🔄
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Crew API
|
|
148
|
-
|
|
149
|
-
**Planning**
|
|
150
|
-
| Action | Description | Example |
|
|
151
|
-
|--------|-------------|---------|
|
|
152
|
-
| `plan` | Create plan from PRD | `{ action: "plan" }` or `{ action: "plan", prd: "..." }` |
|
|
153
|
-
| `status` | Show progress | `{ action: "status" }` |
|
|
154
|
-
|
|
155
|
-
**Work Execution**
|
|
156
|
-
| Action | Description | Example |
|
|
157
|
-
|--------|-------------|---------|
|
|
158
|
-
| `work` | Run ready tasks | `{ action: "work" }` |
|
|
159
|
-
| `work` (auto) | Run until done/blocked | `{ action: "work", autonomous: true }` |
|
|
160
|
-
|
|
161
|
-
**Task Management**
|
|
162
|
-
| Action | Description | Example |
|
|
163
|
-
|--------|-------------|---------|
|
|
164
|
-
| `task.show` | Show task details | `{ action: "task.show", id: "task-1" }` |
|
|
165
|
-
| `task.list` | List all tasks | `{ action: "task.list" }` |
|
|
166
|
-
| `task.start` | Start task | `{ action: "task.start", id: "task-1" }` |
|
|
167
|
-
| `task.done` | Complete task | `{ action: "task.done", id: "task-1", summary: "..." }` |
|
|
168
|
-
| `task.block` | Block task | `{ action: "task.block", id: "task-1", reason: "..." }` |
|
|
169
|
-
| `task.unblock` | Unblock task | `{ action: "task.unblock", id: "task-1" }` |
|
|
170
|
-
| `task.ready` | List ready tasks | `{ action: "task.ready" }` |
|
|
171
|
-
| `task.reset` | Reset task | `{ action: "task.reset", id: "task-1", cascade: true }` |
|
|
172
|
-
|
|
173
|
-
**Review**
|
|
174
|
-
| Action | Description | Example |
|
|
175
|
-
|--------|-------------|---------|
|
|
176
|
-
| `review` | Review implementation | `{ action: "review", target: "task-1" }` |
|
|
177
|
-
|
|
178
|
-
**Maintenance**
|
|
179
|
-
| Action | Description | Example |
|
|
180
|
-
|--------|-------------|---------|
|
|
181
|
-
| `crew.status` | Overall status | `{ action: "crew.status" }` |
|
|
182
|
-
| `crew.validate` | Validate plan | `{ action: "crew.validate" }` |
|
|
183
|
-
| `crew.agents` | List crew agents | `{ action: "crew.agents" }` |
|
|
184
|
-
| `crew.install` | Install crew agents | `{ action: "crew.install" }` |
|
|
185
|
-
|
|
186
|
-
### Planning Workflow
|
|
187
|
-
|
|
188
|
-
The `plan` action runs a multi-pass planning loop: the planner drafts tasks, a reviewer checks them against the PRD, and the planner refines until SHIP or `planning.maxPasses` is reached. All passes and feedback are stored in `.pi/messenger/crew/planning-progress.md`.
|
|
189
|
-
|
|
190
|
-
```
|
|
191
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
192
|
-
│ Your Project │
|
|
193
|
-
│ ├── PRD.md ◄── Planner discovers and reads these │
|
|
194
|
-
│ ├── DESIGN.md │
|
|
195
|
-
│ ├── src/ │
|
|
196
|
-
│ └── ... │
|
|
197
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
198
|
-
│
|
|
199
|
-
▼
|
|
200
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
201
|
-
│ Planner (opus) │
|
|
202
|
-
│ ├── Explores codebase structure and patterns │
|
|
203
|
-
│ ├── Reads project documentation │
|
|
204
|
-
│ ├── Identifies gaps, edge cases, security concerns │
|
|
205
|
-
│ └── Drafts task breakdown with dependencies │
|
|
206
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
207
|
-
│ append to
|
|
208
|
-
▼
|
|
209
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
210
|
-
│ planning-progress.md (history + feedback) │
|
|
211
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
212
|
-
│
|
|
213
|
-
▼
|
|
214
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
215
|
-
│ Reviewer (gpt-5.2-high) │
|
|
216
|
-
│ ├── SHIP ✅ or NEEDS_WORK 🔄 │
|
|
217
|
-
│ └── Feeds back into the next planner pass │
|
|
218
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
219
|
-
│ SHIP
|
|
220
|
-
▼
|
|
221
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
222
|
-
│ Result: Tasks with Dependencies │
|
|
223
|
-
│ ├── task-1: Setup types (no deps) │
|
|
224
|
-
│ ├── task-2: Core logic (depends on task-1) │
|
|
225
|
-
│ ├── task-3: API endpoints (depends on task-1) │
|
|
226
|
-
│ └── task-4: Tests (depends on task-2, task-3) │
|
|
227
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
228
|
-
```
|
|
95
|
+
1. **Plan** — Planner explores the codebase and PRD, drafts tasks with dependencies. A reviewer checks the plan; the planner refines until SHIP or `maxPasses` is reached. History is stored in `planning-progress.md`.
|
|
96
|
+
2. **Work** — Workers implement ready tasks (all dependencies met) in parallel waves. A single `work` call runs one wave. `autonomous: true` runs waves back-to-back until everything is done or blocked.
|
|
97
|
+
3. **Review** — Reviewer checks each implementation: SHIP, NEEDS_WORK, or MAJOR_RETHINK.
|
|
229
98
|
|
|
230
|
-
|
|
99
|
+
No special PRD format required — the planner auto-discovers `PRD.md`, `SPEC.md`, `DESIGN.md`, etc. in your project root and `docs/`.
|
|
231
100
|
|
|
232
|
-
###
|
|
101
|
+
### Wave Execution
|
|
233
102
|
|
|
234
|
-
|
|
103
|
+
Tasks form a dependency graph. Independent tasks run concurrently:
|
|
235
104
|
|
|
236
105
|
```
|
|
237
106
|
Wave 1: task-1 (no deps) ─┐
|
|
@@ -243,63 +112,7 @@ Wave 2: task-2 (→ task-1) ─┤── task-1 done, task-2 unblocked
|
|
|
243
112
|
Wave 3: task-5 (→ task-2, task-4) ── both deps done
|
|
244
113
|
```
|
|
245
114
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
The planner structures tasks to maximize this parallelism. Foundation work (types, config, schemas) has no dependencies so it starts immediately. Features that don't touch each other get separate dependency chains so they can run in parallel. Tasks that need shared work done first (tests, integration, docs) depend on the tasks that produce it.
|
|
249
|
-
|
|
250
|
-
A single `work` call runs one wave. Autonomous mode (`autonomous: true`) runs waves back-to-back until everything is done or blocked.
|
|
251
|
-
|
|
252
|
-
### Autonomous Mode
|
|
253
|
-
|
|
254
|
-
Run tasks continuously until completion:
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
pi_messenger({ action: "work", autonomous: true })
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
Autonomous mode:
|
|
261
|
-
- Executes waves of parallel workers
|
|
262
|
-
- Auto-blocks on failure
|
|
263
|
-
- Stops when all tasks done or blocked
|
|
264
|
-
- Respects `maxWaves` limit (default: 50)
|
|
265
|
-
|
|
266
|
-
### Crew Overlay Tab
|
|
267
|
-
|
|
268
|
-
The `/messenger` overlay includes a Crew tab showing task status:
|
|
269
|
-
|
|
270
|
-
```
|
|
271
|
-
╭─ Messenger ── 3 agents ── myapp ──────────────────────╮
|
|
272
|
-
│ Agents │ ▸ Crew (2/5) │ ● GoldFalcon │ + All │
|
|
273
|
-
├──────────────────────────────────────────────────────┤
|
|
274
|
-
│ │
|
|
275
|
-
│ 📋 docs/PRD.md [2/5] │
|
|
276
|
-
│ │
|
|
277
|
-
│ ✓ task-1 Setup OAuth config │
|
|
278
|
-
│ ✓ task-2 Implement token storage │
|
|
279
|
-
│ ● task-3 Add Google provider (SwiftRaven) │
|
|
280
|
-
│ ○ task-4 Add GitHub provider → task-2 │
|
|
281
|
-
│ ○ task-5 Write tests → task-3, task-4 │
|
|
282
|
-
│ │
|
|
283
|
-
├──────────────────────────────────────────────────────┤
|
|
284
|
-
│ ● AUTO Wave 2 │ 2/5 done │ 1 ready │ ⏱️ 3:42 │
|
|
285
|
-
╰──────────────────────────────────────────────────────╯
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
### Crew Data Storage
|
|
289
|
-
|
|
290
|
-
```
|
|
291
|
-
.pi/messenger/crew/
|
|
292
|
-
├── plan.json # Plan metadata (PRD path, progress)
|
|
293
|
-
├── plan.md # Planner output
|
|
294
|
-
├── planning-progress.md # Planning loop history + feedback
|
|
295
|
-
├── tasks/
|
|
296
|
-
│ ├── task-1.json # Task metadata
|
|
297
|
-
│ ├── task-1.md # Task specification
|
|
298
|
-
│ └── ...
|
|
299
|
-
├── blocks/ # Block context for blocked tasks
|
|
300
|
-
├── artifacts/ # Debug artifacts
|
|
301
|
-
└── config.json # Project-level crew config
|
|
302
|
-
```
|
|
115
|
+
The planner structures tasks to maximize parallelism. Foundation work has no dependencies and starts immediately. Features that don't touch each other get separate chains. Autonomous mode stops when all tasks are done or blocked.
|
|
303
116
|
|
|
304
117
|
### Crew Configuration
|
|
305
118
|
|
|
@@ -316,121 +129,55 @@ Add to `~/.pi/agent/pi-messenger.json`:
|
|
|
316
129
|
}
|
|
317
130
|
```
|
|
318
131
|
|
|
319
|
-
|
|
320
|
-
|---------|-------------|---------|
|
|
321
|
-
| `concurrency.workers` | Max parallel workers during work | `2` |
|
|
322
|
-
| `review.enabled` | Enable review functionality | `true` |
|
|
323
|
-
| `review.maxIterations` | Max review iterations per task | `3` |
|
|
324
|
-
| `planning.maxPasses` | Max planner passes before accepting last output | `3` |
|
|
325
|
-
| `work.maxAttemptsPerTask` | Retries before blocking a task | `5` |
|
|
326
|
-
| `work.maxWaves` | Max waves in autonomous mode | `50` |
|
|
327
|
-
|
|
328
|
-
### Crew Install
|
|
132
|
+
Crew agents (planner, worker, reviewer, interview-generator, plan-sync) are **auto-installed** on first use. Run `npx pi-messenger --crew-install` to manually install or update.
|
|
329
133
|
|
|
330
|
-
|
|
134
|
+
## API Reference
|
|
331
135
|
|
|
332
|
-
|
|
333
|
-
pi_messenger({ action: "crew.install" })
|
|
334
|
-
```
|
|
136
|
+
### Coordination
|
|
335
137
|
|
|
336
|
-
**What gets installed:**
|
|
337
|
-
- **5 agents** in `~/.pi/agent/agents/` (planner, worker, reviewer, interview-generator, plan-sync)
|
|
338
|
-
- **1 skill** in `~/.pi/agent/skills/` (pi-messenger-crew quick reference)
|
|
339
|
-
|
|
340
|
-
To remove:
|
|
341
|
-
```typescript
|
|
342
|
-
pi_messenger({ action: "crew.uninstall" })
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
## Tool Reference
|
|
346
|
-
|
|
347
|
-
### Action-Based API (Recommended)
|
|
348
|
-
|
|
349
|
-
**Coordination**
|
|
350
138
|
| Action | Description |
|
|
351
139
|
|--------|-------------|
|
|
352
140
|
| `join` | Join the agent mesh |
|
|
353
141
|
| `list` | List agents with presence info |
|
|
354
142
|
| `status` | Show your status or crew progress |
|
|
355
|
-
| `whois` | Detailed info about an agent |
|
|
356
|
-
| `feed` | Show activity feed |
|
|
357
|
-
| `set_status` | Set custom status message (
|
|
358
|
-
| `send` | Send DM (
|
|
359
|
-
| `broadcast` | Broadcast to all (
|
|
360
|
-
| `reserve` | Reserve files (
|
|
361
|
-
| `release` | Release reservations (
|
|
362
|
-
| `rename` | Change your name (
|
|
363
|
-
| `swarm` | Show swarm task status |
|
|
364
|
-
| `claim` | Claim a swarm task (requires `taskId`) |
|
|
365
|
-
| `unclaim` | Release a swarm claim (requires `taskId`) |
|
|
366
|
-
| `complete` | Complete a swarm task (requires `taskId`) |
|
|
143
|
+
| `whois` | Detailed info about an agent (`name` required) |
|
|
144
|
+
| `feed` | Show activity feed (`limit` optional, default: 20) |
|
|
145
|
+
| `set_status` | Set custom status message (`message` optional — omit to clear) |
|
|
146
|
+
| `send` | Send DM (`to` + `message` required) |
|
|
147
|
+
| `broadcast` | Broadcast to all (`message` required) |
|
|
148
|
+
| `reserve` | Reserve files (`paths` required, `reason` optional) |
|
|
149
|
+
| `release` | Release reservations (`paths` optional — omit to release all) |
|
|
150
|
+
| `rename` | Change your name (`name` required) |
|
|
367
151
|
|
|
368
|
-
|
|
369
|
-
pi_messenger({
|
|
370
|
-
action: string, // Action to perform
|
|
371
|
-
|
|
372
|
-
// Coordination
|
|
373
|
-
name?: string, // For whois, rename
|
|
374
|
-
message?: string, // For send, broadcast, set_status
|
|
375
|
-
to?: string | string[], // For send
|
|
376
|
-
paths?: string[], // For reserve, release
|
|
377
|
-
reason?: string, // For reserve, claim, task.block
|
|
378
|
-
limit?: number, // For feed (default: 20)
|
|
379
|
-
|
|
380
|
-
// Plan
|
|
381
|
-
prd?: string, // PRD file path
|
|
382
|
-
|
|
383
|
-
// Task identifiers
|
|
384
|
-
id?: string, // Task ID (task-N)
|
|
385
|
-
taskId?: string, // Swarm task ID
|
|
386
|
-
target?: string, // Target for review
|
|
387
|
-
|
|
388
|
-
// Creation
|
|
389
|
-
title?: string, // For task.create
|
|
390
|
-
dependsOn?: string[], // Task dependencies
|
|
391
|
-
|
|
392
|
-
// Completion
|
|
393
|
-
summary?: string, // For task.done
|
|
394
|
-
|
|
395
|
-
// Work options
|
|
396
|
-
autonomous?: boolean, // Run continuously
|
|
397
|
-
concurrency?: number, // Override concurrency
|
|
398
|
-
|
|
399
|
-
// Reset
|
|
400
|
-
cascade?: boolean, // Reset dependent tasks too
|
|
401
|
-
})
|
|
402
|
-
```
|
|
152
|
+
### Crew
|
|
403
153
|
|
|
404
|
-
|
|
154
|
+
| Action | Description |
|
|
155
|
+
|--------|-------------|
|
|
156
|
+
| `plan` | Create plan from PRD (`prd` optional — auto-discovers if omitted) |
|
|
157
|
+
| `work` | Run ready tasks (`autonomous`, `concurrency` optional) |
|
|
158
|
+
| `review` | Review implementation (`target` task ID required) |
|
|
159
|
+
| `task.list` | List all tasks |
|
|
160
|
+
| `task.show` | Show task details (`id` required) |
|
|
161
|
+
| `task.start` | Start a task (`id` required) |
|
|
162
|
+
| `task.done` | Complete a task (`id` required, `summary` optional) |
|
|
163
|
+
| `task.block` | Block a task (`id` + `reason` required) |
|
|
164
|
+
| `task.unblock` | Unblock a task (`id` required) |
|
|
165
|
+
| `task.ready` | List tasks ready to work |
|
|
166
|
+
| `task.reset` | Reset a task (`id` required, `cascade` optional) |
|
|
167
|
+
| `crew.status` | Overall crew status |
|
|
168
|
+
| `crew.validate` | Validate plan dependencies |
|
|
169
|
+
| `crew.agents` | List available crew agents |
|
|
170
|
+
| `crew.install` | Install/update crew agents |
|
|
171
|
+
| `crew.uninstall` | Remove crew agents and skill |
|
|
172
|
+
|
|
173
|
+
### Swarm (Spec-Based)
|
|
405
174
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
// Swarm
|
|
413
|
-
swarm?: boolean, // Get swarm status
|
|
414
|
-
claim?: string, // Claim a task
|
|
415
|
-
unclaim?: string, // Release without completing
|
|
416
|
-
complete?: string, // Mark task complete
|
|
417
|
-
notes?: string, // Completion notes
|
|
418
|
-
|
|
419
|
-
// Messaging
|
|
420
|
-
to?: string | string[], // Recipient(s)
|
|
421
|
-
broadcast?: boolean, // Send to all
|
|
422
|
-
message?: string, // Message text
|
|
423
|
-
|
|
424
|
-
// Reservations
|
|
425
|
-
reserve?: string[], // Paths to reserve
|
|
426
|
-
reason?: string, // Why reserving/claiming
|
|
427
|
-
release?: string[] | true, // Release reservations
|
|
428
|
-
|
|
429
|
-
// Other
|
|
430
|
-
rename?: string, // Change your name
|
|
431
|
-
list?: boolean, // List active agents
|
|
432
|
-
})
|
|
433
|
-
```
|
|
175
|
+
| Action | Description |
|
|
176
|
+
|--------|-------------|
|
|
177
|
+
| `swarm` | Show swarm task status |
|
|
178
|
+
| `claim` | Claim a task (`taskId` required) |
|
|
179
|
+
| `unclaim` | Release a claim (`taskId` required) |
|
|
180
|
+
| `complete` | Complete a task (`taskId` required) |
|
|
434
181
|
|
|
435
182
|
## Configuration
|
|
436
183
|
|
|
@@ -452,32 +199,30 @@ Create `~/.pi/agent/pi-messenger.json`:
|
|
|
452
199
|
| `autoRegister` | Join mesh on startup | `false` |
|
|
453
200
|
| `autoRegisterPaths` | Folders where auto-join is enabled (supports `*` globs) | `[]` |
|
|
454
201
|
| `scopeToFolder` | Only see agents in same directory | `false` |
|
|
455
|
-
| `nameTheme` | Name
|
|
202
|
+
| `nameTheme` | Name theme: `default`, `nature`, `space`, `minimal`, `custom` | `"default"` |
|
|
456
203
|
| `nameWords` | Custom theme words: `{ adjectives: [...], nouns: [...] }` | — |
|
|
457
204
|
| `feedRetention` | Max events kept in activity feed | `50` |
|
|
458
|
-
| `stuckThreshold` | Seconds of inactivity before stuck detection | `900`
|
|
205
|
+
| `stuckThreshold` | Seconds of inactivity before stuck detection | `900` |
|
|
459
206
|
| `stuckNotify` | Show notification when a peer appears stuck | `true` |
|
|
460
207
|
| `autoStatus` | Auto-generate status messages from activity | `true` |
|
|
461
208
|
| `crewEventsInFeed` | Include crew task events in activity feed | `true` |
|
|
462
209
|
| `contextMode` | Context injection level: `full`, `minimal`, `none` | `"full"` |
|
|
463
210
|
|
|
211
|
+
Config priority: project `.pi/pi-messenger.json` > user `~/.pi/agent/pi-messenger.json` > `~/.pi/agent/settings.json` `"messenger"` key > defaults.
|
|
212
|
+
|
|
464
213
|
## How It Works
|
|
465
214
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
├── claims.json # Active task claims
|
|
472
|
-
├── completions.json # Completed tasks
|
|
473
|
-
└── swarm.lock # Atomic lock for claims
|
|
474
|
-
```
|
|
215
|
+
Pi-messenger is a [pi extension](https://github.com/badlogic/pi-mono) that hooks into the agent lifecycle. It uses `pi.on("tool_call")` and `pi.on("tool_result")` to track activity — every edit, commit, and test run gets logged. `pi.on("session_start")` handles auto-registration, `pi.on("session_shutdown")` cleans up, and `pi.on("agent_end")` drives autonomous crew mode by checking for ready tasks after each agent turn.
|
|
216
|
+
|
|
217
|
+
Incoming messages wake the receiving agent via `pi.sendMessage()` with `triggerTurn: true` and `deliverAs: "steer"`, which injects the message as a steering prompt that resumes the agent. File reservations are enforced by returning `{ block: true }` from a `tool_call` hook on write/edit operations. The `/messenger` overlay uses `ctx.ui.custom()` for the chat TUI, and `ctx.ui.setStatus()` keeps the status bar updated with peer count and unread messages.
|
|
218
|
+
|
|
219
|
+
Crew workers are spawned as `pi --mode json` subprocesses with the agent's system prompt, model, and tool restrictions from their `.md` definitions. Progress is tracked via JSONL streaming. The planner and reviewer work the same way — just pi instances with different agent configs.
|
|
475
220
|
|
|
476
|
-
|
|
221
|
+
All coordination is file-based, no daemon required. Global state (registry, inboxes, activity feed) lives in `~/.pi/agent/messenger/`. Per-project crew data (plan, tasks, artifacts) lives in `.pi/messenger/crew/` inside your project. Dead agents are detected via PID checks and cleaned up automatically.
|
|
477
222
|
|
|
478
223
|
## Credits
|
|
479
224
|
|
|
480
|
-
- **[mcp_agent_mail](https://github.com/Dicklesworthstone/mcp_agent_mail)** by [@doodlestein](https://x.com/doodlestein)
|
|
225
|
+
- **[mcp_agent_mail](https://github.com/Dicklesworthstone/mcp_agent_mail)** by [@doodlestein](https://x.com/doodlestein) — Inspiration for agent-to-agent messaging
|
|
481
226
|
- **[Pi coding agent](https://github.com/badlogic/pi-mono/)** by [@badlogicgames](https://x.com/badlogicgames)
|
|
482
227
|
|
|
483
228
|
## License
|
package/crew/agents.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as os from "node:os";
|
|
9
11
|
import * as path from "node:path";
|
|
10
12
|
import { fileURLToPath } from "node:url";
|
|
11
13
|
import { discoverCrewAgents, type CrewAgentConfig } from "./utils/discover.js";
|
|
@@ -31,6 +33,7 @@ import type { AgentTask, AgentResult } from "./types.js";
|
|
|
31
33
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
34
|
const __dirname = path.dirname(__filename);
|
|
33
35
|
const EXTENSION_DIR = path.resolve(__dirname, "..");
|
|
36
|
+
const BUILTIN_TOOLS = new Set(["read", "bash", "edit", "write", "grep", "find", "ls"]);
|
|
34
37
|
|
|
35
38
|
export interface SpawnOptions {
|
|
36
39
|
onProgress?: (results: AgentResult[]) => void;
|
|
@@ -113,12 +116,41 @@ async function runAgent(
|
|
|
113
116
|
|
|
114
117
|
return new Promise((resolve) => {
|
|
115
118
|
// Build args for pi command
|
|
116
|
-
const args = ["--mode", "json", "--
|
|
119
|
+
const args = ["--mode", "json", "--no-session", "-p"];
|
|
117
120
|
if (agentConfig?.model) args.push("--model", agentConfig.model);
|
|
118
|
-
|
|
121
|
+
|
|
122
|
+
if (agentConfig?.tools?.length) {
|
|
123
|
+
const builtinTools: string[] = [];
|
|
124
|
+
const extensionPaths: string[] = [];
|
|
125
|
+
for (const tool of agentConfig.tools) {
|
|
126
|
+
if (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js")) {
|
|
127
|
+
extensionPaths.push(tool);
|
|
128
|
+
} else if (BUILTIN_TOOLS.has(tool)) {
|
|
129
|
+
builtinTools.push(tool);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (builtinTools.length > 0) {
|
|
134
|
+
args.push("--tools", builtinTools.join(","));
|
|
135
|
+
}
|
|
136
|
+
for (const extensionPath of extensionPaths) {
|
|
137
|
+
args.push("--extension", extensionPath);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
119
141
|
// Pass extension so workers can use pi_messenger
|
|
120
142
|
args.push("--extension", EXTENSION_DIR);
|
|
121
143
|
|
|
144
|
+
let promptTmpDir: string | null = null;
|
|
145
|
+
if (agentConfig?.systemPrompt) {
|
|
146
|
+
promptTmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-messenger-agent-"));
|
|
147
|
+
const promptPath = path.join(promptTmpDir, `${task.agent.replace(/[^\w.-]/g, "_")}.md`);
|
|
148
|
+
fs.writeFileSync(promptPath, agentConfig.systemPrompt, { mode: 0o600 });
|
|
149
|
+
args.push("--append-system-prompt", promptPath);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
args.push(task.task);
|
|
153
|
+
|
|
122
154
|
const proc = spawn("pi", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
123
155
|
|
|
124
156
|
let jsonlBuffer = "";
|
|
@@ -166,6 +198,10 @@ async function runAgent(
|
|
|
166
198
|
});
|
|
167
199
|
}
|
|
168
200
|
|
|
201
|
+
if (promptTmpDir) {
|
|
202
|
+
try { fs.rmSync(promptTmpDir, { recursive: true, force: true }); } catch {}
|
|
203
|
+
}
|
|
204
|
+
|
|
169
205
|
resolve({
|
|
170
206
|
agent: task.agent,
|
|
171
207
|
exitCode: code ?? 1,
|
|
@@ -194,4 +230,3 @@ async function runAgent(
|
|
|
194
230
|
}
|
|
195
231
|
});
|
|
196
232
|
}
|
|
197
|
-
|
package/install.mjs
CHANGED
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
* No git dependency — the npm package IS the source.
|
|
8
8
|
*
|
|
9
9
|
* Usage:
|
|
10
|
-
* npx pi-messenger
|
|
11
|
-
* npx pi-messenger --remove
|
|
10
|
+
* npx pi-messenger # Install or update extension
|
|
11
|
+
* npx pi-messenger --remove # Remove the extension
|
|
12
|
+
* npx pi-messenger --crew-install # Install crew agents and skills
|
|
13
|
+
* npx pi-messenger --crew-uninstall # Remove crew agents and skills
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
16
|
import * as fs from "node:fs";
|
|
@@ -19,12 +21,35 @@ import { fileURLToPath } from "node:url";
|
|
|
19
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
22
|
const PACKAGE_DIR = path.dirname(__filename);
|
|
21
23
|
const EXTENSION_DIR = path.join(os.homedir(), ".pi", "agent", "extensions", "pi-messenger");
|
|
24
|
+
const AGENTS_DIR = path.join(os.homedir(), ".pi", "agent", "agents");
|
|
25
|
+
const SKILLS_DIR = path.join(os.homedir(), ".pi", "agent", "skills");
|
|
26
|
+
|
|
27
|
+
const CREW_AGENTS = [
|
|
28
|
+
"crew-planner.md",
|
|
29
|
+
"crew-interview-generator.md",
|
|
30
|
+
"crew-plan-sync.md",
|
|
31
|
+
"crew-worker.md",
|
|
32
|
+
"crew-reviewer.md",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const DEPRECATED_AGENTS = [
|
|
36
|
+
"crew-repo-scout.md",
|
|
37
|
+
"crew-practice-scout.md",
|
|
38
|
+
"crew-docs-scout.md",
|
|
39
|
+
"crew-web-scout.md",
|
|
40
|
+
"crew-github-scout.md",
|
|
41
|
+
"crew-gap-analyst.md",
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
const CREW_SKILLS = ["pi-messenger-crew"];
|
|
22
45
|
|
|
23
46
|
const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_DIR, "package.json"), "utf-8"));
|
|
24
47
|
const VERSION = pkg.version;
|
|
25
48
|
|
|
26
49
|
const args = process.argv.slice(2);
|
|
27
50
|
const isRemove = args.includes("--remove") || args.includes("-r");
|
|
51
|
+
const isCrewInstall = args.includes("--crew-install");
|
|
52
|
+
const isCrewUninstall = args.includes("--crew-uninstall");
|
|
28
53
|
const isHelp = args.includes("--help") || args.includes("-h");
|
|
29
54
|
|
|
30
55
|
if (isHelp) {
|
|
@@ -32,15 +57,103 @@ if (isHelp) {
|
|
|
32
57
|
pi-messenger v${VERSION} - Multi-agent coordination for pi
|
|
33
58
|
|
|
34
59
|
Usage:
|
|
35
|
-
npx pi-messenger
|
|
36
|
-
npx pi-messenger --remove
|
|
37
|
-
npx pi-messenger --
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
npx pi-messenger Install or update extension
|
|
61
|
+
npx pi-messenger --remove Remove the extension
|
|
62
|
+
npx pi-messenger --crew-install Install crew agents and skills
|
|
63
|
+
npx pi-messenger --crew-uninstall Remove crew agents and skills
|
|
64
|
+
npx pi-messenger --help Show this help
|
|
65
|
+
|
|
66
|
+
Extension directory: ${EXTENSION_DIR}
|
|
67
|
+
Agents directory: ${AGENTS_DIR}
|
|
68
|
+
Skills directory: ${SKILLS_DIR}
|
|
40
69
|
`);
|
|
41
70
|
process.exit(0);
|
|
42
71
|
}
|
|
43
72
|
|
|
73
|
+
// ─── Crew install ────────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
if (isCrewInstall) {
|
|
76
|
+
const sourceAgents = path.join(PACKAGE_DIR, "crew", "agents");
|
|
77
|
+
if (!fs.existsSync(sourceAgents)) {
|
|
78
|
+
console.error("Could not find crew agent files in package.");
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fs.mkdirSync(AGENTS_DIR, { recursive: true });
|
|
83
|
+
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
84
|
+
|
|
85
|
+
let installed = 0;
|
|
86
|
+
let updated = 0;
|
|
87
|
+
|
|
88
|
+
for (const agent of DEPRECATED_AGENTS) {
|
|
89
|
+
const target = path.join(AGENTS_DIR, agent);
|
|
90
|
+
if (fs.existsSync(target)) {
|
|
91
|
+
fs.unlinkSync(target);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (const agent of CREW_AGENTS) {
|
|
96
|
+
const src = path.join(sourceAgents, agent);
|
|
97
|
+
const dst = path.join(AGENTS_DIR, agent);
|
|
98
|
+
if (!fs.existsSync(src)) continue;
|
|
99
|
+
const existed = fs.existsSync(dst);
|
|
100
|
+
fs.copyFileSync(src, dst);
|
|
101
|
+
if (existed) updated++;
|
|
102
|
+
else installed++;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const sourceSkills = path.join(PACKAGE_DIR, "skills");
|
|
106
|
+
for (const skill of CREW_SKILLS) {
|
|
107
|
+
const srcDir = path.join(sourceSkills, skill);
|
|
108
|
+
const dstDir = path.join(SKILLS_DIR, skill);
|
|
109
|
+
if (!fs.existsSync(srcDir)) continue;
|
|
110
|
+
const existed = fs.existsSync(dstDir);
|
|
111
|
+
fs.mkdirSync(dstDir, { recursive: true });
|
|
112
|
+
for (const file of fs.readdirSync(srcDir)) {
|
|
113
|
+
const srcFile = path.join(srcDir, file);
|
|
114
|
+
if (fs.statSync(srcFile).isFile()) {
|
|
115
|
+
fs.copyFileSync(srcFile, path.join(dstDir, file));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (existed) updated++;
|
|
119
|
+
else installed++;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(`Crew installed (${installed} new, ${updated} updated)`);
|
|
123
|
+
console.log(` Agents: ${AGENTS_DIR}`);
|
|
124
|
+
console.log(` Skills: ${SKILLS_DIR}`);
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── Crew uninstall ──────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
if (isCrewUninstall) {
|
|
131
|
+
let removed = 0;
|
|
132
|
+
|
|
133
|
+
for (const agent of [...CREW_AGENTS, ...DEPRECATED_AGENTS]) {
|
|
134
|
+
const target = path.join(AGENTS_DIR, agent);
|
|
135
|
+
if (fs.existsSync(target)) {
|
|
136
|
+
fs.unlinkSync(target);
|
|
137
|
+
removed++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const skill of CREW_SKILLS) {
|
|
142
|
+
const target = path.join(SKILLS_DIR, skill);
|
|
143
|
+
if (fs.existsSync(target)) {
|
|
144
|
+
fs.rmSync(target, { recursive: true });
|
|
145
|
+
removed++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
console.log(removed > 0
|
|
150
|
+
? `Removed ${removed} crew file(s) from ${AGENTS_DIR} and ${SKILLS_DIR}`
|
|
151
|
+
: "Nothing to remove");
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ─── Extension remove ────────────────────────────────────────────────────────
|
|
156
|
+
|
|
44
157
|
if (isRemove) {
|
|
45
158
|
if (fs.existsSync(EXTENSION_DIR)) {
|
|
46
159
|
fs.rmSync(EXTENSION_DIR, { recursive: true });
|