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