pi-crew 0.1.37 → 0.1.39

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 (162) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +27 -0
  3. package/README.md +5 -0
  4. package/agents/analyst.md +11 -11
  5. package/agents/critic.md +11 -11
  6. package/agents/executor.md +11 -11
  7. package/agents/explorer.md +11 -11
  8. package/agents/planner.md +11 -11
  9. package/agents/reviewer.md +11 -11
  10. package/agents/security-reviewer.md +11 -11
  11. package/agents/test-engineer.md +11 -11
  12. package/agents/verifier.md +11 -11
  13. package/agents/writer.md +11 -11
  14. package/docs/refactor-tasks-phase3.md +394 -394
  15. package/docs/refactor-tasks-phase4.md +564 -564
  16. package/docs/refactor-tasks-phase5.md +402 -402
  17. package/docs/refactor-tasks-phase6.md +662 -662
  18. package/docs/research-extension-examples.md +297 -297
  19. package/docs/research-extension-system.md +324 -324
  20. package/docs/research-optimization-plan.md +548 -548
  21. package/docs/research-pi-coding-agent.md +357 -357
  22. package/docs/research-source-pi-crew-reference.md +174 -174
  23. package/docs/resource-formats.md +10 -8
  24. package/docs/runtime-flow.md +148 -148
  25. package/docs/source-runtime-refactor-map.md +83 -83
  26. package/docs/usage.md +6 -0
  27. package/index.ts +6 -6
  28. package/package.json +3 -3
  29. package/schema.json +2 -2
  30. package/src/agents/agent-serializer.ts +34 -34
  31. package/src/config/config.ts +8 -4
  32. package/src/extension/cross-extension-rpc.ts +82 -82
  33. package/src/extension/import-index.ts +18 -2
  34. package/src/extension/register.ts +11 -1
  35. package/src/extension/registration/compaction-guard.ts +125 -125
  36. package/src/extension/registration/subagent-helpers.ts +30 -6
  37. package/src/extension/registration/subagent-tools.ts +8 -3
  38. package/src/extension/result-watcher.ts +98 -98
  39. package/src/extension/run-import.ts +12 -2
  40. package/src/extension/run-index.ts +12 -2
  41. package/src/extension/run-maintenance.ts +24 -24
  42. package/src/extension/team-tool/api.ts +54 -14
  43. package/src/extension/team-tool/cancel.ts +31 -31
  44. package/src/extension/team-tool/doctor.ts +179 -179
  45. package/src/extension/team-tool/inspect.ts +41 -41
  46. package/src/extension/team-tool/lifecycle-actions.ts +79 -79
  47. package/src/extension/team-tool/plan.ts +19 -19
  48. package/src/extension/team-tool/status.ts +73 -73
  49. package/src/observability/correlation.ts +35 -35
  50. package/src/observability/event-to-metric.ts +54 -54
  51. package/src/observability/exporters/adapter.ts +24 -24
  52. package/src/observability/exporters/otlp-exporter.ts +65 -65
  53. package/src/observability/exporters/prometheus-exporter.ts +47 -47
  54. package/src/observability/metric-registry.ts +72 -72
  55. package/src/observability/metric-retention.ts +46 -46
  56. package/src/observability/metric-sink.ts +51 -51
  57. package/src/observability/metrics-primitives.ts +166 -166
  58. package/src/prompt/prompt-runtime.ts +68 -68
  59. package/src/runtime/agent-control.ts +64 -64
  60. package/src/runtime/agent-memory.ts +72 -72
  61. package/src/runtime/agent-observability.ts +114 -113
  62. package/src/runtime/async-marker.ts +26 -26
  63. package/src/runtime/background-runner.ts +53 -53
  64. package/src/runtime/crash-recovery.ts +56 -56
  65. package/src/runtime/crew-agent-records.ts +54 -9
  66. package/src/runtime/crew-agent-runtime.ts +58 -58
  67. package/src/runtime/deadletter.ts +36 -36
  68. package/src/runtime/direct-run.ts +35 -35
  69. package/src/runtime/foreground-control.ts +82 -82
  70. package/src/runtime/green-contract.ts +46 -46
  71. package/src/runtime/group-join.ts +88 -88
  72. package/src/runtime/heartbeat-gradient.ts +28 -28
  73. package/src/runtime/heartbeat-watcher.ts +80 -80
  74. package/src/runtime/live-agent-control.ts +87 -78
  75. package/src/runtime/live-agent-manager.ts +85 -85
  76. package/src/runtime/live-control-realtime.ts +36 -36
  77. package/src/runtime/live-session-runtime.ts +299 -299
  78. package/src/runtime/manifest-cache.ts +248 -212
  79. package/src/runtime/model-fallback.ts +261 -261
  80. package/src/runtime/parallel-research.ts +44 -44
  81. package/src/runtime/parallel-utils.ts +99 -99
  82. package/src/runtime/pi-json-output.ts +111 -111
  83. package/src/runtime/policy-engine.ts +78 -78
  84. package/src/runtime/post-exit-stdio-guard.ts +86 -86
  85. package/src/runtime/process-status.ts +56 -56
  86. package/src/runtime/progress-event-coalescer.ts +43 -43
  87. package/src/runtime/recovery-recipes.ts +74 -74
  88. package/src/runtime/retry-executor.ts +59 -59
  89. package/src/runtime/role-permission.ts +39 -39
  90. package/src/runtime/session-usage.ts +79 -79
  91. package/src/runtime/sidechain-output.ts +28 -28
  92. package/src/runtime/subagent-manager.ts +80 -12
  93. package/src/runtime/task-display.ts +38 -38
  94. package/src/runtime/task-output-context.ts +127 -106
  95. package/src/runtime/task-runner/live-executor.ts +98 -98
  96. package/src/runtime/task-runner/progress.ts +111 -111
  97. package/src/runtime/task-runner/result-utils.ts +14 -14
  98. package/src/runtime/task-runner/state-helpers.ts +22 -22
  99. package/src/runtime/team-runner.ts +1 -1
  100. package/src/runtime/worker-heartbeat.ts +21 -21
  101. package/src/runtime/worker-startup.ts +57 -57
  102. package/src/schema/config-schema.ts +21 -21
  103. package/src/schema/team-tool-schema.ts +100 -100
  104. package/src/state/artifact-store.ts +122 -108
  105. package/src/state/contracts.ts +105 -105
  106. package/src/state/jsonl-writer.ts +77 -77
  107. package/src/state/mailbox.ts +67 -22
  108. package/src/state/state-store.ts +36 -5
  109. package/src/state/task-claims.ts +42 -42
  110. package/src/state/usage.ts +29 -29
  111. package/src/subagents/async-entry.ts +1 -1
  112. package/src/subagents/index.ts +3 -3
  113. package/src/subagents/live/control.ts +1 -1
  114. package/src/subagents/live/manager.ts +1 -1
  115. package/src/subagents/live/realtime.ts +1 -1
  116. package/src/subagents/live/session-runtime.ts +1 -1
  117. package/src/subagents/manager.ts +1 -1
  118. package/src/subagents/spawn.ts +1 -1
  119. package/src/teams/discover-teams.ts +27 -5
  120. package/src/teams/team-serializer.ts +38 -36
  121. package/src/types/diff.d.ts +18 -18
  122. package/src/ui/crew-footer.ts +101 -101
  123. package/src/ui/crew-select-list.ts +111 -111
  124. package/src/ui/dashboard-panes/metrics-pane.ts +34 -34
  125. package/src/ui/dynamic-border.ts +25 -25
  126. package/src/ui/layout-primitives.ts +106 -106
  127. package/src/ui/loaders.ts +158 -158
  128. package/src/ui/mascot.ts +441 -441
  129. package/src/ui/render-diff.ts +119 -119
  130. package/src/ui/run-dashboard.ts +5 -2
  131. package/src/ui/run-snapshot-cache.ts +19 -8
  132. package/src/ui/spinner.ts +17 -17
  133. package/src/ui/status-colors.ts +54 -54
  134. package/src/ui/syntax-highlight.ts +116 -116
  135. package/src/ui/transcript-viewer.ts +15 -1
  136. package/src/utils/completion-dedupe.ts +63 -63
  137. package/src/utils/file-coalescer.ts +84 -84
  138. package/src/utils/frontmatter.ts +36 -36
  139. package/src/utils/fs-watch.ts +31 -31
  140. package/src/utils/git.ts +262 -262
  141. package/src/utils/ids.ts +12 -12
  142. package/src/utils/names.ts +26 -26
  143. package/src/utils/paths.ts +3 -2
  144. package/src/utils/safe-paths.ts +34 -0
  145. package/src/utils/sleep.ts +32 -32
  146. package/src/utils/timings.ts +31 -31
  147. package/src/utils/visual.ts +159 -159
  148. package/src/workflows/discover-workflows.ts +30 -3
  149. package/src/workflows/validate-workflow.ts +40 -40
  150. package/src/worktree/branch-freshness.ts +45 -45
  151. package/teams/default.team.md +12 -12
  152. package/teams/fast-fix.team.md +11 -11
  153. package/teams/implementation.team.md +18 -18
  154. package/teams/parallel-research.team.md +14 -14
  155. package/teams/research.team.md +11 -11
  156. package/teams/review.team.md +12 -12
  157. package/workflows/default.workflow.md +29 -29
  158. package/workflows/fast-fix.workflow.md +22 -22
  159. package/workflows/implementation.workflow.md +38 -38
  160. package/workflows/parallel-research.workflow.md +46 -46
  161. package/workflows/research.workflow.md +22 -22
  162. package/workflows/review.workflow.md +30 -30
@@ -1,297 +1,297 @@
1
- # Research: Extension Examples & Patterns
2
-
3
- > Ngày: 2026-04-29 | Read-only research | Source: `source/pi-mono/packages/coding-agent/examples/extensions/`
4
-
5
- ## 1. Example Catalog (86 files, 60+ extensions)
6
-
7
- ### 1.1 Sorted by relevance to pi-crew
8
-
9
- | Priority | Example | Relevance |
10
- |---|---|---|
11
- | ⭐⭐⭐ | `subagent/` | Most similar to pi-crew: child Pi spawning, parallel, chain |
12
- | ⭐⭐⭐ | `custom-compaction.ts` | Hook compaction — useful for preserving run state |
13
- | ⭐⭐⭐ | `event-bus.ts` | Cross-extension communication pattern |
14
- | ⭐⭐⭐ | `plan-mode/` | State persistence, dynamic tools, widget management |
15
- | ⭐⭐⭐ | `structured-output.ts` | `terminate: true` — save LLM turns |
16
- | ⭐⭐ | `handoff.ts` | Context transfer to new session |
17
- | ⭐⭐ | `dynamic-tools.ts` | Register tools at runtime |
18
- | ⭐⭐ | `permission-gate.ts` | Gate dangerous operations |
19
- | ⭐⭐ | `trigger-compact.ts` | Proactive compaction monitoring |
20
- | ⭐⭐ | `send-user-message.ts` | sendUserMessage pattern |
21
- | ⭐ | `dirty-repo-guard.ts` | Guard against uncommitted changes |
22
- | ⭐ | `model-status.ts` | Model status in footer |
23
- | ⭐ | `confirm-destructive.ts` | Confirm destructive operations |
24
-
25
- ## 2. Deep Analysis of Key Examples
26
-
27
- ### 2.1 subagent/ — The Reference Implementation
28
-
29
- **Files:**
30
- - `index.ts` (~530 dòng): Main tool with execute + render
31
- - `agents.ts` (~130 dòng): Agent discovery (user/project scope)
32
-
33
- **Architecture:**
34
- ```
35
- subagent tool
36
- ├── Single: runSingleAgent() → spawn pi --mode json -p
37
- ├── Parallel: mapWithConcurrencyLimit(tasks, 4, runSingleAgent)
38
- └── Chain: sequential loop with {previous} placeholder
39
- ```
40
-
41
- **Key patterns:**
42
- - Agent discovery: `discoverAgents(cwd, scope)` — scans `.md` files with YAML frontmatter
43
- - Child process: `getPiInvocation()` detects current runtime (node/bun/pi binary)
44
- - Streaming: `onUpdate` callback for partial results during execution
45
- - Render: `renderCall()` + `renderResult()` with collapsed/expanded views
46
- - Abort: AbortSignal propagated to child process
47
-
48
- **What pi-crew does better:**
49
- - Durable state (manifest, tasks, events) instead of in-memory only
50
- - Team/workflow abstraction instead of flat agent list
51
- - Task graph with DAG dependencies instead of linear chain
52
- - Async background runner with PID tracking
53
- - Policy engine for limits/retry/escalation
54
- - Mailbox for inter-task communication
55
- - Worktree isolation per task
56
-
57
- **What pi-crew could adopt from this:**
58
- - `terminate: true` on final results (not used in example either, but available)
59
- - `renderCall/Result` custom rendering patterns
60
- - `mapWithConcurrencyLimit` pattern (pi-crew already has similar)
61
-
62
- ### 2.2 custom-compaction.ts — Custom Compaction
63
-
64
- **Pattern:**
65
- ```typescript
66
- pi.on("session_before_compact", async (event, ctx) => {
67
- // 1. Get preparation data
68
- const { messagesToSummarize, turnPrefixMessages, tokensBefore, firstKeptEntryId } = event.preparation;
69
-
70
- // 2. Use different model for summarization (cheaper)
71
- const model = ctx.modelRegistry.find("google", "gemini-2.5-flash");
72
-
73
- // 3. Custom prompt
74
- const summary = await complete(model, { messages: [...] }, { apiKey, signal });
75
-
76
- // 4. Return custom compaction result
77
- return {
78
- compaction: { summary, firstKeptEntryId, tokensBefore }
79
- };
80
- });
81
- ```
82
-
83
- **Relevance to pi-crew:**
84
- - Can use cheap model to summarize completed tasks
85
- - Can protect foreground runs from being compacted mid-execution
86
- - Can store structured artifact index in compaction `details`
87
-
88
- ### 2.3 event-bus.ts — Cross-Extension Communication
89
-
90
- **Pattern:**
91
- ```typescript
92
- // Extension A: emit events
93
- pi.events.emit("my:notification", { message: "hello", from: "ext-a" });
94
-
95
- // Extension B: listen
96
- pi.events.on("my:notification", (data) => {
97
- currentCtx?.ui.notify(`Event from ${data.from}: ${data.message}`);
98
- });
99
- ```
100
-
101
- **Relevance to pi-crew:**
102
- - Already used for internal events (`subagent.stuck-blocked`)
103
- - Could publish structured events for other extensions to consume:
104
- - `pi-crew:run:completed`
105
- - `pi-crew:subagent:completed`
106
- - `pi-crew:run:failed`
107
-
108
- ### 2.4 plan-mode/ — State Persistence + Dynamic Tools
109
-
110
- **Key patterns:**
111
-
112
- State persistence:
113
- ```typescript
114
- // Save
115
- pi.appendEntry("plan-mode", { enabled, todos, executing });
116
-
117
- // Restore on session_start
118
- const entries = ctx.sessionManager.getEntries();
119
- const state = entries
120
- .filter(e => e.type === "custom" && e.customType === "plan-mode")
121
- .pop()?.data;
122
- ```
123
-
124
- Dynamic tools:
125
- ```typescript
126
- // Switch between tool sets
127
- if (planModeEnabled) {
128
- pi.setActiveTools(["read", "bash", "grep", "find", "ls"]);
129
- } else {
130
- pi.setActiveTools(["read", "bash", "edit", "write"]);
131
- }
132
- ```
133
-
134
- Tool call gate:
135
- ```typescript
136
- pi.on("tool_call", async (event) => {
137
- if (planModeEnabled && event.toolName === "bash") {
138
- if (!isSafeCommand(event.input.command)) {
139
- return { block: true, reason: "..." };
140
- }
141
- }
142
- });
143
- ```
144
-
145
- **Relevance to pi-crew:**
146
- - `pi.appendEntry` pattern for cross-session run awareness
147
- - `pi.setActiveTools` could be used to restrict tools during team runs
148
- - `tool_call` gate for destructive team actions
149
-
150
- ### 2.5 structured-output.ts — terminate: true
151
-
152
- **Pattern:**
153
- ```typescript
154
- async execute(_toolCallId, params) {
155
- return {
156
- content: [{ type: "text", text: "Done" }],
157
- details: { headline, summary, actionItems },
158
- terminate: true, // ← No follow-up LLM turn needed
159
- };
160
- }
161
- ```
162
-
163
- **Relevance to pi-crew:**
164
- - `Agent` tool results could use `terminate: true` when background run queued
165
- - `get_subagent_result` could terminate when result is final
166
- - `team` tool status/list/recommend actions could terminate
167
-
168
- ### 2.6 handoff.ts — Context Transfer to New Session
169
-
170
- **Pattern:**
171
- ```typescript
172
- // 1. Extract conversation context
173
- const messages = ctx.sessionManager.getBranch()
174
- .filter(e => e.type === "message")
175
- .map(e => e.message);
176
-
177
- // 2. Generate focused prompt
178
- const prompt = await complete(model, { systemPrompt, messages }, { apiKey });
179
-
180
- // 3. Create new session with pre-filled editor
181
- await ctx.newSession({
182
- parentSession: currentSessionFile,
183
- withSession: async (replacementCtx) => {
184
- replacementCtx.ui.setEditorText(prompt);
185
- },
186
- });
187
- ```
188
-
189
- **Relevance to pi-crew:**
190
- - When a task in a team run needs isolated context, could handoff to new session
191
- - Parent session tracking via `parentSession`
192
-
193
- ### 2.7 permission-gate.ts — Dangerous Operation Gate
194
-
195
- **Pattern:**
196
- ```typescript
197
- pi.on("tool_call", async (event, ctx) => {
198
- if (event.toolName !== "bash") return;
199
- if (isDangerousPattern(event.input.command)) {
200
- const choice = await ctx.ui.select("Allow?", ["Yes", "No"]);
201
- if (choice !== "Yes") {
202
- return { block: true, reason: "Blocked by user" };
203
- }
204
- }
205
- });
206
- ```
207
-
208
- **Relevance to pi-crew:**
209
- - Gate destructive team actions (delete, forget, prune)
210
- - Only allow with explicit `confirm: true` parameter
211
-
212
- ### 2.8 trigger-compact.ts — Proactive Compaction
213
-
214
- **Pattern:**
215
- ```typescript
216
- pi.on("turn_end", (_event, ctx) => {
217
- const usage = ctx.getContextUsage();
218
- if (usage?.tokens && usage.tokens > THRESHOLD) {
219
- ctx.compact({ customInstructions: "..." });
220
- }
221
- });
222
- ```
223
-
224
- **Relevance to pi-crew:**
225
- - Monitor context during long team runs
226
- - Auto-compact before hitting overflow errors
227
- - Use compact's callback to track state
228
-
229
- ## 3. Pattern Summary
230
-
231
- ### 3.1 Patterns pi-crew already implements well
232
-
233
- | Pattern | pi-crew implementation |
234
- |---|---|
235
- | Child Pi spawning | `SubagentManager` + `spawn.ts` with full process management |
236
- | Parallel execution | `mapConcurrent` in team runner |
237
- | State persistence | Durable file-based (manifest, tasks, events, artifacts) |
238
- | Widget rendering | `CrewWidget`, `LiveRunSidebar`, `Powerbar` |
239
- | Lifecycle hooks | `session_start`, `session_before_switch`, `session_shutdown` |
240
- | Config merge | `loadConfig` with user/project priority |
241
- | Abort propagation | `AbortController` trees in foreground runs |
242
-
243
- ### 3.2 Patterns pi-crew could adopt
244
-
245
- | Pattern | Current status | Recommendation |
246
- |---|---|---|
247
- | `terminate: true` | ❌ Not used | Add to Agent/get_subagent_result |
248
- | `session_before_compact` hook | ❌ Not hooked | Cancel compact during foreground runs |
249
- | Custom compaction model | ❌ Not used | Use Haiku/Gemini Flash for task summaries |
250
- | `pi.events` publish | ⚠️ Internal only | Add public structured events |
251
- | `pi.appendEntry` | ❌ Not used | Cross-session run references |
252
- | `tool_call` permission gate | ❌ Not gated | Gate destructive team actions |
253
- | Config-driven tool registration | ❌ Always all | Register tools per config |
254
- | Working indicator | ❌ Widget only | Use `ctx.ui.setWorkingIndicator` |
255
- | Session name auto-set | ❌ Manual only | Auto-name from team run context |
256
- | `ctx.compact()` proactive | ❌ No monitoring | Monitor + auto-compact at threshold |
257
-
258
- ## 4. Example: Complete Tool with terminate + render
259
-
260
- This shows a hypothetical optimized pi-crew Agent tool:
261
-
262
- ```typescript
263
- // OPTIMIZED Agent tool pattern
264
- const AgentTool = defineTool({
265
- name: "Agent",
266
- label: "Agent",
267
- description: "Launch a real pi-crew subagent...",
268
- parameters: Type.Object({
269
- prompt: Type.String(),
270
- description: Type.String(),
271
- subagent_type: Type.String(),
272
- run_in_background: Type.Optional(Type.Boolean()),
273
- }),
274
- async execute(_id, params, signal, _onUpdate, ctx) {
275
- // ... spawn subagent ...
276
- if (params.run_in_background) {
277
- return {
278
- content: [{ type: "text", text: `Agent queued. ID: ${record.id}` }],
279
- details: { agentId: record.id, status: "queued" },
280
- terminate: true, // ← No need for LLM follow-up
281
- };
282
- }
283
- await record.promise;
284
- const output = readResult(record);
285
- return {
286
- content: [{ type: "text", text: output }],
287
- details: { agentId: record.id, status: record.status },
288
- terminate: true, // ← Final result, save LLM turn
289
- };
290
- },
291
- renderResult(result, { expanded }, theme) {
292
- // Custom rendering with colored status icons
293
- // Collapsed/expanded views
294
- // Usage stats display
295
- },
296
- });
297
- ```
1
+ # Research: Extension Examples & Patterns
2
+
3
+ > Ngày: 2026-04-29 | Read-only research | Source: `source/pi-mono/packages/coding-agent/examples/extensions/`
4
+
5
+ ## 1. Example Catalog (86 files, 60+ extensions)
6
+
7
+ ### 1.1 Sorted by relevance to pi-crew
8
+
9
+ | Priority | Example | Relevance |
10
+ |---|---|---|
11
+ | ⭐⭐⭐ | `subagent/` | Most similar to pi-crew: child Pi spawning, parallel, chain |
12
+ | ⭐⭐⭐ | `custom-compaction.ts` | Hook compaction — useful for preserving run state |
13
+ | ⭐⭐⭐ | `event-bus.ts` | Cross-extension communication pattern |
14
+ | ⭐⭐⭐ | `plan-mode/` | State persistence, dynamic tools, widget management |
15
+ | ⭐⭐⭐ | `structured-output.ts` | `terminate: true` — save LLM turns |
16
+ | ⭐⭐ | `handoff.ts` | Context transfer to new session |
17
+ | ⭐⭐ | `dynamic-tools.ts` | Register tools at runtime |
18
+ | ⭐⭐ | `permission-gate.ts` | Gate dangerous operations |
19
+ | ⭐⭐ | `trigger-compact.ts` | Proactive compaction monitoring |
20
+ | ⭐⭐ | `send-user-message.ts` | sendUserMessage pattern |
21
+ | ⭐ | `dirty-repo-guard.ts` | Guard against uncommitted changes |
22
+ | ⭐ | `model-status.ts` | Model status in footer |
23
+ | ⭐ | `confirm-destructive.ts` | Confirm destructive operations |
24
+
25
+ ## 2. Deep Analysis of Key Examples
26
+
27
+ ### 2.1 subagent/ — The Reference Implementation
28
+
29
+ **Files:**
30
+ - `index.ts` (~530 dòng): Main tool with execute + render
31
+ - `agents.ts` (~130 dòng): Agent discovery (user/project scope)
32
+
33
+ **Architecture:**
34
+ ```
35
+ subagent tool
36
+ ├── Single: runSingleAgent() → spawn pi --mode json -p
37
+ ├── Parallel: mapWithConcurrencyLimit(tasks, 4, runSingleAgent)
38
+ └── Chain: sequential loop with {previous} placeholder
39
+ ```
40
+
41
+ **Key patterns:**
42
+ - Agent discovery: `discoverAgents(cwd, scope)` — scans `.md` files with YAML frontmatter
43
+ - Child process: `getPiInvocation()` detects current runtime (node/bun/pi binary)
44
+ - Streaming: `onUpdate` callback for partial results during execution
45
+ - Render: `renderCall()` + `renderResult()` with collapsed/expanded views
46
+ - Abort: AbortSignal propagated to child process
47
+
48
+ **What pi-crew does better:**
49
+ - Durable state (manifest, tasks, events) instead of in-memory only
50
+ - Team/workflow abstraction instead of flat agent list
51
+ - Task graph with DAG dependencies instead of linear chain
52
+ - Async background runner with PID tracking
53
+ - Policy engine for limits/retry/escalation
54
+ - Mailbox for inter-task communication
55
+ - Worktree isolation per task
56
+
57
+ **What pi-crew could adopt from this:**
58
+ - `terminate: true` on final results (not used in example either, but available)
59
+ - `renderCall/Result` custom rendering patterns
60
+ - `mapWithConcurrencyLimit` pattern (pi-crew already has similar)
61
+
62
+ ### 2.2 custom-compaction.ts — Custom Compaction
63
+
64
+ **Pattern:**
65
+ ```typescript
66
+ pi.on("session_before_compact", async (event, ctx) => {
67
+ // 1. Get preparation data
68
+ const { messagesToSummarize, turnPrefixMessages, tokensBefore, firstKeptEntryId } = event.preparation;
69
+
70
+ // 2. Use different model for summarization (cheaper)
71
+ const model = ctx.modelRegistry.find("google", "gemini-2.5-flash");
72
+
73
+ // 3. Custom prompt
74
+ const summary = await complete(model, { messages: [...] }, { apiKey, signal });
75
+
76
+ // 4. Return custom compaction result
77
+ return {
78
+ compaction: { summary, firstKeptEntryId, tokensBefore }
79
+ };
80
+ });
81
+ ```
82
+
83
+ **Relevance to pi-crew:**
84
+ - Can use cheap model to summarize completed tasks
85
+ - Can protect foreground runs from being compacted mid-execution
86
+ - Can store structured artifact index in compaction `details`
87
+
88
+ ### 2.3 event-bus.ts — Cross-Extension Communication
89
+
90
+ **Pattern:**
91
+ ```typescript
92
+ // Extension A: emit events
93
+ pi.events.emit("my:notification", { message: "hello", from: "ext-a" });
94
+
95
+ // Extension B: listen
96
+ pi.events.on("my:notification", (data) => {
97
+ currentCtx?.ui.notify(`Event from ${data.from}: ${data.message}`);
98
+ });
99
+ ```
100
+
101
+ **Relevance to pi-crew:**
102
+ - Already used for internal events (`subagent.stuck-blocked`)
103
+ - Could publish structured events for other extensions to consume:
104
+ - `pi-crew:run:completed`
105
+ - `pi-crew:subagent:completed`
106
+ - `pi-crew:run:failed`
107
+
108
+ ### 2.4 plan-mode/ — State Persistence + Dynamic Tools
109
+
110
+ **Key patterns:**
111
+
112
+ State persistence:
113
+ ```typescript
114
+ // Save
115
+ pi.appendEntry("plan-mode", { enabled, todos, executing });
116
+
117
+ // Restore on session_start
118
+ const entries = ctx.sessionManager.getEntries();
119
+ const state = entries
120
+ .filter(e => e.type === "custom" && e.customType === "plan-mode")
121
+ .pop()?.data;
122
+ ```
123
+
124
+ Dynamic tools:
125
+ ```typescript
126
+ // Switch between tool sets
127
+ if (planModeEnabled) {
128
+ pi.setActiveTools(["read", "bash", "grep", "find", "ls"]);
129
+ } else {
130
+ pi.setActiveTools(["read", "bash", "edit", "write"]);
131
+ }
132
+ ```
133
+
134
+ Tool call gate:
135
+ ```typescript
136
+ pi.on("tool_call", async (event) => {
137
+ if (planModeEnabled && event.toolName === "bash") {
138
+ if (!isSafeCommand(event.input.command)) {
139
+ return { block: true, reason: "..." };
140
+ }
141
+ }
142
+ });
143
+ ```
144
+
145
+ **Relevance to pi-crew:**
146
+ - `pi.appendEntry` pattern for cross-session run awareness
147
+ - `pi.setActiveTools` could be used to restrict tools during team runs
148
+ - `tool_call` gate for destructive team actions
149
+
150
+ ### 2.5 structured-output.ts — terminate: true
151
+
152
+ **Pattern:**
153
+ ```typescript
154
+ async execute(_toolCallId, params) {
155
+ return {
156
+ content: [{ type: "text", text: "Done" }],
157
+ details: { headline, summary, actionItems },
158
+ terminate: true, // ← No follow-up LLM turn needed
159
+ };
160
+ }
161
+ ```
162
+
163
+ **Relevance to pi-crew:**
164
+ - `Agent` tool results could use `terminate: true` when background run queued
165
+ - `get_subagent_result` could terminate when result is final
166
+ - `team` tool status/list/recommend actions could terminate
167
+
168
+ ### 2.6 handoff.ts — Context Transfer to New Session
169
+
170
+ **Pattern:**
171
+ ```typescript
172
+ // 1. Extract conversation context
173
+ const messages = ctx.sessionManager.getBranch()
174
+ .filter(e => e.type === "message")
175
+ .map(e => e.message);
176
+
177
+ // 2. Generate focused prompt
178
+ const prompt = await complete(model, { systemPrompt, messages }, { apiKey });
179
+
180
+ // 3. Create new session with pre-filled editor
181
+ await ctx.newSession({
182
+ parentSession: currentSessionFile,
183
+ withSession: async (replacementCtx) => {
184
+ replacementCtx.ui.setEditorText(prompt);
185
+ },
186
+ });
187
+ ```
188
+
189
+ **Relevance to pi-crew:**
190
+ - When a task in a team run needs isolated context, could handoff to new session
191
+ - Parent session tracking via `parentSession`
192
+
193
+ ### 2.7 permission-gate.ts — Dangerous Operation Gate
194
+
195
+ **Pattern:**
196
+ ```typescript
197
+ pi.on("tool_call", async (event, ctx) => {
198
+ if (event.toolName !== "bash") return;
199
+ if (isDangerousPattern(event.input.command)) {
200
+ const choice = await ctx.ui.select("Allow?", ["Yes", "No"]);
201
+ if (choice !== "Yes") {
202
+ return { block: true, reason: "Blocked by user" };
203
+ }
204
+ }
205
+ });
206
+ ```
207
+
208
+ **Relevance to pi-crew:**
209
+ - Gate destructive team actions (delete, forget, prune)
210
+ - Only allow with explicit `confirm: true` parameter
211
+
212
+ ### 2.8 trigger-compact.ts — Proactive Compaction
213
+
214
+ **Pattern:**
215
+ ```typescript
216
+ pi.on("turn_end", (_event, ctx) => {
217
+ const usage = ctx.getContextUsage();
218
+ if (usage?.tokens && usage.tokens > THRESHOLD) {
219
+ ctx.compact({ customInstructions: "..." });
220
+ }
221
+ });
222
+ ```
223
+
224
+ **Relevance to pi-crew:**
225
+ - Monitor context during long team runs
226
+ - Auto-compact before hitting overflow errors
227
+ - Use compact's callback to track state
228
+
229
+ ## 3. Pattern Summary
230
+
231
+ ### 3.1 Patterns pi-crew already implements well
232
+
233
+ | Pattern | pi-crew implementation |
234
+ |---|---|
235
+ | Child Pi spawning | `SubagentManager` + `spawn.ts` with full process management |
236
+ | Parallel execution | `mapConcurrent` in team runner |
237
+ | State persistence | Durable file-based (manifest, tasks, events, artifacts) |
238
+ | Widget rendering | `CrewWidget`, `LiveRunSidebar`, `Powerbar` |
239
+ | Lifecycle hooks | `session_start`, `session_before_switch`, `session_shutdown` |
240
+ | Config merge | `loadConfig` with user/project priority |
241
+ | Abort propagation | `AbortController` trees in foreground runs |
242
+
243
+ ### 3.2 Patterns pi-crew could adopt
244
+
245
+ | Pattern | Current status | Recommendation |
246
+ |---|---|---|
247
+ | `terminate: true` | ❌ Not used | Add to Agent/get_subagent_result |
248
+ | `session_before_compact` hook | ❌ Not hooked | Cancel compact during foreground runs |
249
+ | Custom compaction model | ❌ Not used | Use Haiku/Gemini Flash for task summaries |
250
+ | `pi.events` publish | ⚠️ Internal only | Add public structured events |
251
+ | `pi.appendEntry` | ❌ Not used | Cross-session run references |
252
+ | `tool_call` permission gate | ❌ Not gated | Gate destructive team actions |
253
+ | Config-driven tool registration | ❌ Always all | Register tools per config |
254
+ | Working indicator | ❌ Widget only | Use `ctx.ui.setWorkingIndicator` |
255
+ | Session name auto-set | ❌ Manual only | Auto-name from team run context |
256
+ | `ctx.compact()` proactive | ❌ No monitoring | Monitor + auto-compact at threshold |
257
+
258
+ ## 4. Example: Complete Tool with terminate + render
259
+
260
+ This shows a hypothetical optimized pi-crew Agent tool:
261
+
262
+ ```typescript
263
+ // OPTIMIZED Agent tool pattern
264
+ const AgentTool = defineTool({
265
+ name: "Agent",
266
+ label: "Agent",
267
+ description: "Launch a real pi-crew subagent...",
268
+ parameters: Type.Object({
269
+ prompt: Type.String(),
270
+ description: Type.String(),
271
+ subagent_type: Type.String(),
272
+ run_in_background: Type.Optional(Type.Boolean()),
273
+ }),
274
+ async execute(_id, params, signal, _onUpdate, ctx) {
275
+ // ... spawn subagent ...
276
+ if (params.run_in_background) {
277
+ return {
278
+ content: [{ type: "text", text: `Agent queued. ID: ${record.id}` }],
279
+ details: { agentId: record.id, status: "queued" },
280
+ terminate: true, // ← No need for LLM follow-up
281
+ };
282
+ }
283
+ await record.promise;
284
+ const output = readResult(record);
285
+ return {
286
+ content: [{ type: "text", text: output }],
287
+ details: { agentId: record.id, status: record.status },
288
+ terminate: true, // ← Final result, save LLM turn
289
+ };
290
+ },
291
+ renderResult(result, { expanded }, theme) {
292
+ // Custom rendering with colored status icons
293
+ // Collapsed/expanded views
294
+ // Usage stats display
295
+ },
296
+ });
297
+ ```