@chorus-aidlc/chorus-pi 0.0.1 → 0.0.2

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/README.md CHANGED
@@ -6,6 +6,7 @@ Chorus AI-DLC collaboration platform extension for [Pi](https://pi.dev). Ported
6
6
 
7
7
  - **12 skills** — `/skill:chorus`, `/skill:idea`, `/skill:proposal`, `/skill:develop`, `/skill:review`, `/skill:quick-dev`, `/skill:yolo`, `/skill:brainstorm`, `/skill:orchestrate`, `/skill:docs`, `/skill:chorus-cli`, `/skill:openspec-aware`
8
8
  - **3 read-only reviewer sub-agents** — `chorus-proposal-reviewer`, `chorus-task-reviewer`, `chorus-code-reviewer`
9
+ - **1 worker sub-agent** — `chorus-worker`, a general-purpose Chorus implementer that claims and completes ONE task via the develop workflow (dispatch it with the `subagent` tool, single or parallel mode, for wave-based execution)
9
10
  - **1 session-aware extension** (`extensions/chorus.ts`) — subscribes to Pi native events to automate checkin, context injection, reviewer nudges, and session lifecycle
10
11
  - **The official pi subagent pattern** bundled at `extensions/subagent/` (the `subagent` tool + package-relative agent discovery)
11
12
 
@@ -25,11 +26,17 @@ reviewer agents are discovered directly from the package's own `agents/` dir —
25
26
  there is **no** separate subagents dependency and **no** manual copy of agent
26
27
  files into `~/.pi/agent/agents/`.
27
28
 
28
- Then configure `.mcp.json` and env vars — see [`docs/CONNECT_PI.md`](../../docs/CONNECT_PI.md).
29
+ Then configure `mcp.json` and env vars — see [`docs/CONNECT_PI.md`](../../docs/CONNECT_PI.md).
29
30
 
30
31
  `chorus init` (a.k.a. `chorus agents add`) automates this: select **Pi** in the agent
31
- checklist and it runs `pi install npm:@chorus-aidlc/chorus-pi` for you (degrading to the
32
- manual command if the `pi` CLI is absent).
32
+ checklist and it runs both installs (`pi install npm:pi-mcp-adapter && pi install
33
+ npm:@chorus-aidlc/chorus-pi`, degrading to the manual commands if the `pi` CLI is absent)
34
+ **and** writes pi's global `~/.pi/agent/mcp.json` with an `mcpServers.chorus` entry whose
35
+ `Authorization` header references the key by environment variable (`Bearer ${CHORUS_API_KEY}`)
36
+ — the resolved endpoint URL is a literal, and **no `cho_` key is written to disk** (the same
37
+ keyless model Claude Code and Codex use). You still export `CHORUS_API_KEY` (and
38
+ `CHORUS_AGENT_PROFILE`) in the shell that launches interactive pi — pi has no settings env-file
39
+ to persist them into; the daemon spawner injects them for the wake path.
33
40
 
34
41
  ## Wakeable daemon backend (`--agent pi`)
35
42
 
@@ -49,7 +56,7 @@ that wakes it. See [`docs/CONNECT_PI.md`](../../docs/CONNECT_PI.md#run-pi-as-a-w
49
56
 
50
57
  ## Why Pi is the lowest-friction target
51
58
 
52
- - **MCP: zero installer.** `pi-mcp-adapter` auto-discovers the repo's `.mcp.json` (literal URL + Bearerno `${VAR}` expansion needed, unlike Codex). The main agent gets all 40+ `chorus_*` tools with no setup script.
59
+ - **MCP: adapter path, keyless config.** `pi-mcp-adapter` reads the `mcp.json` `chorus agents add` writes at `~/.pi/agent/mcp.json` (or a project-root `.mcp.json`) and exposes all 40+ `chorus_*` tools the extension never registers tools itself. The `Authorization` header references the key by env var (`Bearer ${CHORUS_API_KEY}`, which the adapter interpolates at connect time), so no `cho_` key lands on disk. A literal Bearer also works, but the env-referenced form is what the CLI writes.
53
60
  - **Hooks: TypeScript, not bash.** The extension replaces ~10 bash hook scripts with one TS file. No `curl`/`jq`, no Bash 3.2 compatibility traps (the `${2:-{}}` JSON-parse bug that plagued the Codex port is structurally impossible here).
54
61
  - **Sub-agent sessions: automatic.** By monitoring `subagent` tool events, the extension auto-creates a Chorus session for each worker task in a dispatch and closes it when the tool call returns — a capability the Codex port lacks (Codex has no sub-agent lifecycle events, so its workers manage sessions manually).
55
62
  - **Skills: same standard.** Pi implements the Agent Skills standard, so the skill bodies port with find/replace only (Claude's `Task` tool → the `subagent` tool; `/chorus:develop` → `/skill:develop`).
@@ -71,17 +78,18 @@ packages/chorus-pi/
71
78
  │ ├── brainstorm/ orchestrate/ # divergent prelude + multi-agent orchestration
72
79
  │ ├── docs/ chorus-cli/ # docs router + CLI reference
73
80
  │ └── openspec-aware/ # opt-in spec-driven authoring sub-procedure
74
- ├── agents/ # 3 reviewer sub-agents — discovered package-relative by extensions/subagent/agents.ts (no manual copy)
75
- │ ├── chorus-proposal-reviewer.md
81
+ ├── agents/ # 4 sub-agents — discovered package-relative by extensions/subagent/agents.ts (no manual copy)
82
+ │ ├── chorus-proposal-reviewer.md # read-only reviewers
76
83
  │ ├── chorus-task-reviewer.md
77
- └── chorus-code-reviewer.md
84
+ ├── chorus-code-reviewer.md
85
+ │ └── chorus-worker.md # general-purpose task implementer (inherits full tools)
78
86
  ├── bin/
79
87
  │ └── chorus-mcp-call.sh # stateless MCP-over-HTTP wrapper (from the Codex port) for OpenSpec byte-exact document mirroring
80
88
  └── README.md
81
89
  ```
82
90
  ## Status
83
91
 
84
- **Complete port** of the Claude Code / Codex plugins to Pi. All 12 skills, all 3 reviewer sub-agents, the session-aware extension, the bundled official subagent pattern, and the OpenSpec wrapper are implemented and validated (TS transpiles, JSON valid, all skill/agent names compliant with the Agent Skills standard, no Claude/Codex-specific references remain).
92
+ **Complete port** of the Claude Code / Codex plugins to Pi. All 12 skills, all 3 reviewer sub-agents plus the `chorus-worker` implementer, the session-aware extension, the bundled official subagent pattern, and the OpenSpec wrapper are implemented and validated (TS transpiles, JSON valid, all skill/agent names compliant with the Agent Skills standard, no Claude/Codex-specific references remain).
85
93
 
86
94
  The extension goes beyond the Codex port in one key way: by using Pi's `tool_call` event (pre-execution, mutable input), it **auto-injects the Chorus session UUID + workflow into each dispatched worker's task** — the Pi-native equivalent of Claude's `SubagentStart` hook. The Codex port has no pre-spawn mutation channel, so its workers must manage sessions manually. On Pi, dispatch a worker via the `subagent` tool and the extension handles session creation + context injection, then closes the session when the (ephemeral) tool call returns.
87
95
 
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: chorus-worker
3
+ description: General-purpose Chorus implementer subagent that claims and completes ONE Chorus task end-to-end via the develop workflow. Dispatch it via the blocking subagent tool (single or parallel mode) for wave-based execution.
4
+ ---
5
+
6
+ You are a Chorus implementer. Your job is to take ONE assigned Chorus task and drive it from open to `to_verify` by writing real, working code — then hand back to the main agent for independent review and admin verification. You do NOT review, verify, or approve your own work.
7
+
8
+ This mirrors the single-task execution flow of `/skill:develop`; consult that skill for the full workflow and edge cases.
9
+
10
+ === WHAT YOU RECEIVE ===
11
+
12
+ Your dispatch prompt contains a Chorus **task UUID** (and usually a project UUID). It also carries a block the chorus-pi extension auto-injects at the end:
13
+
14
+ ```
15
+ --- Chorus session (auto-injected by the chorus-pi extension) ---
16
+ Session UUID: <session-uuid>
17
+ ...
18
+ ```
19
+
20
+ Read the `Session UUID` from that block and pass it as `sessionUuid` on every task-lifecycle call below (checkin, update, report, checkout). If no such block is present (e.g. you were run without the extension), omit `sessionUuid` — the task calls still work, just without session attribution.
21
+
22
+ === MCP TOOL NAMES ===
23
+
24
+ Use the `chorus_*` MCP tools for all Chorus data access — do NOT use curl or raw HTTP. Depending on how pi-mcp-adapter exposed the server, the tool-name prefix is either `chorus_*` (native) or `chorus_chorus_*` (gateway mode). If unsure, probe once with a checkin (`chorus_checkin` / `chorus_chorus_checkin`) and use whichever prefix resolves; apply it consistently for the rest of the run.
25
+
26
+ === WORKFLOW ===
27
+
28
+ **1. Gather context.** Do NOT rely on the dispatch summary — read the source of truth:
29
+ ```
30
+ chorus_get_task({ taskUuid: "<task-uuid>" })
31
+ ```
32
+ Read the description, `acceptanceCriteriaItems`, priority, `dependsOn`, and `commentCount`. Then, for context:
33
+ - `chorus_get_comments({ targetType: "task", targetUuid: "<task-uuid>" })` if `commentCount > 0` (prior work reports, feedback).
34
+ - `chorus_get_proposal({ proposalUuid: "<from-task>", section: "documents" })` for the PRD / tech design the task implements.
35
+ - `chorus_get_document({ documentUuid: "<doc-uuid>" })` for any linked references or full doc bodies.
36
+ - Read upstream `dependsOn` tasks + their comments for the interfaces/contracts your work builds on.
37
+
38
+ **2. Claim the task:**
39
+ ```
40
+ chorus_claim_task({ taskUuid: "<task-uuid>" })
41
+ ```
42
+
43
+ **3. Check in and start:**
44
+ ```
45
+ chorus_session_checkin_task({ sessionUuid: "<session-uuid>", taskUuid: "<task-uuid>" })
46
+ chorus_update_task({ taskUuid: "<task-uuid>", status: "in_progress", sessionUuid: "<session-uuid>" })
47
+ ```
48
+ > If `chorus_update_task(status:"in_progress")` is rejected for unresolved dependencies, stop and report the blocker back to the main agent — do not force it.
49
+
50
+ **4. Implement.** Write real code per the task description and acceptance criteria. Follow the repo's conventions (read `CLAUDE.md` / `AGENTS.md` if present). Run the project's tests / build / lint and make them pass — do not narrate tests you did not run.
51
+
52
+ **5. Report progress:**
53
+ ```
54
+ chorus_report_work({
55
+ taskUuid: "<task-uuid>",
56
+ report: "What was done, files changed, commits, remaining work/blockers",
57
+ sessionUuid: "<session-uuid>"
58
+ })
59
+ ```
60
+
61
+ **6. Self-check acceptance criteria.** Re-read the task's `acceptanceCriteriaItems`, then:
62
+ ```
63
+ chorus_report_criteria_self_check({
64
+ taskUuid: "<task-uuid>",
65
+ criteria: [
66
+ { uuid: "<criterion-uuid>", devStatus: "passed", devEvidence: "<evidence>" }
67
+ // ...
68
+ ]
69
+ })
70
+ ```
71
+ For **required** criteria, keep working until you can self-check as `passed`. Only mark **optional** criteria `failed` if genuinely out of scope.
72
+
73
+ **7. Check out and submit for verify:**
74
+ ```
75
+ chorus_session_checkout_task({ sessionUuid: "<session-uuid>", taskUuid: "<task-uuid>" })
76
+ chorus_submit_for_verify({ taskUuid: "<task-uuid>", summary: "<what you built + AC self-check result>" })
77
+ ```
78
+
79
+ === HARD LIMITS ===
80
+
81
+ - Do **NOT** admin-verify or approve your own work. `chorus_admin_verify_task`, `chorus_mark_acceptance_criteria`, and proposal approval are the main agent's / orchestrator's job — after you submit, the main agent spawns `chorus-task-reviewer` and acts on its VERDICT.
82
+ - Do **NOT** call `chorus_create_session` or `chorus_close_session` — the chorus-pi extension owns session lifecycle (it created your session and closes it when the dispatching `subagent` tool call returns).
83
+ - Work on **ONE** task. If you cannot complete it (missing knowledge, hard blocker), `chorus_release_task` it, add a comment explaining why, and report that back — do not leave it half-claimed.
84
+
85
+ === OUTPUT FORMAT (REQUIRED) ===
86
+
87
+ End your run with this exact structure so the main agent can proceed to review:
88
+
89
+ ```
90
+ ## Completed
91
+ <one-paragraph summary of what you implemented and the task's final status (to_verify)>
92
+
93
+ ## Files Changed
94
+ - path/to/file.ts — what changed
95
+ - ...
96
+
97
+ ## Notes
98
+ - Test/build results, any AC left optional-failed with rationale, blockers, or follow-ups
99
+ ```
package/lib/lib.ts CHANGED
@@ -102,11 +102,13 @@ export function isReviewerAgent(name: string): boolean {
102
102
  * the session workflow into them adds irrelevant task-lifecycle instructions and
103
103
  * unnecessary chorus_create_session API traffic for agents that never touch a task.
104
104
  *
105
- * This is a positive allowlist (not a reviewer exclusion) so arbitrary custom
106
- * read-only agents also do NOT get a session. Add more worker names here if the
107
- * project introduces them.
105
+ * `chorus-worker` is this package's own general-purpose implementer agent
106
+ * (agents/chorus-worker.md); `worker` is retained for back-compat with pi's
107
+ * subagent example. This is a positive allowlist (not a reviewer exclusion) so
108
+ * arbitrary custom read-only agents also do NOT get a session. Add more worker
109
+ * names here if the project introduces them.
108
110
  */
109
- export const WORKER_AGENT_NAMES = ["worker"] as const;
111
+ export const WORKER_AGENT_NAMES = ["worker", "chorus-worker"] as const;
110
112
  export function isWorkerAgent(name: string): boolean {
111
113
  return (WORKER_AGENT_NAMES as readonly string[]).includes(name);
112
114
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chorus-aidlc/chorus-pi",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Chorus AI-DLC collaboration platform extension for the Pi coding agent. Provides skills for every stage of the AI-DLC lifecycle, read-only reviewer subagents, and session-aware extension hooks. The Chorus MCP server is auto-discovered from the repo's .mcp.json by pi-mcp-adapter — no installer required.",
5
5
  "author": {
6
6
  "name": "Chorus-AIDLC"
@@ -78,7 +78,7 @@ Review your persona, current assignments, and pending work counts.
78
78
 
79
79
  **Skip if you are the main agent or Team Lead.**
80
80
 
81
- If you are a **sub-agent** (spawned via `subagent_spawn`), the Chorus extension automatically creates your session and injects it into your task prompt — look for a `--- Chorus session (auto-injected) ---` section containing your `Session UUID`. Keep it for all task operations.
81
+ If you are a **sub-agent** (dispatched via the `subagent` tool), the Chorus extension automatically creates your session and injects it into your task prompt — look for a `--- Chorus session (auto-injected) ---` section containing your `Session UUID`. Keep it for all task operations.
82
82
 
83
83
  ### Step 2: Find Work
84
84
 
@@ -265,7 +265,7 @@ If the task you just self-verified was the LAST one of its Idea (every Task acro
265
265
 
266
266
  ## Session (Sub-Agents Only)
267
267
 
268
- The Chorus extension **fully automates** session lifecycle — creation (on `subagent_spawn`, via `tool_call` task injection) and cleanup (on `subagent_manage close`) are handled by the extension. Sub-agents only do 3 things manually:
268
+ The Chorus extension **fully automates** session lifecycle — a Chorus session is created (on `subagent` dispatch, via `tool_call` task injection) and closed (when the blocking `subagent` call returns) by the extension. Sub-agents only do 3 things manually:
269
269
 
270
270
  1. `chorus_session_checkin_task({ sessionUuid, taskUuid })` — before starting work
271
271
  2. `chorus_session_checkout_task({ sessionUuid, taskUuid })` — when done (recommended; plugin also auto-checkouts on exit)
@@ -277,13 +277,15 @@ The Chorus extension **fully automates** session lifecycle — creation (on `sub
277
277
 
278
278
  ## Parallel Sub-Agent Integration
279
279
 
280
- When using Pi's subagents (`pi-subagents`) to run multiple sub-agents in parallel, Chorus provides full work observability. The `chorus-pi` extension automates the session lifecycle: when you `subagent_spawn` a worker, it creates a Chorus session and injects the session UUID + workflow into the worker's task; when you `subagent_manage close` the agent, it closes the session.
280
+ Use the `subagent` tool to run multiple Chorus workers in parallel; Chorus provides full work observability. The `subagent` tool is **blocking** — a parallel dispatch runs every worker to completion and returns their aggregated output in one call (there is no async spawn, no `agentId`, and no manual close). The `chorus-pi` extension automates session lifecycle: when you dispatch a `chorus-worker`, it creates a Chorus session and injects the session UUID + workflow into that worker's task; when the `subagent` call returns, it closes the session.
281
+
282
+ > The `subagent` tool has three modes — **single** (`{ agent, task }`), **parallel** (`{ tasks: [...] }`, max 8 per call, concurrency 4), and **chain** (`{ chain: [...] }`, sequential with a `{previous}` placeholder). Dispatch `agent: "chorus-worker"` for Chorus task implementation.
281
283
 
282
284
  ### Two-Layer Architecture
283
285
 
284
286
  | Layer | System | Purpose |
285
287
  |-------|--------|---------|
286
- | **Orchestration** | Pi subagents (`subagent_spawn` / `subagent_send` / `subagent_mailbox`) | Spawning sub-agents, follow-up tasks, inter-agent messaging |
288
+ | **Orchestration** | The `subagent` tool (single / parallel / chain) | Dispatching workers to isolated pi subprocesses and collecting their results |
287
289
  | **Work Tracking** | Chorus | Task lifecycle, session observability, activity stream |
288
290
 
289
291
  ### Team Lead Workflow
@@ -293,24 +295,28 @@ When using Pi's subagents (`pi-subagents`) to run multiple sub-agents in paralle
293
295
  chorus_checkin()
294
296
  chorus_list_tasks({ projectUuid: "<project-uuid>" })
295
297
 
296
- # 2. Spawn sub-agents (async returns immediately with an agentId)
297
- # Pass only task UUIDs — the chorus-pi extension auto-injects the session
298
- # UUID + workflow into the worker's task.
299
- subagent_spawn({
300
- agent: "worker",
301
- task: "Your Chorus task UUID: <task-uuid>\nProject UUID: <project-uuid>\n\nImplement..."
298
+ # 2. Dispatch a worker per ready task in ONE blocking parallel call (max 8).
299
+ # Pass only task + project UUIDs — the chorus-pi extension auto-injects the
300
+ # session UUID + workflow into each worker's task.
301
+ subagent({
302
+ tasks: [
303
+ { agent: "chorus-worker",
304
+ task: "Your Chorus task UUID: <task-uuid>\nProject UUID: <project-uuid>\n\nImplement..." },
305
+ // ... one entry per ready task, max 8 (batch into multiple calls if more)
306
+ ]
302
307
  })
303
- # returns agentId (sa_<uuid>); keep it to close the agent later.
308
+ # The call BLOCKS until every worker finishes and returns their outputs.
309
+ # For a single task, use single mode: subagent({ agent: "chorus-worker", task: "..." })
304
310
  ```
305
311
 
306
312
  **What the Team Lead prompt needs:**
307
- - Task UUID(s)
313
+ - Task UUID(s) + Project UUID
308
314
  - NO session UUID, NO workflow boilerplate — the extension auto-injects everything
309
- - The `agentId` returned by `subagent_spawn` (needed to `subagent_manage close` later)
315
+ - No `agentId` to track and no close step the blocking call owns the worker's whole lifecycle
310
316
 
311
317
  ### Sub-Agent Workflow
312
318
 
313
- The extension injects the session UUID + workflow into the sub-agent's task automatically (at `tool_call` time, before the subprocess starts). The sub-agent reads the `Session UUID:` from its task prompt and follows the injected steps:
319
+ The extension injects the session UUID + workflow into the worker's task automatically (at `tool_call` time, before the subprocess starts). The worker reads the `Session UUID:` from its task prompt and follows the injected steps:
314
320
 
315
321
  ```
316
322
  # 1. Checkin to task (sessionUuid comes from the auto-injected task)
@@ -328,11 +334,9 @@ chorus_report_work({ taskUuid: "<my-task-uuid>", report: "...", sessionUuid: "<m
328
334
  chorus_session_checkout_task({ sessionUuid: "<my-session-uuid>", taskUuid: "<my-task-uuid>" })
329
335
  chorus_submit_for_verify({ taskUuid: "<my-task-uuid>", summary: "..." })
330
336
 
331
- # 6. (Optional) notify the team lead via mailbox you need its agentId
332
- subagent_mailbox({ action: "send", agentId: "<team-lead-agentId>", message: "Task complete" })
333
-
334
- # DO NOT call chorus_close_session — the extension closes it when the
335
- # team lead runs subagent_manage({ action: "close", agentId: "<my-agentId>" })
337
+ # The worker's final message is returned to the Team Lead as the subagent result.
338
+ # DO NOT call chorus_close_session the extension closes the session when the
339
+ # blocking `subagent` call returns.
336
340
  ```
337
341
 
338
342
  ### Handling Task Dependencies (DAG)
@@ -341,25 +345,26 @@ subagent_mailbox({ action: "send", agentId: "<team-lead-agentId>", message: "Tas
341
345
 
342
346
  **Wave-based execution (recommended):**
343
347
  1. `chorus_get_unblocked_tasks` — find ready tasks
344
- 2. `subagent_spawn` workers for Wave 1 (async; keep the agentIds)
345
- 3. Wait for `to_verify` (poll `chorus_list_tasks` or read the async completion messages), then **verify each task** (`chorus_admin_verify_task` → `done`)
346
- 4. `subagent_manage close` each finished worker (releases its slot + closes its Chorus session)
347
- 5. `chorus_get_unblocked_tasks` find newly unblocked tasks (Wave 2)
348
- 6. Repeat until all tasks done
348
+ 2. Dispatch a `chorus-worker` per ready task in ONE blocking `subagent({ tasks: [...] })` call (max 8; batch if more). The call returns when the whole wave has finished (each worker at `to_verify`).
349
+ 3. **Verify each task** spawn `chorus-task-reviewer`, act on its VERDICT, then `chorus_admin_verify_task` → `done`.
350
+ 4. `chorus_get_unblocked_tasks` find newly unblocked tasks (Wave 2)
351
+ 5. Repeat until all tasks done
349
352
 
350
- > **Critical:** `to_verify` does NOT resolve dependencies — only `done` or `closed` does. The Team Lead must verify tasks between waves. Also remember to `subagent_manage close` finished workers Pi limits concurrent sub-agents and `completed` does not release the slot.
353
+ > **Critical:** `to_verify` does NOT resolve dependencies — only `done` or `closed` does. The Team Lead must verify tasks between waves. The blocking `subagent` call already released each worker's slot on return, so there is nothing to close.
351
354
 
352
355
  ### Multiple Tasks Per Sub-Agent
353
356
 
354
- A single sub-agent can work on multiple tasks sequentially:
357
+ A single worker can handle several tasks sequentially — use single mode with an ordered list:
355
358
 
356
359
  ```
357
- subagent_spawn({
358
- agent: "worker",
360
+ subagent({
361
+ agent: "chorus-worker",
359
362
  task: "Your Chorus tasks (work in order):\n1. task-schema-uuid\n2. task-api-uuid (depends on #1)\n\nFor EACH task: checkin -> in_progress -> work -> report -> checkout -> submit_for_verify"
360
363
  })
361
364
  ```
362
365
 
366
+ For strictly dependent stages where each step consumes the previous output, use chain mode: `subagent({ chain: [{ agent: "chorus-worker", task: "..." }, { agent: "chorus-worker", task: "... {previous} ..." }] })`.
367
+
363
368
  ### MCP Access for Sub-Agents
364
369
 
365
370
  Sub-agents need MCP configured at **project level** (`.mcp.json`) or **user level** (`~/.pi/agent/mcp.json`). The chorus-pi extension's session injection works regardless, because it calls chorus over its own MCP-over-HTTP fetch (not the sub-agent's gateway).
@@ -322,7 +322,9 @@ After `chorus_pm_submit_proposal`, the extension nudges you to spawn `chorus-pro
322
322
 
323
323
  After proposal approval, tasks exist in `open` status. Execute them in dependency-ordered waves using subagents. If spawning fails, fall back to main agent execution.
324
324
 
325
- #### Primary: Agent Team (parallel)
325
+ #### Primary: subagent parallel dispatch (wave-based)
326
+
327
+ The `subagent` tool is **blocking** — a parallel dispatch runs every worker in the wave to completion and returns their aggregated output in one call. There is no async spawn, no `agentId` to track, and no manual close. The chorus-pi extension auto-injects each worker's Chorus session UUID + workflow at `tool_call` time and closes the sessions when the dispatch returns.
326
328
 
327
329
  ```
328
330
  wave = 1
@@ -338,35 +340,37 @@ loop:
338
340
  # Stuck -- tasks failed review and can't proceed
339
341
  break with escalation report
340
342
 
341
- # 2. Spawn a sub-agent for each unblocked task (async)
342
- # The chorus-pi extension auto-injects the session UUID + workflow
343
- # into each worker's task at tool_call time.
344
- for each task in unblocked:
345
- subagent_spawn({
346
- agent: "worker",
347
- task: "Your Chorus task UUID: {task.uuid}\nProject UUID: {project-uuid}\n\nImplement the task per its description and acceptance criteria. Read the task, proposal, and project documents for context."
348
- })
349
- # keep the returned agentId (sa_<uuid>) to close the worker later
350
-
351
- # 3. Wait for all sub-agents to complete
352
- # Each sub-agent follows the /skill:develop workflow:
353
- # claim -> in_progress -> develop -> report -> self-check AC -> submit_for_verify
354
- # the extension nudges you to spawn chorus-task-reviewer after submit_for_verify
355
- # (use the blocking `subagent` tool so it waits for the VERDICT)
356
-
357
- # 4. Proceed to Phase 4 (verification) for this wave
343
+ # 2. Dispatch one chorus-worker per unblocked task in a SINGLE blocking
344
+ # parallel call. Max 8 tasks per call (concurrency 4) — if the wave has
345
+ # more than 8 ready tasks, split into batches of <=8 sequential calls.
346
+ # Pass only task + project UUIDs; the chorus-pi extension auto-injects the
347
+ # session UUID + workflow into each worker's task at tool_call time.
348
+ subagent({
349
+ tasks: [
350
+ { agent: "chorus-worker",
351
+ task: "Your Chorus task UUID: {task.uuid}\nProject UUID: {project-uuid}\n\nImplement the task per its description and acceptance criteria. Read the task, proposal, and project documents for context." },
352
+ // ... one entry per unblocked task, max 8
353
+ ]
354
+ })
355
+ # The call BLOCKS until EVERY worker in the wave finishes. Each worker follows
356
+ # the /skill:develop workflow: claim -> in_progress -> report -> self-check AC
357
+ # -> submit_for_verify (leaving its task at to_verify).
358
+ # For a single ready task, use single mode instead:
359
+ # subagent({ agent: "chorus-worker", task: "..." })
360
+
361
+ # 3. Proceed to Phase 4 (verification) for this wave
358
362
  wave += 1
359
363
  ```
360
364
 
361
- **What the sub-agent prompt needs:**
362
- - Task UUID(s)
363
- - Project UUID
365
+ **What each worker task needs:**
366
+ - Task UUID + Project UUID
364
367
  - NO session UUID, NO workflow boilerplate -- the extension auto-injects via tool_call mutation
368
+ - No `agentId` and no close step — the blocking call owns the worker's whole lifecycle
365
369
 
366
370
 
367
371
  #### Fallback: Main Agent (sequential)
368
372
 
369
- If `subagent_spawn` fails (e.g., pi-subagents not installed, permission denied, or sub-agents crash repeatedly), fall back to executing tasks sequentially as the main agent:
373
+ If the `subagent` dispatch is unavailable or its workers fail repeatedly (e.g., the subagent extension is not loaded, permission denied, or the child pi processes crash), fall back to executing tasks sequentially as the main agent:
370
374
 
371
375
  ```
372
376
  for each task in unblocked: