@tmustier/pi-agent-teams 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +55 -9
- package/WORKFLOW.md +110 -0
- package/docs/claude-parity.md +16 -13
- package/docs/hook-contract.md +183 -0
- package/docs/smoke-test-plan.md +26 -7
- package/extensions/teams/activity-tracker.ts +296 -8
- package/extensions/teams/cleanup.ts +222 -3
- package/extensions/teams/hooks.ts +57 -5
- package/extensions/teams/leader-attach-commands.ts +8 -4
- package/extensions/teams/leader-inbox.ts +162 -4
- package/extensions/teams/leader-info-commands.ts +105 -3
- package/extensions/teams/leader-lifecycle-commands.ts +205 -3
- package/extensions/teams/leader-messaging-commands.ts +19 -7
- package/extensions/teams/leader-spawn-command.ts +5 -1
- package/extensions/teams/leader-team-command.ts +51 -2
- package/extensions/teams/leader-teams-tool.ts +264 -10
- package/extensions/teams/leader.ts +174 -9
- package/extensions/teams/mailbox.ts +6 -1
- package/extensions/teams/spawn-types.ts +4 -0
- package/extensions/teams/teammate-rpc.ts +14 -0
- package/extensions/teams/teams-panel.ts +117 -19
- package/extensions/teams/teams-ui-shared.ts +205 -2
- package/extensions/teams/teams-widget.ts +67 -14
- package/extensions/teams/worker.ts +18 -6
- package/extensions/teams/worktree.ts +143 -0
- package/package.json +3 -2
- package/scripts/integration-cleanup-test.mts +419 -0
- package/scripts/smoke-test.mts +655 -2
- package/skills/agent-teams/SKILL.md +24 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- **Automatic startup GC** — on session start, silently removes stale team directories older than 24h (fire-and-forget, never blocks). Reuses the existing `gcStaleTeamDirs()` with age + state checks. (Thanks **@RensTillmann** — #8, #30)
|
|
8
|
+
- **Exit cleanup of empty team dirs** — on session shutdown, deletes the session's own team directory if it has no tasks in any namespace, no active teammates (RPC or manual), and no attach claim from another session. (Thanks **@RensTillmann** — #8, #30)
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
|
|
12
|
+
- Added `excludeTeamIds` parameter to `gcStaleTeamDirs()` to prevent startup GC from removing the current session's team (important for resumed sessions older than 24h).
|
|
13
|
+
|
|
14
|
+
## 0.5.0
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **DM routing to leader LLM context** — Teammate DMs are now injected into the leader's conversation via `sendLeaderLlmMessage` instead of only showing in the TUI. The leader can now act on DM requests autonomously. (Thanks **@davidsu** — #6, #29)
|
|
19
|
+
- **Batch-complete auto-wake** — `DelegationTracker` tracks task ID batches from `delegate()` calls. When all tasks in a batch complete, the idle leader is automatically woken to review results and continue orchestrating. Quality-gate aware. (Thanks **@RensTillmann** — #7, #29)
|
|
20
|
+
- **Worker completion messages in leader context** — Per-task completion/failure notifications injected into the leader LLM conversation with task subject, result summary, and progress counters. All-done detection warns when quality gates are still running. (#13)
|
|
21
|
+
- **Ergonomic worker status** — Real-time time-in-state, stall detection (configurable via `PI_TEAMS_STALL_THRESHOLD_MS`), last message summary, and model-per-worker in panel detail view. `member_status` tool action for agent-driven orchestration. (#10)
|
|
22
|
+
- **Tool call content in transcript** — Worker transcript view shows tool arguments inline: file paths, commands, patterns. Errors marked with ✗. (#18, #21, #23)
|
|
23
|
+
- **`/team done` + auto-done detection** — `/team done` ends a run (stops teammates, hides widget, notifies with summary). Widget auto-detects when all tasks complete. (#16)
|
|
24
|
+
- **Hook/model policy in panel** — Compact policy summary (hooks status, failure action, reopens, model inheritance) shown in widget and panel. (#20)
|
|
25
|
+
- **Model, thinking, task in spawn/panel** — Visible in spawn output, panel detail, and transcript header. (#19)
|
|
26
|
+
- **Urgent message interrupts** — `--urgent` flag on `/team dm` and `/team broadcast` interrupts active worker turns via steering. (#15)
|
|
27
|
+
- **Hook contract versioning** — Formal versioning and compatibility policy for quality-gate hooks. (#24)
|
|
28
|
+
|
|
29
|
+
### Fixes
|
|
30
|
+
|
|
31
|
+
- **Worktree/branch auto-cleanup** — Stale team dirs, worktrees, and branches cleaned up on shutdown and session switch. (#14)
|
|
32
|
+
- **`/team status` in README** — Added missing command to docs table. (#27)
|
|
33
|
+
- **Activity tracker** — Added `extractStartSummary`/`extractEndSummary` for tool transcript display.
|
|
34
|
+
|
|
35
|
+
## 0.4.0
|
|
36
|
+
|
|
37
|
+
Initial public release.
|
package/README.md
CHANGED
|
@@ -10,15 +10,16 @@ Core agent-teams primitives, matching Claude's design:
|
|
|
10
10
|
|
|
11
11
|
- **Shared task list** — file-per-task on disk with three states (pending / in-progress / completed) and dependency tracking so blocked tasks stay blocked until their prerequisites finish.
|
|
12
12
|
- **Auto-claim** — idle teammates automatically pick up the next unassigned, unblocked task. No manual dispatching required (disable with `PI_TEAMS_DEFAULT_AUTO_CLAIM=0`).
|
|
13
|
-
- **Direct messages and broadcast** — send a message to one teammate or all of them at once, via file-based mailboxes.
|
|
13
|
+
- **Direct messages and broadcast** — send a message to one teammate or all of them at once, via file-based mailboxes. Urgent messages can interrupt active turns via steering.
|
|
14
14
|
- **Graceful lifecycle** — spawn, stop, shutdown (with handshake), or kill teammates. The leader tracks who's online, idle, or streaming.
|
|
15
15
|
- **LLM-callable teams tool** — the model can spawn teammates, delegate tasks, mutate task assignment/status/dependencies, message teammates, and run lifecycle actions in tool calls (no slash commands needed).
|
|
16
|
-
- **Team cleanup** —
|
|
16
|
+
- **Team done + cleanup** — `/team done` ends a run (stops teammates, hides the widget, notifies with a summary); the widget auto-detects when all tasks are complete and shows a hint. `/team cleanup` tears down artifacts afterward.
|
|
17
17
|
|
|
18
18
|
Additional Pi-specific capabilities:
|
|
19
19
|
|
|
20
20
|
- **Git worktrees** — optionally give each teammate its own worktree so they work on isolated branches without conflicting edits.
|
|
21
21
|
- **Session branching** — clone the leader's conversation context into a teammate so it starts with full awareness of the work so far, instead of from scratch.
|
|
22
|
+
- **Completion notifications** — when a teammate finishes or fails a task, the leader LLM receives a structured `[Team]` message with task ID, subject, result summary, and progress counters so it can orchestrate autonomously without human intervention. When quality-gate hooks are active, the message warns that task states may still change.
|
|
22
23
|
- **Hooks / quality gates** — optional leader-side hooks on idle / task completion to run scripts (opt-in).
|
|
23
24
|
|
|
24
25
|
## UI style (terminology + naming)
|
|
@@ -110,9 +111,13 @@ Or drive it manually:
|
|
|
110
111
|
|
|
111
112
|
/tw # open the interactive widget panel
|
|
112
113
|
|
|
114
|
+
/team done # end run: stop teammates + hide widget
|
|
115
|
+
/team done --force # end run even with in-progress tasks
|
|
116
|
+
|
|
113
117
|
/team shutdown alice # graceful shutdown (handshake)
|
|
114
118
|
/team shutdown # stop all teammates (leader session remains active)
|
|
115
|
-
/team cleanup # remove team artifacts
|
|
119
|
+
/team cleanup # remove team artifacts (worktrees, branches, team dir)
|
|
120
|
+
/team gc --dry-run # preview stale team dirs that would be removed
|
|
116
121
|
```
|
|
117
122
|
|
|
118
123
|
Or let the model drive it with the delegate tool:
|
|
@@ -143,13 +148,15 @@ Or let the model drive it with the delegate tool:
|
|
|
143
148
|
| `task_dep_add` | `taskId`, `depId` | Add dependency edge (`taskId` depends on `depId`). |
|
|
144
149
|
| `task_dep_rm` | `taskId`, `depId` | Remove dependency edge. |
|
|
145
150
|
| `task_dep_ls` | `taskId` | Inspect dependency/block graph for one task. |
|
|
146
|
-
| `message_dm` | `name`, `message` | Send mailbox DM to one teammate. |
|
|
147
|
-
| `message_broadcast` | `message` | Send mailbox message to all discovered workers. |
|
|
151
|
+
| `message_dm` | `name`, `message` | Send mailbox DM to one teammate. Set `urgent=true` to interrupt their active turn. |
|
|
152
|
+
| `message_broadcast` | `message` | Send mailbox message to all discovered workers. Set `urgent=true` to interrupt active turns. |
|
|
148
153
|
| `message_steer` | `name`, `message` | Send steer instruction to a running RPC teammate. |
|
|
149
154
|
| `member_spawn` | `name` | Spawn one teammate (supports context/workspace/model/thinking/plan options). |
|
|
155
|
+
| `member_status` | optional `name` | Real-time worker status: activity, time in state, stall detection, tool use, tokens, last message. Omit name for all-worker summary. |
|
|
150
156
|
| `member_shutdown` | `name` or `all=true` | Request graceful shutdown via mailbox handshake. |
|
|
151
157
|
| `member_kill` | `name` | Force-stop one RPC teammate and unassign active tasks. |
|
|
152
158
|
| `member_prune` | _(none)_ | Mark stale non-RPC workers offline (`all=true` to force). |
|
|
159
|
+
| `team_done` | _(none)_ | End team run: stop all teammates, mark workers offline, hide widget (`all=true` to force with in-progress tasks). |
|
|
153
160
|
| `plan_approve` | `name` | Approve pending plan for a plan-required teammate. |
|
|
154
161
|
| `plan_reject` | `name` | Reject pending plan (`feedback` optional). |
|
|
155
162
|
| `hooks_policy_get` | _(none)_ | Read team hooks policy (configured + effective with env fallback). |
|
|
@@ -163,11 +170,13 @@ Example calls:
|
|
|
163
170
|
{ "action": "task_assign", "taskId": "12", "assignee": "alice" }
|
|
164
171
|
{ "action": "task_dep_add", "taskId": "12", "depId": "7" }
|
|
165
172
|
{ "action": "message_broadcast", "message": "Sync: finishing this milestone" }
|
|
173
|
+
{ "action": "message_dm", "name": "alice", "message": "Stop using lib X, use Y instead", "urgent": true }
|
|
166
174
|
{ "action": "member_kill", "name": "alice" }
|
|
167
175
|
{ "action": "plan_approve", "name": "alice" }
|
|
168
176
|
{ "action": "hooks_policy_get" }
|
|
169
177
|
{ "action": "hooks_policy_set", "hookFailureAction": "reopen_followup", "hookMaxReopensPerTask": 2, "hookFollowupOwner": "member" }
|
|
170
178
|
{ "action": "model_policy_get" }
|
|
179
|
+
{ "action": "team_done" }
|
|
171
180
|
{ "action": "model_policy_check", "model": "openai-codex/gpt-5.1-codex-mini" }
|
|
172
181
|
```
|
|
173
182
|
|
|
@@ -189,6 +198,7 @@ All management commands live under `/team`.
|
|
|
189
198
|
| --- | --- |
|
|
190
199
|
| `/team spawn <name> [fresh\|branch] [shared\|worktree] [plan] [--model <provider>/<modelId>] [--thinking <level>]` | Start a teammate |
|
|
191
200
|
| `/team list` | List teammates and their status |
|
|
201
|
+
| `/team status [name]` | Real-time worker state: stall detection, time in state, activity (omit name for summary) |
|
|
192
202
|
| `/team panel` | Interactive widget panel (same as `/tw`) |
|
|
193
203
|
| `/team attach list` | Discover existing team workspaces under `<teamsRoot>` |
|
|
194
204
|
| `/team attach <teamId> [--claim]` | Attach this session to an existing team workspace (`--claim` force-takes over an active claim) |
|
|
@@ -199,14 +209,16 @@ All management commands live under `/team`.
|
|
|
199
209
|
| `/team style <name>` | Set style (built-in or custom) |
|
|
200
210
|
| `/team send <name> <msg>` | Send a prompt over RPC |
|
|
201
211
|
| `/team steer <name> <msg>` | Redirect an in-flight run |
|
|
202
|
-
| `/team dm <name> <msg>` | Send a mailbox message |
|
|
203
|
-
| `/team broadcast <msg>` | Message all teammates |
|
|
212
|
+
| `/team dm <name> [--urgent] <msg>` | Send a mailbox message (`--urgent` interrupts active turns) |
|
|
213
|
+
| `/team broadcast [--urgent] <msg>` | Message all teammates (`--urgent` interrupts active turns) |
|
|
204
214
|
| `/team stop <name> [reason]` | Abort current work (resets task to pending) |
|
|
205
215
|
| `/team shutdown <name> [reason]` | Graceful shutdown (handshake) |
|
|
206
216
|
| `/team shutdown` | Stop all teammates (RPC + best-effort manual) (leader session remains active) |
|
|
207
217
|
| `/team prune [--all]` | Mark stale manual teammates offline (hides them in widget) |
|
|
208
218
|
| `/team kill <name>` | Force-terminate |
|
|
209
|
-
| `/team
|
|
219
|
+
| `/team done [--force]` | End run: stop teammates + hide widget (auto-detects when all tasks complete) |
|
|
220
|
+
| `/team cleanup [--force]` | Delete team artifacts (worktrees, branches, team dir) |
|
|
221
|
+
| `/team gc [--dry-run] [--force] [--max-age-hours=N]` | Garbage-collect stale team dirs older than N hours (default: 24) |
|
|
210
222
|
| `/team id` | Print team/task-list IDs and paths |
|
|
211
223
|
| `/team env <name>` | Print env vars to start a manual teammate |
|
|
212
224
|
|
|
@@ -216,11 +228,34 @@ Model inheritance note:
|
|
|
216
228
|
- Explicit deprecated `--model` overrides are rejected.
|
|
217
229
|
- Agents can introspect/check this at runtime via `teams` actions: `{ "action": "model_policy_get" }` and `{ "action": "model_policy_check", "model": "..." }`.
|
|
218
230
|
|
|
231
|
+
### Policy visibility
|
|
232
|
+
|
|
233
|
+
Both the persistent widget and the interactive panel (`/tw`) show a compact policy
|
|
234
|
+
summary below the header:
|
|
235
|
+
|
|
236
|
+
- **Hooks**: on/off status, `failureAction`, `maxReopensPerTask`, `followupOwner` (effective values from team config + env fallback)
|
|
237
|
+
- **Model**: leader model with deprecation warning when applicable, teammate selection source (`inherit`/`override`/`default`)
|
|
238
|
+
|
|
239
|
+
These values reflect the same resolution as the `hooks_policy_get` and `model_policy_get`
|
|
240
|
+
tool actions, but are continuously visible — no extra tool calls needed.
|
|
241
|
+
|
|
242
|
+
### Ergonomic worker status
|
|
243
|
+
|
|
244
|
+
The widget and panel show real-time worker state at a glance:
|
|
245
|
+
|
|
246
|
+
- **Time in state**: how long a worker has been in its current status (e.g. `3m12s`)
|
|
247
|
+
- **Stall detection**: when a streaming worker hasn't emitted any agent event for > 5 minutes, status changes to `⚠ stalled` (configurable via `PI_TEAMS_STALL_THRESHOLD_MS`)
|
|
248
|
+
- **Last message summary**: most recent assistant text (first 80–100 chars) visible in the panel's selected-worker detail section
|
|
249
|
+
- **Model per worker**: shown in the panel detail view when available
|
|
250
|
+
- **Current activity**: tool verb (e.g. `running…`, `editing…`) displayed inline
|
|
251
|
+
|
|
252
|
+
The `member_status` tool action provides the same information programmatically for agent-driven orchestration — no need to parse JSONL files or check file modification times.
|
|
253
|
+
|
|
219
254
|
### Panel shortcuts (`/tw` / `/team panel`)
|
|
220
255
|
|
|
221
256
|
- `↑/↓` or `w/s`: select teammate / scroll transcript
|
|
222
257
|
- `1..9`: jump directly to teammate in overview
|
|
223
|
-
- `enter`: open selected teammate transcript
|
|
258
|
+
- `enter`: open selected teammate transcript (shows tool args inline: file paths, commands, patterns; errors marked with ✗)
|
|
224
259
|
- `t` or `shift+t`: open selected teammate task list (task-centric view with deps/blocks); in task view, toggle back (`esc`/`t`/`shift+t`)
|
|
225
260
|
- task view: `c` complete, `p` pending, `i` in-progress, `u` unassign, `r` reassign selected task
|
|
226
261
|
- `m` or `d`: compose message to selected teammate
|
|
@@ -257,6 +292,7 @@ Model inheritance note:
|
|
|
257
292
|
| `PI_TEAMS_HOOKS_MAX_REOPENS_PER_TASK` | Reopen cap per task when failure action includes `reopen` (`0` disables auto-reopen) | `3` |
|
|
258
293
|
| `PI_TEAMS_HOOKS_FOLLOWUP_OWNER` | Follow-up owner policy: `member`, `lead`, `none` | `member` |
|
|
259
294
|
| `PI_TEAMS_HOOKS_CREATE_TASK_ON_FAILURE` | Legacy shortcut for `PI_TEAMS_HOOKS_FAILURE_ACTION=followup` | `0` (off) |
|
|
295
|
+
| `PI_TEAMS_STALL_THRESHOLD_MS` | Threshold (ms) before a streaming worker with no events is flagged as "stalled" | `300000` (5 min) |
|
|
260
296
|
|
|
261
297
|
## Storage layout
|
|
262
298
|
|
|
@@ -305,6 +341,8 @@ Hooks run with working directory = the **leader session cwd** and receive contex
|
|
|
305
341
|
- `PI_TEAMS_MEMBER`
|
|
306
342
|
- `PI_TEAMS_TASK_ID`, `PI_TEAMS_TASK_SUBJECT`, `PI_TEAMS_TASK_OWNER`, `PI_TEAMS_TASK_STATUS`
|
|
307
343
|
|
|
344
|
+
See [`docs/hook-contract.md`](docs/hook-contract.md) for the full versioned contract, JSON schema, and compatibility policy.
|
|
345
|
+
|
|
308
346
|
Hook policy can be controlled by agents at runtime via `teams` tool actions:
|
|
309
347
|
|
|
310
348
|
- `{ "action": "hooks_policy_get" }`
|
|
@@ -385,6 +423,14 @@ Deterministic leader-side integration flow that verifies failed `on_task_complet
|
|
|
385
423
|
- follow-up task is created/assigned when policy includes `followup`
|
|
386
424
|
- remediation mailbox nudge is emitted for the responsible teammate
|
|
387
425
|
|
|
426
|
+
### Integration: cleanup and garbage collection
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
npm run integration-cleanup-test
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Tests worktree/branch cleanup lifecycle, full team directory removal, GC age/activity filtering, and filesystem fallback when no git context is available.
|
|
433
|
+
|
|
388
434
|
### tmux dogfooding
|
|
389
435
|
|
|
390
436
|
```bash
|
package/WORKFLOW.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
tracker:
|
|
3
|
+
kind: linear
|
|
4
|
+
api_key: "$LINEAR_API_KEY"
|
|
5
|
+
team_key: "SYM"
|
|
6
|
+
project_slug: "db8e51049f48"
|
|
7
|
+
active_states:
|
|
8
|
+
- Todo
|
|
9
|
+
- In Progress
|
|
10
|
+
- In Review
|
|
11
|
+
- Merging
|
|
12
|
+
- Rework
|
|
13
|
+
terminal_states:
|
|
14
|
+
- Done
|
|
15
|
+
- Closed
|
|
16
|
+
- Cancelled
|
|
17
|
+
- Canceled
|
|
18
|
+
- Duplicate
|
|
19
|
+
polling:
|
|
20
|
+
interval_ms: 30000
|
|
21
|
+
workspace:
|
|
22
|
+
root: "$PI_SYMPHONY_WORKSPACE_ROOT"
|
|
23
|
+
worker:
|
|
24
|
+
runtime: pi
|
|
25
|
+
agent:
|
|
26
|
+
max_concurrent_agents: 4
|
|
27
|
+
max_turns: 8
|
|
28
|
+
max_retry_backoff_ms: 300000
|
|
29
|
+
codex:
|
|
30
|
+
turn_timeout_ms: 3600000
|
|
31
|
+
read_timeout_ms: 5000
|
|
32
|
+
stall_timeout_ms: 300000
|
|
33
|
+
pi:
|
|
34
|
+
command: pi
|
|
35
|
+
response_timeout_ms: 60000
|
|
36
|
+
session_dir_name: .pi-rpc-sessions
|
|
37
|
+
model:
|
|
38
|
+
provider: anthropic
|
|
39
|
+
model_id: claude-opus-4-6
|
|
40
|
+
thinking_level: xhigh
|
|
41
|
+
extension_paths:
|
|
42
|
+
- ../extensions/workspace-guard/index.ts
|
|
43
|
+
- ../extensions/proof/index.ts
|
|
44
|
+
- ../extensions/linear-graphql/index.ts
|
|
45
|
+
disable_extensions: true
|
|
46
|
+
disable_themes: true
|
|
47
|
+
orchestration:
|
|
48
|
+
phase_store: workpad
|
|
49
|
+
default_phase: implementing
|
|
50
|
+
passive_phases:
|
|
51
|
+
- waiting_for_checks
|
|
52
|
+
- waiting_for_human
|
|
53
|
+
- blocked
|
|
54
|
+
max_rework_cycles: 3
|
|
55
|
+
ownership:
|
|
56
|
+
required_label: symphony
|
|
57
|
+
required_workpad_marker: "## Symphony Workpad"
|
|
58
|
+
rollout:
|
|
59
|
+
mode: mutate
|
|
60
|
+
preflight_required: true
|
|
61
|
+
kill_switch_label: no-symphony-automation
|
|
62
|
+
kill_switch_file: /tmp/pi-symphony.pause
|
|
63
|
+
pr:
|
|
64
|
+
auto_create: true
|
|
65
|
+
base_branch: main
|
|
66
|
+
repo_slug: tmustier/pi-agent-teams
|
|
67
|
+
reuse_branch_pr: true
|
|
68
|
+
closed_pr_policy: new_branch
|
|
69
|
+
attach_to_tracker: true
|
|
70
|
+
required_labels:
|
|
71
|
+
- symphony
|
|
72
|
+
review_comment_mode: upsert
|
|
73
|
+
review_comment_marker: "<!-- symphony-review -->"
|
|
74
|
+
review:
|
|
75
|
+
enabled: true
|
|
76
|
+
agent: pr-reviewer
|
|
77
|
+
output_format: structured_markdown_v1
|
|
78
|
+
max_passes: 2
|
|
79
|
+
fix_consideration_severities:
|
|
80
|
+
- P0
|
|
81
|
+
- P1
|
|
82
|
+
- P2
|
|
83
|
+
merge:
|
|
84
|
+
mode: disabled
|
|
85
|
+
executor: gh
|
|
86
|
+
method: squash
|
|
87
|
+
strategy: queue
|
|
88
|
+
max_rebase_attempts: 2
|
|
89
|
+
require_green_checks: true
|
|
90
|
+
require_head_match: true
|
|
91
|
+
require_human_approval: true
|
|
92
|
+
approval_states:
|
|
93
|
+
- Merging
|
|
94
|
+
hooks:
|
|
95
|
+
timeout_ms: 60000
|
|
96
|
+
observability:
|
|
97
|
+
dashboard_enabled: true
|
|
98
|
+
refresh_ms: 1000
|
|
99
|
+
render_interval_ms: 16
|
|
100
|
+
server:
|
|
101
|
+
port: 4041
|
|
102
|
+
host: 127.0.0.1
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Before starting implementation, read and apply the agent-friendly-design skill at:
|
|
106
|
+
`/Users/thomasmustier/.pi/agent/skills/agent-friendly-design/SKILL.md`
|
|
107
|
+
|
|
108
|
+
This project builds interfaces that AI agents operate (CLIs, tools, extensions, UI surfaces).
|
|
109
|
+
Every change should follow agent-friendly design principles: structured output, progressive disclosure,
|
|
110
|
+
clear error classification, token-budget awareness, and discoverability.
|
package/docs/claude-parity.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Claude Agent Teams parity roadmap (pi-agent-teams)
|
|
2
2
|
|
|
3
|
-
Last updated: 2026-
|
|
3
|
+
Last updated: 2026-03-21
|
|
4
4
|
|
|
5
5
|
This document tracks **feature parity gaps** between:
|
|
6
6
|
|
|
@@ -8,12 +8,12 @@ This document tracks **feature parity gaps** between:
|
|
|
8
8
|
- https://code.claude.com/docs/en/agent-teams#control-your-agent-team
|
|
9
9
|
- https://code.claude.com/docs/en/interactive-mode#task-list
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
...and this repository's implementation:
|
|
12
12
|
|
|
13
13
|
- `pi-agent-teams` (Pi extension)
|
|
14
14
|
|
|
15
15
|
> Terminology note: this extension supports `PI_TEAMS_STYLE=<style>`.
|
|
16
|
-
> This doc often uses
|
|
16
|
+
> This doc often uses "comrade" as a generic stand-in for "worker/teammate", but **styles can customize terminology, naming, and lifecycle copy**.
|
|
17
17
|
> Built-ins: `normal`, `soviet`, `pirate`. Custom styles live under `~/.pi/agent/teams/_styles/`.
|
|
18
18
|
|
|
19
19
|
## Scope / philosophy
|
|
@@ -30,8 +30,8 @@ This document tracks **feature parity gaps** between:
|
|
|
30
30
|
|
|
31
31
|
These are intentional differences / additions:
|
|
32
32
|
|
|
33
|
-
- **Configurable styles** (`/team style
|
|
34
|
-
- **Git worktrees** for isolation (`/team spawn <name>
|
|
33
|
+
- **Configurable styles** (`/team style ...`) for terminology + naming + lifecycle copy.
|
|
34
|
+
- **Git worktrees** for isolation (`/team spawn <name> ... worktree`).
|
|
35
35
|
- **Session branching** (clone leader context into a teammate).
|
|
36
36
|
- A **status widget + interactive panel** (`/tw`, `/team panel`).
|
|
37
37
|
|
|
@@ -41,19 +41,20 @@ Legend: ✅ implemented • 🟡 partial • ❌ missing
|
|
|
41
41
|
|
|
42
42
|
| Area | Claude docs behavior | Pi Teams status | Notes / next step | Priority |
|
|
43
43
|
| --- | --- | --- | --- | --- |
|
|
44
|
-
| Enablement | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` + settings | N/A | Pi extension is available when installed/loaded. |
|
|
44
|
+
| Enablement | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` + settings | N/A | Pi extension is available when installed/loaded. | - |
|
|
45
45
|
| Team config | `~/.claude/teams/<team>/config.json` w/ members | ✅ | `extensions/teams/team-config.ts` (under `~/.pi/agent/teams/...` or `PI_TEAMS_ROOT_DIR`). | P0 |
|
|
46
46
|
| Task list (shared) | `~/.claude/tasks/<taskListId>/` + states + deps | ✅ | File-per-task + deps (`blockedBy`/`blocks`); `/team task dep add|rm|ls`; self-claim skips blocked tasks. | P0 |
|
|
47
47
|
| Self-claim | Comrades self-claim next unassigned, unblocked task; file locking | ✅ | `claimNextAvailableTask()` + locks; enabled by default (`PI_TEAMS_DEFAULT_AUTO_CLAIM=1`). | P0 |
|
|
48
48
|
| Explicit assign | Lead assigns task to comrade | ✅ | `/team task assign` sets owner + pings via mailbox. | P0 |
|
|
49
|
-
|
|
|
50
|
-
| Comrade↔comrade messaging | Comrades message each other directly | ✅ | Worker tool `team_message
|
|
49
|
+
| "Message" vs "broadcast" | Send to one comrade or all comrades | ✅ | `/team dm` + `/team broadcast` use mailbox; `/team send` uses RPC. Recipients = config workers + RPC map + active task owners. | P0 |
|
|
50
|
+
| Comrade↔comrade messaging | Comrades message each other directly | ✅ | Worker tool `team_message` (with `urgent` flag for mid-turn interrupts); messages via mailbox + CC leader via `peer_dm_sent`. | P1 |
|
|
51
51
|
| Display modes | In-process selection (Shift+Up/Down); split panes (tmux/iTerm) | ❌ | Pi has widget/panel + commands, but no terminal-level comrade navigation/panes. | P2 |
|
|
52
52
|
| Delegate mode | Lead restricted to coordination-only tools | ✅ | `/team delegate [on|off]`; `tool_call` blocks `bash/edit/write`; widget shows `[delegate]`. | P1 |
|
|
53
|
-
| Plan approval | Comrade can be
|
|
54
|
-
| Shutdown handshake | Lead requests shutdown; comrade can approve/reject | ✅ | Protocol: `shutdown_request` → `shutdown_approved` / `shutdown_rejected`. `/team shutdown <name>` (graceful), `/team kill <name>` (SIGTERM). Wording is style-controlled (e.g.
|
|
55
|
-
| Cleanup team |
|
|
53
|
+
| Plan approval | Comrade can be "plan required" and needs lead approval to implement | ✅ | `/team spawn <name> plan` → read-only tools; sends `plan_approval_request`; `/team plan approve|reject`. | P1 |
|
|
54
|
+
| Shutdown handshake | Lead requests shutdown; comrade can approve/reject | ✅ | Protocol: `shutdown_request` → `shutdown_approved` / `shutdown_rejected`. `/team shutdown <name>` (graceful), `/team kill <name>` (SIGTERM). Wording is style-controlled (e.g. "was asked to shut down", "walked the plank"). | P1 |
|
|
55
|
+
| Cleanup team | "Clean up the team" removes shared resources after comrades stopped | ✅ | `/team done [--force]` ends run (stops teammates, hides widget, auto-detects completion). `/team cleanup [--force]` deletes artifacts. | P1 |
|
|
56
56
|
| Hooks / quality gates | `ComradeIdle`, `TaskCompleted` hooks | 🟡 | Optional leader-side hook runner (idle/task-complete/task-fail) via `PI_TEAMS_HOOKS_ENABLED=1` + scripts under `_hooks/`; inline failure surfacing + failure-action policies (`warn`/`followup`/`reopen`/`reopen_followup`) implemented; stable hook context payload exposed via `PI_TEAMS_HOOK_CONTEXT_JSON` + auto-remediation flow (reopen cap / follow-up owner policy / teammate notification). Runtime policy changes are agent-invocable via `teams` actions (`hooks_policy_get` / `hooks_policy_set`). | P2 |
|
|
57
|
+
| Widget liveliness | Status updates in near real-time | ✅ | Event-driven widget refresh on teammate tool start/end and turn completion; auto-done detection with `/team done` hint. | P2 |
|
|
57
58
|
| Task list UX | Ctrl+T toggle; show all/clear tasks by asking | 🟡 | Widget + `/team task list` + `/team task show` + `/team task clear`; panel supports fast `t`/`shift+t` toggle into task-centric view (`Ctrl+T` is reserved by Pi for thinking blocks). | P0 |
|
|
58
59
|
| Shared task list across sessions | `CLAUDE_CODE_TASK_LIST_ID=...` | ✅ | Worker env: `PI_TEAMS_TASK_LIST_ID` (manual workers). Leader: `/team task use <taskListId>` (persisted). Newly spawned workers inherit; existing workers need restart. | P1 |
|
|
59
60
|
| Join/attach flow | Join existing team context from another running session | 🟡 | `/team attach list`, `/team attach <teamId> [--claim]`, `/team detach` plus claim heartbeat/takeover handshake added. Widget/panel now show attached-mode banner + detach hint. | P2 |
|
|
@@ -94,13 +95,14 @@ Legend: ✅ implemented • 🟡 partial • ❌ missing
|
|
|
94
95
|
- `/team cleanup [--force]` deletes only `<teamsRoot>/<teamId>` after safety checks.
|
|
95
96
|
|
|
96
97
|
8) **Peer-to-peer messaging** ✅
|
|
97
|
-
- Worker tool `team_message`
|
|
98
|
+
- Worker tool `team_message` with `urgent` flag for mid-turn interrupts
|
|
98
99
|
- Mailbox transport; leader CC notifications
|
|
100
|
+
- Urgent messages delivered via `sendUserMessage({ deliverAs: "steer" })` to interrupt active turns
|
|
99
101
|
|
|
100
102
|
9) **Shared task list across sessions** ✅
|
|
101
103
|
- `/team task use <taskListId>` + persisted `config.json`
|
|
102
104
|
|
|
103
|
-
### P2: UX +
|
|
105
|
+
### P2: UX + "product-level" parity
|
|
104
106
|
|
|
105
107
|
10) **Hooks / quality gates** 🟡 (partial)
|
|
106
108
|
- Implemented: optional leader-side hook runner (opt-in + timeout + logs).
|
|
@@ -123,6 +125,7 @@ Legend: ✅ implemented • 🟡 partial • ❌ missing
|
|
|
123
125
|
- Implemented: agent-invocable lifecycle actions via `teams` tool (`member_spawn|shutdown|kill|prune`).
|
|
124
126
|
- Implemented: agent-invocable governance actions via `teams` tool (`plan_approve|plan_reject`).
|
|
125
127
|
- Implemented: agent-invocable model policy introspection/check actions via `teams` tool (`model_policy_get|model_policy_check`) to validate spawn overrides before execution.
|
|
128
|
+
- Implemented: agent-invocable end-of-run via `teams` tool (`team_done`) with structured error classification (`status`/`reason`/`hint`).
|
|
126
129
|
- Next: optional tmux split-pane integration and deeper dependency/task editing flows in panel.
|
|
127
130
|
|
|
128
131
|
12) **Join/attach flow** 🟡 (partial)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Hook Contract
|
|
2
|
+
|
|
3
|
+
Versioned specification for the interface between pi-agent-teams and hook scripts.
|
|
4
|
+
|
|
5
|
+
Hook scripts are external programs (`.js`, `.mjs`, `.sh`, or bare executables) that run
|
|
6
|
+
on lifecycle events. This document defines what hooks receive and what pi-agent-teams
|
|
7
|
+
guarantees across releases.
|
|
8
|
+
|
|
9
|
+
## Current version
|
|
10
|
+
|
|
11
|
+
**Contract version: 1**
|
|
12
|
+
|
|
13
|
+
Exported as `HOOK_CONTRACT_VERSION` from `extensions/teams/hooks.ts`.
|
|
14
|
+
|
|
15
|
+
## Contract surface
|
|
16
|
+
|
|
17
|
+
Hooks receive context through two channels:
|
|
18
|
+
|
|
19
|
+
| Channel | Format | Key / field |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| Environment variable | string | `PI_TEAMS_HOOK_CONTEXT_VERSION` — the contract version as a string |
|
|
22
|
+
| Environment variable | JSON string | `PI_TEAMS_HOOK_CONTEXT_JSON` — structured payload (schema below) |
|
|
23
|
+
| Environment variables | flat strings | `PI_TEAMS_HOOK_EVENT`, `PI_TEAMS_TEAM_ID`, etc. (convenience) |
|
|
24
|
+
| Exit code | integer | `0` = pass, non-zero = fail |
|
|
25
|
+
|
|
26
|
+
### Context JSON schema (v1)
|
|
27
|
+
|
|
28
|
+
```jsonc
|
|
29
|
+
{
|
|
30
|
+
"version": 1, // always matches PI_TEAMS_HOOK_CONTEXT_VERSION
|
|
31
|
+
"event": "task_completed", // "idle" | "task_completed" | "task_failed"
|
|
32
|
+
"team": {
|
|
33
|
+
"id": "<teamId>",
|
|
34
|
+
"dir": "<absolute path>",
|
|
35
|
+
"taskListId": "<taskListId>",
|
|
36
|
+
"style": "normal" // current UI style id
|
|
37
|
+
},
|
|
38
|
+
"member": "<name>" | null, // teammate that triggered the event
|
|
39
|
+
"timestamp": "<ISO 8601>" | null,
|
|
40
|
+
"task": { // null for "idle" events; may also be null
|
|
41
|
+
// for task_completed/task_failed if the task
|
|
42
|
+
// was cleared before the leader processed it
|
|
43
|
+
"id": "3",
|
|
44
|
+
"subject": "<text>", // truncated to 1,000 chars
|
|
45
|
+
"description": "<text>", // truncated to 8,000 chars
|
|
46
|
+
"owner": "<name>" | null,
|
|
47
|
+
"status": "completed", // "pending" | "in_progress" | "completed"
|
|
48
|
+
// NOTE: for task_failed events the status is
|
|
49
|
+
// typically "pending" (reset before hook runs)
|
|
50
|
+
"blockedBy": ["1", "2"], // max 200 entries
|
|
51
|
+
"blocks": ["5"], // max 200 entries
|
|
52
|
+
"metadata": {}, // freeform key-value
|
|
53
|
+
"createdAt": "<ISO 8601>",
|
|
54
|
+
"updatedAt": "<ISO 8601>"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Flat environment variables (v1)
|
|
60
|
+
|
|
61
|
+
| Variable | Always set | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `PI_TEAMS_HOOK_EVENT` | ✓ | Event name |
|
|
64
|
+
| `PI_TEAMS_HOOK_CONTEXT_VERSION` | ✓ | Contract version (string) |
|
|
65
|
+
| `PI_TEAMS_HOOK_CONTEXT_JSON` | ✓ | Full JSON payload |
|
|
66
|
+
| `PI_TEAMS_TEAM_ID` | ✓ | Team identifier |
|
|
67
|
+
| `PI_TEAMS_TEAM_DIR` | ✓ | Absolute path to team directory |
|
|
68
|
+
| `PI_TEAMS_TASK_LIST_ID` | ✓ | Task list identifier |
|
|
69
|
+
| `PI_TEAMS_STYLE` | ✓ | UI style id |
|
|
70
|
+
| `PI_TEAMS_MEMBER` | when available | Teammate name |
|
|
71
|
+
| `PI_TEAMS_EVENT_TIMESTAMP` | when available | ISO 8601 event timestamp |
|
|
72
|
+
| `PI_TEAMS_TASK_ID` | when task exists | Task id |
|
|
73
|
+
| `PI_TEAMS_TASK_SUBJECT` | when task exists | Task subject (untruncated) |
|
|
74
|
+
| `PI_TEAMS_TASK_OWNER` | when task has owner | Task owner name |
|
|
75
|
+
| `PI_TEAMS_TASK_STATUS` | when task exists | Task status |
|
|
76
|
+
|
|
77
|
+
### Hook exit code semantics
|
|
78
|
+
|
|
79
|
+
| Exit code | Meaning | Leader behavior |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `0` | Pass | Record success in task metadata |
|
|
82
|
+
| Non-zero | Fail | Apply failure policy (warn / followup / reopen / reopen_followup) |
|
|
83
|
+
| Timeout (SIGTERM) | Fail | Same as non-zero exit |
|
|
84
|
+
|
|
85
|
+
## Compatibility policy
|
|
86
|
+
|
|
87
|
+
### Additive changes (no version bump)
|
|
88
|
+
|
|
89
|
+
The following changes are **backward-compatible** and do NOT increment the contract version:
|
|
90
|
+
|
|
91
|
+
- Adding new **optional** fields to the context JSON (hooks must tolerate unknown keys)
|
|
92
|
+
- Adding new **environment variables** (hooks must tolerate new env vars)
|
|
93
|
+
- Adding new **event types** (hooks only receive events matching their filename)
|
|
94
|
+
- Extending `metadata` with new keys
|
|
95
|
+
- Increasing truncation limits
|
|
96
|
+
|
|
97
|
+
### Breaking changes (version bump required)
|
|
98
|
+
|
|
99
|
+
The following changes **require incrementing** the contract version:
|
|
100
|
+
|
|
101
|
+
- Removing or renaming existing JSON fields
|
|
102
|
+
- Changing the type of an existing field
|
|
103
|
+
- Changing the semantics of an existing field (e.g., status values)
|
|
104
|
+
- Reducing truncation limits below current values
|
|
105
|
+
- Changing exit code semantics
|
|
106
|
+
- Removing environment variables
|
|
107
|
+
|
|
108
|
+
### Version lifecycle
|
|
109
|
+
|
|
110
|
+
1. **New version**: old version continues to be supported for at least one minor release
|
|
111
|
+
2. **Deprecation**: the old version emits a warning in hook logs
|
|
112
|
+
3. **Removal**: the old version is dropped in the next major release
|
|
113
|
+
|
|
114
|
+
### Hook author guidelines
|
|
115
|
+
|
|
116
|
+
Write hooks that are resilient to additive changes and race conditions:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
// ✅ Good: parse only the fields you need, ignore the rest
|
|
120
|
+
const ctx = JSON.parse(process.env.PI_TEAMS_HOOK_CONTEXT_JSON);
|
|
121
|
+
const taskId = ctx.task?.id;
|
|
122
|
+
|
|
123
|
+
// ✅ Good: always guard task access — task can be null even for
|
|
124
|
+
// task_completed/task_failed events (race: task cleared before leader reads it)
|
|
125
|
+
if (!ctx.task) {
|
|
126
|
+
console.log("Task already cleared, skipping quality gate");
|
|
127
|
+
process.exit(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ✅ Good: don't assume task.status matches the event name —
|
|
131
|
+
// for task_failed events the status is typically "pending" (reset before hook runs)
|
|
132
|
+
if (ctx.event === "task_failed") {
|
|
133
|
+
console.log(`Task #${ctx.task.id} failed (current status: ${ctx.task.status})`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ✅ Good: check the version for breaking changes
|
|
137
|
+
const version = parseInt(process.env.PI_TEAMS_HOOK_CONTEXT_VERSION, 10);
|
|
138
|
+
if (version > 1) {
|
|
139
|
+
console.error(`Unsupported hook contract version: ${version}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ❌ Bad: assume exact shape, fail on new fields
|
|
144
|
+
const { version, event, team, member, timestamp, task } = ctx;
|
|
145
|
+
assert(Object.keys(ctx).length === 5); // breaks when fields are added
|
|
146
|
+
|
|
147
|
+
// ❌ Bad: unconditionally access task fields
|
|
148
|
+
const subject = ctx.task.subject; // crashes when task is null
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Hook log format
|
|
152
|
+
|
|
153
|
+
Each hook invocation produces a log file in `<teamDir>/hook-logs/` with the structure:
|
|
154
|
+
|
|
155
|
+
```jsonc
|
|
156
|
+
{
|
|
157
|
+
"invocation": {
|
|
158
|
+
"event": "task_completed",
|
|
159
|
+
"teamId": "...",
|
|
160
|
+
// ... full invocation context
|
|
161
|
+
},
|
|
162
|
+
"result": {
|
|
163
|
+
"ran": true,
|
|
164
|
+
"hookPath": "/path/to/on_task_completed.js",
|
|
165
|
+
"command": ["node", "/path/to/on_task_completed.js"],
|
|
166
|
+
"exitCode": 0,
|
|
167
|
+
"timedOut": false,
|
|
168
|
+
"durationMs": 142,
|
|
169
|
+
"stdout": "...",
|
|
170
|
+
"stderr": "...",
|
|
171
|
+
"contractVersion": 1 // traces which version was used
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Changelog
|
|
177
|
+
|
|
178
|
+
### v1 (initial)
|
|
179
|
+
|
|
180
|
+
- Context JSON with `version`, `event`, `team`, `member`, `timestamp`, `task`
|
|
181
|
+
- Flat env vars: `PI_TEAMS_HOOK_EVENT`, `PI_TEAMS_HOOK_CONTEXT_VERSION`, `PI_TEAMS_HOOK_CONTEXT_JSON`, team/task fields
|
|
182
|
+
- Exit code 0 = pass, non-zero = fail
|
|
183
|
+
- Truncation: subject 1,000 chars, description 8,000 chars, blockedBy/blocks max 200 entries
|
package/docs/smoke-test-plan.md
CHANGED
|
@@ -20,13 +20,22 @@ npx tsx scripts/smoke-test.mts
|
|
|
20
20
|
| Module | Coverage |
|
|
21
21
|
|------------------|-----------------------------------------------------------------|
|
|
22
22
|
| `names.ts` | `sanitizeName` character replacement, edge cases |
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
23
|
+
| `model-policy.ts`| Deprecated model detection, teammate model selection/override |
|
|
24
|
+
| `teams-ui-shared.ts` | `isTeamDone` (9 edge cases), display helpers |
|
|
25
|
+
| `fs-lock.ts` | `withLock` returns value, cleans up lock file, stale locks |
|
|
26
|
+
| `mailbox.ts` | `writeToMailbox`, `popUnreadMessages`, read-once, urgent flag |
|
|
25
27
|
| `task-store.ts` | CRUD, `startAssignedTask`, `completeTask`, `claimNextAvailable`,|
|
|
26
28
|
| | `unassignTasksForAgent`, dependencies, `clearTasks` |
|
|
27
|
-
| `team-config.ts` | `ensureTeamConfig` (idempotent), `upsertMember`, `setMemberStatus`, `loadTeamConfig
|
|
29
|
+
| `team-config.ts` | `ensureTeamConfig` (idempotent), `upsertMember`, `setMemberStatus`, `loadTeamConfig`, hooks policy |
|
|
28
30
|
| `protocol.ts` | Structured message parsers (valid + invalid JSON + wrong type) |
|
|
29
|
-
|
|
|
31
|
+
| `teams-style.ts` | Custom styles, naming rules, pool naming |
|
|
32
|
+
| `hooks.ts` | Hook execution, failure policies, follow-up/reopen actions |
|
|
33
|
+
| `team-attach-claim.ts` | Acquire/release/heartbeat claims, staleness detection |
|
|
34
|
+
| `team-discovery.ts` | Team listing, config parsing, online worker counts |
|
|
35
|
+
| `/team done` | End-of-run cleanup, force-done with in-progress tasks, idempotency |
|
|
36
|
+
| `isTeamDone` | All branches: empty, completed, pending, streaming, stopped |
|
|
37
|
+
| docs drift guard | README, SKILL.md, help text consistency checks |
|
|
38
|
+
| Pi CLI | `pi --version` executes (skipped in CI if `pi` not on PATH) |
|
|
30
39
|
|
|
31
40
|
**Expected result:** `PASSED: <n> FAILED: 0`
|
|
32
41
|
|
|
@@ -95,7 +104,17 @@ Ask the model:
|
|
|
95
104
|
|
|
96
105
|
**Expected:** the `teams` tool is invoked, task created and assigned.
|
|
97
106
|
|
|
98
|
-
### 3g.
|
|
107
|
+
### 3g. End of run
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
/team done
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Expected:** all teammates stopped, widget hidden, summary notification shows task counts. If tasks are still in progress, use `/team done --force`.
|
|
114
|
+
|
|
115
|
+
After `/team done`, spawning a new teammate should automatically restore the widget.
|
|
116
|
+
|
|
117
|
+
### 3h. Shutdown (alternative to done)
|
|
99
118
|
|
|
100
119
|
```
|
|
101
120
|
/team shutdown agent1
|
|
@@ -138,9 +157,9 @@ pi --no-extensions -e extensions/teams/index.ts --mode rpc
|
|
|
138
157
|
|
|
139
158
|
| # | Test | Method | Status |
|
|
140
159
|
|---|-------------------------------|------------|--------|
|
|
141
|
-
| 1 | Unit primitives (
|
|
160
|
+
| 1 | Unit primitives (200+ asserts)| Automated | ✅ |
|
|
142
161
|
| 2 | Extension loading | CLI | ✅ |
|
|
143
|
-
| 3 | Interactive spawn/task/dm
|
|
162
|
+
| 3 | Interactive spawn/task/dm/done| Manual | 📋 |
|
|
144
163
|
| 4 | Worker-side RPC | Manual | 📋 |
|
|
145
164
|
|
|
146
165
|
✅ = verified in this run, 📋 = documented for manual execution.
|