@melihmucuk/pi-crew 1.0.7 → 1.0.9

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.
Files changed (45) hide show
  1. package/agents/code-reviewer.md +18 -6
  2. package/agents/planner.md +9 -1
  3. package/agents/quality-reviewer.md +20 -13
  4. package/agents/scout.md +33 -26
  5. package/dist/agent-discovery.d.ts +0 -5
  6. package/dist/agent-discovery.js +1 -1
  7. package/dist/bootstrap-session.d.ts +13 -4
  8. package/dist/bootstrap-session.js +25 -16
  9. package/dist/index.js +37 -7
  10. package/dist/integration/register-command.d.ts +2 -2
  11. package/dist/integration/register-command.js +5 -5
  12. package/dist/integration/register-renderers.js +3 -0
  13. package/dist/integration/register-tools.d.ts +2 -2
  14. package/dist/integration/register-tools.js +2 -2
  15. package/dist/integration/tool-presentation.d.ts +2 -3
  16. package/dist/integration/tool-presentation.js +7 -8
  17. package/dist/integration/tools/crew-abort.d.ts +1 -1
  18. package/dist/integration/tools/crew-abort.js +3 -3
  19. package/dist/integration/tools/crew-done.d.ts +1 -1
  20. package/dist/integration/tools/crew-done.js +2 -2
  21. package/dist/integration/tools/crew-list.d.ts +1 -1
  22. package/dist/integration/tools/crew-list.js +3 -3
  23. package/dist/integration/tools/crew-respond.d.ts +1 -1
  24. package/dist/integration/tools/crew-respond.js +6 -7
  25. package/dist/integration/tools/crew-spawn.d.ts +1 -1
  26. package/dist/integration/tools/crew-spawn.js +17 -14
  27. package/dist/integration/tools/tool-deps.d.ts +3 -2
  28. package/dist/integration.d.ts +2 -2
  29. package/dist/integration.js +3 -3
  30. package/dist/runtime/crew-runtime.d.ts +61 -0
  31. package/dist/{crew-manager.js → runtime/crew-runtime.js} +84 -58
  32. package/dist/runtime/delivery-coordinator.d.ts +16 -7
  33. package/dist/runtime/delivery-coordinator.js +46 -20
  34. package/dist/runtime/subagent-registry.d.ts +1 -0
  35. package/dist/runtime/subagent-registry.js +3 -0
  36. package/dist/runtime/subagent-state.d.ts +2 -0
  37. package/dist/status-widget.d.ts +2 -2
  38. package/dist/status-widget.js +3 -3
  39. package/dist/subagent-messages.d.ts +5 -2
  40. package/dist/subagent-messages.js +5 -4
  41. package/docs/architecture.md +106 -843
  42. package/package.json +1 -1
  43. package/prompts/pi-crew-plan.md +82 -123
  44. package/prompts/pi-crew-review.md +64 -115
  45. package/dist/crew-manager.d.ts +0 -44
@@ -1,904 +1,167 @@
1
1
  # pi-crew Architecture
2
2
 
3
- This document explains the technical architecture of `@melihmucuk/pi-crew` for both human users and coding agents.
3
+ This document explains the technical architecture of `@melihmucuk/pi-crew`, focusing on what makes this extension unique.
4
4
 
5
- It describes runtime behavior, integration points, ownership rules, delivery semantics, and implementation boundaries. It intentionally avoids code snippets. Source files are referenced instead, because exact code can change while the behavioral contract should remain stable.
5
+ For pi fundamentals, see pi docs: `extensions.md`, `sdk.md`, `session.md`. Project-level guardrails are in `AGENTS.md`.
6
6
 
7
- All paths in this document are relative to the repository root.
7
+ ## 1. What pi-crew adds
8
8
 
9
- ## 1. What the project is
9
+ `pi-crew` is a non-blocking subagent orchestration extension. It lets one pi session delegate work to isolated subagent sessions without blocking the caller. Results are delivered back as `crew-result` custom messages.
10
10
 
11
- `pi-crew` is a non-blocking subagent orchestration extension for pi.
11
+ Primary components:
12
12
 
13
- Its job is to let one pi session delegate work to one or more isolated subagent sessions without blocking the caller session. Each spawned subagent runs independently, and its result is delivered back to the session that spawned it as a `crew-result` custom message. When the owner session is already streaming, that message is delivered as steering content.
13
+ - `extension/runtime/crew-runtime.ts` - Process-level singleton owning all subagent state
14
+ - `extension/runtime/subagent-registry.ts` - In-memory subagent registry
15
+ - `extension/runtime/delivery-coordinator.ts` - Owner-based result routing
16
+ - `extension/bootstrap-session.ts` - Subagent session construction with extension filtering
17
+ - `extension/agent-discovery.ts` - Subagent definition discovery and validation
14
18
 
15
- At a high level, the system adds:
19
+ ## 2. Core runtime components
16
20
 
17
- - tool-based orchestration for spawning, listing, aborting, responding to, and closing subagents
18
- - a slash-command emergency abort path
19
- - TUI renderers for subagent custom messages
20
- - a live status widget for active subagents owned by the current session
21
- - bundled subagent definitions and a bundled review prompt template
21
+ ### 2.1 CrewRuntime singleton
22
22
 
23
- Primary entry points:
24
-
25
- - `package.json`
26
- - `extension/index.ts`
27
- - `README.md`
28
-
29
- ## 2. Architectural goals
30
-
31
- The extension is built around a few explicit goals:
32
-
33
- 1. **Keep the caller session interactive**
34
- The main session must not block while background work is happening.
35
-
36
- 2. **Preserve session isolation**
37
- Each subagent gets its own pi SDK session, context window, and resolved tool/skill set.
38
-
39
- 3. **Route results to the owning session**
40
- Results are not sent to whichever session happens to be active. They are sent to the session that created the subagent.
41
-
42
- 4. **Make multi-agent work understandable in the TUI**
43
- Users need visible state, clear completion messages, and an emergency stop path.
44
-
45
- 5. **Stay behavior-first**
46
- Agent definitions, tool restrictions, and delivery semantics are designed as explicit contracts, not incidental implementation details.
47
-
48
- Project-level guardrails that define these contracts live in:
49
-
50
- - `AGENTS.md`
51
-
52
- ## 3. Package layout and extension surface
53
-
54
- ### 3.1 Package registration in pi
55
-
56
- `pi-crew` is packaged as a pi extension package.
57
-
58
- Registration metadata lives in:
59
-
60
- - `package.json`
61
-
62
- Important package-level behaviors:
63
-
64
- - `pi.extensions` points pi to the built extension entry at `./dist/index.js`
65
- - `pi.prompts` exposes the bundled prompt template directory at `./prompts`
66
- - `agents/` is shipped as package data and auto-discovered as the lowest-priority source during agent discovery
67
-
68
- ### 3.2 Repository structure
69
-
70
- Main implementation areas:
71
-
72
- - `extension/` - runtime extension logic
73
- - `extension/runtime/` - in-memory state and delivery coordination
74
- - `extension/integration/` - pi tool, command, and renderer registration
75
- - `agents/` - bundled subagent definitions
76
- - `prompts/` - bundled prompt templates
77
-
78
- ## 4. Core runtime components
79
-
80
- ### 4.1 Extension bootstrap
81
-
82
- File:
83
-
84
- - `extension/index.ts`
85
-
86
- Responsibilities:
87
-
88
- - instantiate one `CrewManager` for the extension runtime
89
- - observe pi session lifecycle events
90
- - activate delivery routing when the active pi session changes
91
- - abort owned abortable subagents when an owner session shuts down
92
- - register tools, command, and message renderers
93
- - refresh the status widget when state changes
94
-
95
- Session lifecycle events used by the extension:
96
-
97
- - `session_start` (with `reason: "startup" | "reload" | "new" | "resume" | "fork"`)
98
- - `session_shutdown`
99
-
100
- This is the bridge between pi core events and `pi-crew` runtime behavior.
101
-
102
- ### 4.2 Crew manager
103
-
104
- File:
105
-
106
- - `extension/crew-manager.ts`
107
-
108
- `CrewManager` is the main orchestration service.
109
-
110
- It owns the extension’s operational workflow:
111
-
112
- - create subagent state records
113
- - bootstrap isolated subagent sessions
114
- - send prompts into subagent sessions
115
- - interpret prompt outcomes
116
- - transition subagents between `running`, `waiting`, `done`, `error`, and `aborted`
117
- - deliver results back to the owner session
118
- - enforce ownership checks for `respond`, `done`, and owned abort paths
119
- - dispose finished subagents
120
-
121
- In practice, `CrewManager` is the coordination layer above the registry and delivery subsystems.
122
-
123
- ### 4.3 Subagent registry
124
-
125
- Files:
126
-
127
- - `extension/runtime/subagent-registry.ts`
128
- - `extension/runtime/subagent-state.ts`
129
-
130
- Responsibilities:
131
-
132
- - store live in-memory subagent state in a `Map`
133
- - generate unique runtime IDs such as `<name>-<hex>`
134
- - filter subagents by owner session
135
- - provide summaries for the TUI widget and abort command
136
- - count other still-running subagents for ordered delivery notes
137
-
138
- Important architectural property:
139
-
140
- - the registry is **in-memory only**
141
- - active subagents are therefore runtime-scoped, not globally persistent across process restarts
142
-
143
- However, per project rules, subagent session files themselves are intentionally not cleaned up, so post-hoc inspection through pi session history remains possible.
144
-
145
- ### 4.4 Delivery coordinator
146
-
147
- File:
148
-
149
- - `extension/runtime/delivery-coordinator.ts`
150
-
151
- This component solves one of the most important architecture problems in the extension: **how to deliver background results to the correct session at the correct time**.
23
+ `CrewRuntime` is a process-level singleton that survives pi runtime replacement (`/resume`, `/new`, `/fork`). When pi discards an old extension instance and creates a new one, the new instance reconnects to the same `crewRuntime` and picks up existing subagent state.
152
24
 
153
25
  Responsibilities:
154
26
 
155
- - track which pi session is currently active
156
- - know whether the active owner session is idle or already streaming
157
- - queue results for inactive owner sessions
158
- - flush queued results when the owner session becomes active again
159
- - preserve ordering between the main result message and the optional “remaining subagents” note
160
-
161
- This separation keeps delivery logic independent from spawning logic.
162
-
163
- ## 5. Integration with pi
164
-
165
- ### 5.1 Registered tools
166
-
167
- Files:
168
-
169
- - `extension/integration/register-tools.ts`
170
- - `extension/integration/tools/crew-list.ts`
171
- - `extension/integration/tools/crew-spawn.ts`
172
- - `extension/integration/tools/crew-abort.ts`
173
- - `extension/integration/tools/crew-respond.ts`
174
- - `extension/integration/tools/crew-done.ts`
175
-
176
- The extension registers five tools:
177
-
178
- - `crew_list`
179
- - `crew_spawn`
180
- - `crew_abort`
181
- - `crew_respond`
182
- - `crew_done`
183
-
184
- These are the primary public API for LLM-driven orchestration.
185
-
186
- Behavioral contracts:
187
-
188
- - `crew_list` shows discovered subagent definitions and active subagents owned by the current session
189
- - `crew_spawn` starts a non-blocking subagent owned by the current session
190
- - `crew_abort` can abort one, many, or all active subagents owned by the current session
191
- - `crew_respond` continues a waiting interactive subagent without blocking the caller session
192
- - `crew_done` closes a waiting interactive subagent without emitting a duplicate completion message
193
-
194
- ### 5.2 Registered command
195
-
196
- File:
197
-
198
- - `extension/integration/register-command.ts`
199
-
200
- The extension also registers the `/pi-crew-abort` command.
201
-
202
- This command differs from `crew_abort` in one important way:
203
-
204
- - it is intentionally unrestricted across sessions
205
-
206
- It exists as an emergency escape hatch. This is a deliberate operational tool, not an ownership-safe automation surface.
207
-
208
- ### 5.3 Custom message renderers
209
-
210
- Files:
211
-
212
- - `extension/integration/register-renderers.ts`
213
- - `extension/subagent-messages.ts`
214
-
215
- The extension defines two custom message types:
216
-
217
- - `crew-result`
218
- - `crew-remaining`
219
-
220
- These render in the TUI with custom formatting so asynchronous subagent output is readable and visually distinct from normal assistant text.
221
-
222
- ### 5.4 Status widget
223
-
224
- File:
225
-
226
- - `extension/status-widget.ts`
227
-
228
- When the current session owns active subagents, a live widget shows:
229
-
230
- - subagent ID
231
- - the latest assistant-reported model name, or `…` before the first assistant turn ends
232
- - turn count
233
- - the latest `assistant.usage.totalTokens` value, displayed as `ctx`
234
- - running vs waiting state
235
-
236
- This widget is session-scoped. It only shows subagents owned by the currently active session.
237
-
238
- ## 6. Subagent definition model
239
-
240
- ### 6.1 Discovery sources and priority
241
-
242
- File:
243
-
244
- - `extension/agent-discovery.ts`
245
-
246
- Subagent definitions are discovered from three directories in priority order:
247
-
248
- 1. **Project**: `<cwd>/.pi/agents/*.md`
249
- 2. **User global**: `~/.pi/agent/agents/*.md`
250
- 3. **Bundled**: `agents/` in the package
251
-
252
- When the same subagent name exists in multiple sources, the higher-priority source wins silently. Duplicate names within the same directory produce a warning.
253
-
254
- If a directory does not exist, it is skipped without warnings.
255
-
256
- ### 6.2 Definition format
257
-
258
- Each subagent is a Markdown file with YAML frontmatter plus a Markdown body.
259
-
260
- Frontmatter fields currently recognized by the runtime:
261
-
262
- - `name`
263
- - `description`
264
- - `model`
265
- - `thinking`
266
- - `tools`
267
- - `skills`
268
- - `compaction`
269
- - `interactive`
270
-
271
- The Markdown body becomes appended system prompt content for the spawned subagent session.
272
-
273
- ### 6.3 JSON override sources and precedence
274
-
275
- File:
276
-
277
- - `extension/agent-discovery.ts`
278
-
279
- After `.md` discovery, the runtime loads optional per-agent override config from two JSON files:
280
-
281
- - global: `~/.pi/agent/pi-crew.json`
282
- - project: `<cwd>/.pi/pi-crew.json`
283
-
284
- Only these fields are overridable:
285
-
286
- - `model`
287
- - `thinking`
288
- - `tools`
289
- - `skills`
290
- - `compaction`
291
- - `interactive`
292
-
293
- `name` and `description` are never overridable.
294
-
295
- Merge behavior:
296
-
297
- - global config is loaded first
298
- - project config is loaded second
299
- - project overrides global for the same subagent and field
300
- - if both files define the same subagent, unspecified fields from global remain unless project overrides them
301
-
302
- ### 6.4 Validation and fallback behavior
303
-
304
- Key behaviors implemented in discovery and bootstrap:
305
-
306
- - missing or empty `name` or `description` makes the definition invalid and it is ignored
307
- - names cannot contain whitespace
308
- - later duplicate names are skipped once an earlier valid definition with the same name has been loaded
309
- - `model` must use `provider/model-id` format to be considered valid
310
- - invalid model format is ignored for model resolution with a warning
311
- - invalid `thinking` values are ignored with a warning
312
- - invalid `tools` or `skills` field formats produce a warning and are treated as empty lists in frontmatter
313
- - unknown tools are filtered out with a warning
314
- - unknown skills are not part of discovery validation; when `skills` is present, bootstrap filters against the loaded skill set, omits unknown names, and writes a `console.warn`
315
- - non-boolean `compaction` or `interactive` values in frontmatter are ignored without a warning
316
-
317
- Override-specific validation behavior:
318
-
319
- - override entry value must be a JSON object
320
- - unknown override fields produce warnings
321
- - non-overridable fields (`name`, `description`) produce warnings
322
- - invalid field types in overrides produce warnings and are ignored
323
- - invalid `model`/`thinking` values in overrides produce warnings and are ignored
324
- - invalid `tools`/`skills` formats in overrides produce warnings and are ignored
325
- - unknown tool names in override `tools` produce warnings; valid names in the same list are still applied
326
- - override entries for undiscovered subagent names produce warnings and are ignored
327
-
328
- Important semantic distinction:
329
-
330
- - omitted `tools` means “use the full supported tool allowlist”
331
- - omitted `skills` means “do not install a `skillsOverride`, so all skills from the base resource loader remain available”
332
- - explicit empty `tools` or `skills` means “grant none”
333
-
334
- That distinction matters for both end users and coding agents authoring subagent definitions.
335
-
336
- ### 6.5 Supported tool set for spawned subagents
337
-
338
- File:
339
-
340
- - `extension/tool-registry.ts`
341
-
342
- The current built-in tool allowlist for spawned subagents is:
343
-
344
- - `read`
345
- - `bash`
346
- - `edit`
347
- - `write`
348
- - `grep`
349
- - `find`
350
- - `ls`
351
-
352
- Important limitation:
353
-
354
- - tool restriction here is a pi tool-resolution choice, not an OS sandbox boundary
355
- - for example, a “read-only” subagent remains read-only because of instruction and selected tool capabilities, not because of a kernel-level confinement model
356
-
357
- ## 7. Session bootstrapping and isolation
358
-
359
- ### 7.1 How a subagent session is created
360
-
361
- File:
362
-
363
- - `extension/bootstrap-session.ts`
364
-
365
- When `crew_spawn` is executed, the runtime does not clone the current conversation directly. It creates a new agent session with explicit configuration.
366
-
367
- Bootstrapping responsibilities:
368
-
369
- - resolve the target model
370
- - resolve the selected tool set
371
- - construct a `DefaultResourceLoader`
372
- - optionally filter skills
373
- - append the subagent system prompt body
374
- - create an in-memory settings manager for compaction settings
375
- - create a new `SessionManager`
376
- - call `sessionManager.newSession({ parentSession: parentSessionFile })` before creating the agent session
377
- - create the actual `AgentSession`
378
-
379
- ### 7.2 Parent-child session linkage
380
-
381
- A critical implementation rule is that the subagent session must be created through `SessionManager.newSession({ parentSession })`.
382
-
383
- The current caller session file is passed when one exists. This is the supported way to preserve parent-child linkage for resumable sessions. Project rules explicitly forbid creating subagent sessions through the wrong session factory because it breaks lifecycle expectations.
384
-
385
- Architectural rationale is documented in:
386
-
387
- - `AGENTS.md`
388
-
389
- ### 7.3 Preventing recursive orchestration
390
-
391
- One of the most important safety guards in the system is this:
392
-
393
- - spawned subagent sessions must not load the `pi-crew` extension again
394
-
395
- This is enforced by filtering the extension out through `extensionsOverride` inside the resource loader.
396
-
397
- Why it matters:
398
-
399
- - if a subagent can access `crew_spawn`, it can create more subagents
400
- - that creates recursive or runaway orchestration loops
401
- - preventing that at session bootstrap time is far safer than relying on prompt instructions alone
402
-
403
- ### 7.4 Model resolution
404
-
405
- The runtime resolves models in two stages:
406
-
407
- 1. if the subagent definition does not specify a valid parsed model, the caller session model is reused
408
- 2. if a model is specified but not found in the active pi model registry, the runtime falls back to the caller session model and writes a `console.warn`
409
-
410
- This keeps execution resilient to local model availability differences.
411
-
412
- ### 7.5 Compaction behavior
413
-
414
- Each subagent session gets its own in-memory settings manager.
415
-
416
- Behavior:
417
-
418
- - `compaction` defaults to `true` if omitted
419
- - a definition can explicitly disable it
420
-
421
- This setting is applied per spawned session and does not reuse the caller session's compaction setting.
422
-
423
- ## 8. Spawn lifecycle
424
-
425
- ### 8.1 High-level flow
426
-
427
- Relevant files:
428
-
429
- - `extension/integration/tools/crew-spawn.ts`
430
- - `extension/crew-manager.ts`
431
- - `extension/bootstrap-session.ts`
432
-
433
- Behavior sequence:
434
-
435
- 1. The `crew_spawn` tool handler calls `discoverAgents()` to load the current subagent definitions.
436
- 2. The requested subagent name is resolved against that discovery result.
437
- 3. The current session ID becomes the subagent owner ID.
438
- 4. `CrewManager.spawn()` creates a registry entry with status `running` and returns a runtime subagent ID immediately.
439
- 5. `CrewManager` starts asynchronous session bootstrap in the background.
440
- 6. Once bootstrapped, the new subagent session receives the task string as its prompt.
441
- 7. Completion or failure is delivered later as a `crew-result` custom message. If the owner session is already streaming, that message is delivered with `deliverAs: "steer"`.
442
-
443
- This immediate-return plus background-execution split is the key non-blocking contract of the extension.
444
-
445
- ### 8.2 Runtime metrics during execution
446
-
447
- `CrewManager` subscribes to subagent `turn_end` events.
448
-
449
- Tracked metrics include:
450
-
451
- - turn count, incremented on each `turn_end`
452
- - the latest `assistant.usage.totalTokens` value seen on a `turn_end`
453
- - the latest assistant-reported model name
454
-
455
- These metrics power the status widget and active subagent summaries.
456
-
457
- ### 8.3 Prompt outcome interpretation
458
-
459
- After a prompt cycle completes, the runtime inspects the last assistant message in the subagent session.
460
-
461
- Outcome mapping:
462
-
463
- - assistant stop reason `error` -> subagent status `error`
464
- - assistant stop reason `aborted` -> subagent status `aborted`
465
- - normal completion with `interactive: true` -> subagent status `waiting`
466
- - normal completion with non-interactive definition -> subagent status `done`
467
-
468
- This means interactive subagents and non-interactive subagents share the same prompt execution flow up to the final state transition.
469
-
470
- ## 9. Delivery model and message ordering
471
-
472
- ### 9.1 Owner-based routing
473
-
474
- The most important delivery rule is:
475
-
476
- - results belong to the session that spawned the subagent
477
-
478
- They do not belong to:
479
-
480
- - the currently visible session
481
- - the most recent session
482
- - the session that called a command later
483
-
484
- Ownership identity is based on the current session ID, not the session file path. This matters because unsaved or in-memory sessions may not have stable file paths.
485
-
486
- ### 9.2 Immediate vs deferred delivery
487
-
488
- Relevant files:
489
-
490
- - `extension/runtime/delivery-coordinator.ts`
491
- - `extension/index.ts`
492
-
493
- Delivery branches:
494
-
495
- - if the owner session is currently active, the result is sent immediately
496
- - if the owner session is not active, the result is queued in memory until that session becomes active again
497
-
498
- Queued results are flushed when the extension sees that owner session through:
499
-
500
- - `session_start` (with `reason: "resume"` or `reason: "fork"` for session switches)
501
-
502
- ### 9.3 Idle vs streaming session behavior
503
-
504
- pi requires different delivery semantics depending on whether the target session is idle or already processing output.
505
-
506
- Behavioral rule for a `crew-result` when no separate remaining-note ordering is needed:
507
-
508
- - idle owner session -> send with `triggerTurn: true`
509
- - streaming owner session -> send as steering content with `deliverAs: "steer"` and `triggerTurn: true`
510
-
511
- When an idle owner also needs a `crew-remaining` note, section 9.5 describes the deliberate `triggerTurn: false` / `true` split used to preserve message order.
512
-
513
- Why this distinction exists:
514
-
515
- - sending `deliverAs: "steer"` to an idle session can leave the message unprocessed because there is no active turn loop
516
- - when the owner session is already streaming, the extension injects the result into that active turn as steering content instead of using the idle-session delivery path
517
-
518
- This is one of the most subtle but important integration details in the extension.
519
-
520
- ### 9.4 Deferred flush timing
521
-
522
- Pending message flush after session activation is intentionally deferred to the next macrotask.
523
-
524
- Reason:
525
-
526
- - pi-core can emit `session_start` with `reason: "resume"` before reconnecting the agent listener during resume flows
527
- - synchronous message delivery at that moment can lose custom message persistence
528
-
529
- This is why queued results are flushed asynchronously instead of synchronously during session activation.
530
-
531
- ### 9.5 Result and remaining-note ordering
532
-
533
- Files:
534
-
535
- - `extension/subagent-messages.ts`
536
- - `extension/runtime/delivery-coordinator.ts`
537
-
538
- When a result is delivered and other subagents from the same owner are still in `running` state, the extension may send two messages:
539
-
540
- 1. the `crew-result`
541
- 2. a separate `crew-remaining` note
542
-
543
- They are intentionally separate messages.
544
-
545
- Why:
546
-
547
- - the result message should stay focused on one subagent outcome
548
- - the remaining count is transient orchestration state, not part of that result payload
549
-
550
- Ordering guarantee:
551
-
552
- - the result must appear before the remaining-note message
553
-
554
- When the owner is idle and other subagents are still running, the extension sends the `crew-result` with `triggerTurn: false`, then sends the remaining note with `triggerTurn: true` so the next turn processes both in order.
555
-
556
- When the owner is already streaming, the extension sends the `crew-result` first with `deliverAs: "steer"` and `triggerTurn: true`, then sends the `crew-remaining` note after it with `deliverAs: "steer"` and `triggerTurn: false`.
557
-
558
- The remaining count is computed at send time from the current registry state, not stored in the `crew-result` payload.
559
-
560
- ## 10. Interactive subagents
561
-
562
- ### 10.1 Waiting state
563
-
564
- Interactive subagents are defined with `interactive: true` in frontmatter.
565
-
566
- After a successful prompt cycle, they transition to `waiting` instead of `done`.
567
-
568
- Meaning of `waiting`:
569
-
570
- - the session remains alive
571
- - the subagent can receive follow-up messages
572
- - the status widget shows a waiting icon rather than a spinner
573
-
574
- ### 10.2 `crew_respond`
575
-
576
- Relevant files:
577
-
578
- - `extension/integration/tools/crew-respond.ts`
579
- - `extension/crew-manager.ts`
580
-
581
- Behavior:
582
-
583
- - validate that the subagent exists
584
- - validate that it belongs to the caller session
585
- - validate that it is in `waiting` state
586
- - mark it `running`
587
- - asynchronously send the follow-up prompt
588
- - return immediately to the caller
589
-
590
- This is deliberately fire-and-forget. The response comes later as another `crew-result` message.
591
-
592
- ### 10.3 `crew_done`
593
-
594
- Relevant files:
595
-
596
- - `extension/integration/tools/crew-done.ts`
597
- - `extension/crew-manager.ts`
598
-
599
- Behavior:
600
-
601
- - validate existence, ownership, and `waiting` state
602
- - dispose the session
603
- - remove the subagent from the registry
604
- - do **not** send another `crew-result` message
605
-
606
- That last point is essential. The latest subagent response was already delivered when it entered `waiting`. Sending another completion custom message on `crew_done` would duplicate signal and create an unnecessary turn.
607
-
608
- ## 11. Abort semantics
609
-
610
- ### 11.1 Supported abort paths
611
-
612
- There are three conceptually different abort sources:
613
-
614
- 1. tool-triggered aborts through `crew_abort`
615
- 2. unrestricted manual aborts through `/pi-crew-abort`
616
- 3. cleanup aborts when an owner session shuts down
617
-
618
- Each path should report the real reason.
619
-
620
- ### 11.2 Owned abort behavior
621
-
622
- Relevant files:
623
-
624
- - `extension/integration/tools/crew-abort.ts`
625
- - `extension/crew-manager.ts`
626
-
627
- `crew_abort` supports exactly one mode per call:
628
-
629
- - `subagent_id`
630
- - `subagent_ids`
631
- - `all: true`
632
-
633
- It only operates on subagents owned by the current session.
634
-
635
- The result separates:
636
-
637
- - actually aborted IDs
638
- - missing or already finished IDs
639
- - IDs that belong to another session
640
-
641
- ### 11.3 Unrestricted command abort
642
-
643
- Relevant file:
644
-
645
- - `extension/integration/register-command.ts`
646
-
647
- `/pi-crew-abort` can target any active abortable subagent, regardless of owner. This is not a bug. It is an explicit operational decision.
648
-
649
- ### 11.4 Session shutdown cleanup
650
-
651
- Relevant file:
652
-
653
- - `extension/index.ts`
654
-
655
- On `session_shutdown`, the extension:
656
-
657
- - aborts all abortable subagents currently owned by that session
658
- - clears pending queued messages for that owner
659
-
660
- This avoids memory leaks and prevents stale queued results from surviving after their owner session is gone.
661
-
662
- ## 12. Ownership and isolation rules
663
-
664
- These are core architecture invariants, not optional conventions.
665
-
666
- ### 12.1 Owner identity
667
-
668
- Owner identity uses the pi session ID.
669
-
670
- Why:
671
-
672
- - session file paths may be undefined for in-memory sessions
673
- - file-path-based ownership can collapse multiple live sessions into the same logical owner
674
-
675
- ### 12.2 Session-scoped visibility
676
-
677
- The following surfaces are ownership-restricted:
678
-
679
- - `crew_list` active subagent section
680
- - `crew_abort`
681
- - `crew_respond`
682
- - `crew_done`
683
- - status widget
684
- - owner cleanup on session shutdown
685
-
686
- This prevents cross-session interference in normal tool-driven workflows.
687
-
688
- ### 12.3 What is intentionally not isolated
689
-
690
- The emergency command `/pi-crew-abort` is intentionally cross-session.
691
-
692
- This is the only major exception to normal ownership isolation.
693
-
694
- ## 13. User-facing message model
695
-
696
- Relevant file:
697
-
698
- - `extension/subagent-messages.ts`
699
-
700
- Subagent outcome messaging is normalized into one common format.
701
-
702
- Every `crew-result` payload includes:
703
-
704
- - runtime subagent ID
705
- - logical subagent name
706
- - final status
707
- - an optional body derived from the subagent result or error
708
-
709
- In current completion and error paths, the runtime usually populates that body with assistant text, an error message, or `"(no output)"`.
710
-
711
- `crew-remaining` is simpler. It carries display text only and does not attach structured `details`.
712
-
713
- The `SubagentStatus` union currently includes:
714
-
715
- - `running`
716
- - `waiting`
717
- - `done`
718
- - `error`
719
- - `aborted`
720
-
721
- Current `crew-result` deliveries use `waiting`, `done`, `error`, or `aborted`. `running` is a live registry/widget state, not a completion message state.
722
-
723
- ## 14. Bundled subagents and prompt template
724
-
725
- ### 14.1 Bundled subagents
726
-
727
- Files:
728
-
729
- - `agents/scout.md`
730
- - `agents/planner.md`
731
- - `agents/oracle.md`
732
- - `agents/worker.md`
733
- - `agents/code-reviewer.md`
734
- - `agents/quality-reviewer.md`
735
-
736
- These are opinionated subagent definitions for common workflows.
737
-
738
- They demonstrate how the extension is intended to be used:
739
-
740
- - `scout` for quick investigation
741
- - `planner` for interactive planning
742
- - `oracle` for decision evaluation and blind spot detection
743
- - `worker` for implementation
744
- - `code-reviewer` for correctness review
745
- - `quality-reviewer` for maintainability review
746
-
747
- Architecturally, these files are not special-cased by the runtime. They are auto-discovered as the lowest-priority source (priority 3) and go through the same discovery and bootstrap pipeline as project-level or user-level definitions. Users can override any bundled subagent by placing a same-named `.md` file in `<cwd>/.pi/agents/` or `~/.pi/agent/agents/`.
748
-
749
- ### 14.2 Bundled plan orchestration prompt
750
-
751
- File:
752
-
753
- - `prompts/pi-crew-plan.md`
754
-
755
- This prompt template orchestrates discovery and planning workflow.
756
-
757
- It tells the orchestrating agent to:
758
-
759
- - gather minimal orientation context
760
- - spawn scout subagents to investigate specific areas
761
- - collect and synthesize scout findings
762
- - delegate planning to a planner subagent
763
- - relay the planner's output to the user
764
-
765
- The prompt enforces strict delegation boundaries:
766
-
767
- - the orchestrator must not perform deep investigation itself
768
- - the orchestrator must not write the plan itself
769
- - detailed discovery belongs to scouts
770
- - plan creation belongs to the planner
771
-
772
- ### 14.3 Bundled review orchestration prompt
773
-
774
- File:
775
-
776
- - `prompts/pi-crew-review.md`
27
+ - Create subagent state records
28
+ - Bootstrap isolated subagent sessions
29
+ - Transition subagents between states
30
+ - Deliver results to owner sessions
777
31
 
778
- This prompt template is a good example of how `pi-crew` is meant to be consumed by higher-level orchestration prompts.
32
+ ### 2.2 Delivery coordinator
779
33
 
780
- It does not bypass the extension. Instead, it tells the orchestrating agent to gather review scope with normal repo inspection tools, then use the public `crew_*` tool surface to:
34
+ Routes subagent results to the correct session at the correct time. Key behaviors:
781
35
 
782
- - verify required subagents exist
783
- - spawn reviewers in parallel
784
- - wait for both result messages
785
- - merge results into a final report
36
+ - Tracks active session via `ActiveRuntimeBinding` (set on `session_start`, cleared on `session_shutdown`)
37
+ - Queues results when owner session is inactive
38
+ - Flushes queued results when owner session activates (`session_start` with `reason: "resume"` or `"fork"`)
39
+ - Uses `triggerTurn: false/true` split to preserve ordering between `crew-result` and `crew-remaining`
786
40
 
787
- This separation is important:
41
+ Underlying delivery: see pi's `sendMessage({ deliverAs, triggerTurn })` in extensions.md.
788
42
 
789
- - the extension provides orchestration primitives
790
- - prompts provide workflow policy
43
+ ### 2.3 Subagent registry
791
44
 
792
- ## 15. Failure handling and diagnostics
45
+ In-memory, process-scoped: `Map<subagentId, SubagentState>`
793
46
 
794
- ### 15.1 Discovery warnings
47
+ - Owner session filtering
48
+ - Runtime ID generation (`<name>-<hex>`)
795
49
 
796
- Relevant files:
50
+ Does not persist across process restarts. Subagent session files remain for post-hoc inspection.
797
51
 
798
- - `extension/agent-discovery.ts`
799
- - `extension/integration/register-tools.ts`
52
+ ## 3. Session bootstrapping
800
53
 
801
- Invalid or partially invalid subagent definition files do not crash the extension.
54
+ When `crew_spawn` executes:
802
55
 
803
- Instead:
56
+ 1. Resolve subagent definition from discovery sources
57
+ 2. Resolve model (fallback to caller session model if invalid)
58
+ 3. Resolve tools, skills
59
+ 4. Create `DefaultResourceLoader` with `extensionsOverride` that excludes `pi-crew`
60
+ 5. Call `sessionManager.newSession({ parentSession })` for parent-child linkage
61
+ 6. Create `AgentSession` with resolved configuration
62
+ 7. Send task prompt asynchronously
804
63
 
805
- - discovery accumulates warnings
806
- - `crew_list` includes those warnings in its text output
807
- - `crew_list` and `crew_spawn` both trigger one-time UI notifications when a UI is available
64
+ **Extension filtering:** Subagent sessions must not load `pi-crew` again. Prevents recursive orchestration loops.
808
65
 
809
- This section covers discovery-time warnings only. Unknown skill names are warned later during bootstrap via `console.warn` in `extension/bootstrap-session.ts`.
66
+ ## 4. Delivery model
810
67
 
811
- This keeps misconfigured subagents visible without breaking healthy ones.
68
+ ### 4.1 Owner-based routing
812
69
 
813
- ### 15.2 Bootstrap failures
70
+ Results belong to the session that spawned the subagent. Owner identity uses `getSessionId()`, not file path (in-memory sessions have undefined paths).
814
71
 
815
- Bootstrap failures are settled as subagent `error` results.
72
+ ### 4.2 Idle vs streaming
816
73
 
817
- In practice, this covers exceptions thrown while preparing the resource loader or creating the subagent session.
74
+ Check owner session state before delivery:
818
75
 
819
- The important behavior is that a failed spawn still resolves into a clear terminal subagent result rather than silently disappearing.
76
+ - **Idle (`isIdle() = true`):** Send with `triggerTurn: true`
77
+ - **Streaming (`isIdle() = false`):** Send with `deliverAs: "steer"` and `triggerTurn: true`
820
78
 
821
- ### 15.3 Prompt execution failures
79
+ Critical: `deliverAs: "steer"` to an idle session leaves the message unprocessed (no active turn loop).
822
80
 
823
- Prompt-cycle failures are also normalized into terminal `error` or `aborted` outcomes and delivered through the same result channel.
81
+ ### 4.3 Deferred flush
824
82
 
825
- This gives downstream orchestrators a single message model to watch, regardless of where the failure occurred.
83
+ Pending message flush after `session_start` is deferred to next macrotask. Synchronous delivery loses custom message persistence (pi-core emits `session_start` before reconnecting agent listener during resume).
826
84
 
827
- ## 16. What persists and what does not
85
+ ### 4.4 TTL cleanup
828
86
 
829
- ### Persists
87
+ Pending messages older than 24 hours are discarded during `flushPending`.
830
88
 
831
- - extension package installation metadata
832
- - bundled prompt template availability
833
- - copied subagent definition files in `~/.pi/agent/agents/`
834
- - pi session history files created for subagents
89
+ ## 5. Subagent state lifecycle
835
90
 
836
- ### Does not persist across process restarts
91
+ ### 5.1 States
837
92
 
838
- - in-memory active subagent registry
839
- - in-memory pending delivery queue
840
- - live status widget state
93
+ - `running` - Actively processing
94
+ - `waiting` - Interactive subagent awaiting `crew_respond` or `crew_done`
95
+ - `done` - Completed successfully
96
+ - `error` - Failed with error
97
+ - `aborted` - Cancelled
841
98
 
842
- This distinction matters when designing higher-level workflows. `pi-crew` preserves session artifacts for inspection, but its live orchestration state is runtime-memory-based.
99
+ ### 5.2 State transitions
843
100
 
844
- ## 17. Behavioral invariants for future maintainers
101
+ After prompt cycle completion, inspect assistant stop reason:
845
102
 
846
- These are the behaviors future changes must preserve:
103
+ - `stopReason: "error"` status `error`
104
+ - `stopReason: "aborted"` → status `aborted`
105
+ - Normal completion + `interactive: true` → status `waiting`
106
+ - Normal completion + non-interactive → status `done`
847
107
 
848
- 1. A spawned subagent must not block the caller session.
849
- 2. Results must route to the owning session, not merely the currently active one.
850
- 3. Ownership must be based on session ID.
851
- 4. Subagent sessions must not load `pi-crew` again.
852
- 5. Interactive subagents must remain alive after responding until explicitly closed.
853
- 6. `crew_respond` must return immediately and deliver its result asynchronously later.
854
- 7. `crew_done` must clean up only and must not emit a duplicate result message.
855
- 8. When the owner session is inactive, result delivery must be queued and later flushed.
856
- 9. Result messages must appear before any “remaining subagents” note.
857
- 10. Session shutdown must abort owned abortable subagents and clear pending queued messages for that owner.
858
- 11. Tool ownership restrictions must remain strict, except for the emergency abort command.
108
+ ### 5.3 Interactive subagents
859
109
 
860
- These rules are the extension’s real architecture. File names may move, but these contracts should not.
110
+ `interactive: true` subagents enter `waiting` after each response. They accept follow-up messages via `crew_respond` until explicitly closed with `crew_done`. Closing does NOT emit a duplicate `crew-result`.
861
111
 
862
- ## 18. Reading guide for coding agents
112
+ ## 6. Ownership and isolation
863
113
 
864
- If you need to understand or change behavior, start in this order:
114
+ Invariants:
865
115
 
866
- 1. `README.md`
867
- Public product surface and user contract.
116
+ 1. `crew_list`, `crew_abort`, `crew_respond`, `crew_done`, status widget: session-scoped. Only owner sees/controls.
117
+ 2. `/pi-crew-abort`: cross-session emergency escape hatch.
118
+ 3. `session_shutdown` deactivates delivery binding only; subagents continue running. Abort happens on process exit.
868
119
 
869
- 2. `AGENTS.md`
870
- Non-obvious architecture guardrails that must not regress.
120
+ ## 7. Subagent definition model
871
121
 
872
- 3. `extension/index.ts`
873
- Extension bootstrap and session event wiring.
122
+ Discovery priority:
874
123
 
875
- 4. `extension/crew-manager.ts`
876
- Main orchestration and state transitions.
124
+ 1. Project: `<cwd>/.pi/agents/*.md`
125
+ 2. User global: `~/.pi/agent/agents/*.md`
126
+ 3. Bundled: `agents/` in package
877
127
 
878
- 5. `extension/runtime/delivery-coordinator.ts`
879
- Owner routing, queueing, and turn-trigger behavior.
128
+ Higher priority wins. Same-name duplicates in same directory produce warning.
880
129
 
881
- 6. `extension/bootstrap-session.ts`
882
- Session construction, model/tool/skill resolution, and extension filtering.
130
+ Frontmatter: `name`, `description`, `model`, `thinking`, `tools`, `skills`, `compaction`, `interactive`
883
131
 
884
- 7. `extension/agent-discovery.ts`
885
- Subagent definition semantics and validation rules.
132
+ Tools/skills semantics:
886
133
 
887
- 8. `extension/integration/`
888
- pi-facing tools, command, and renderers.
134
+ - **Omitted:** Use full supported allowlist
135
+ - **Empty list (`tools: []`):** Grant none
889
136
 
890
- 9. `agents/` and `prompts/`
891
- Real workflow examples built on top of the runtime.
137
+ JSON overrides: `~/.pi/agent/pi-crew.json` (global), `<cwd>/.pi/pi-crew.json` (project). Project wins.
892
138
 
893
- ## 19. Verification
139
+ ## 8. Behavioral invariants
894
140
 
895
- For implementation changes that affect runtime behavior, the project-level verification commands are:
141
+ 1. Spawned subagent must not block caller session.
142
+ 2. Results route to owning session (by ID), not currently active session.
143
+ 3. Subagent sessions must not load `pi-crew`.
144
+ 4. `crew_respond` returns immediately; result delivered asynchronously.
145
+ 5. `crew_done` cleans up only; no duplicate result message.
146
+ 6. Queued results flush when owner session becomes active.
147
+ 7. `crew-result` messages appear before `crew-remaining` notes (ordering via `triggerTurn` split).
148
+ 8. Pending messages preserved for inactive sessions; TTL (24h) prevents memory leak.
149
+ 9. Active subagent state survives runtime replacement within same process.
896
150
 
897
- - `npm run typecheck`
898
- - `npm run build`
151
+ ## 9. Reading guide
899
152
 
900
- Source:
153
+ 1. `README.md` - Product surface
154
+ 2. `AGENTS.md` - Architecture guardrails
155
+ 3. `extension/index.ts` - Session event wiring
156
+ 4. `extension/runtime/crew-runtime.ts` - Orchestration, state transitions
157
+ 5. `extension/runtime/delivery-coordinator.ts` - Owner routing, queueing
158
+ 6. `extension/bootstrap-session.ts` - Session construction
159
+ 7. `extension/agent-discovery.ts` - Definition validation
160
+ 8. `extension/integration/` - Tools, command, renderers
901
161
 
902
- - `AGENTS.md`
162
+ ## 10. Verification
903
163
 
904
- For documentation-only changes, these commands are usually unnecessary unless the change is coupled with code edits.
164
+ ```bash
165
+ npm run typecheck
166
+ npm run build
167
+ ```