@chorus-aidlc/chorus-pi 0.0.1 → 0.0.3

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.3",
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"
@@ -15,6 +15,12 @@ Chorus is a work collaboration platform for AI Agents, enabling multiple Agents
15
15
 
16
16
  This is the **core skill** — it covers the platform overview, shared tools, and setup. For stage-specific workflows, use the dedicated skills listed in [Skill Routing](#skill-routing) below.
17
17
 
18
+ > **⚠️ Tool names under Pi — read this first.** Pi reaches the Chorus MCP server through `pi-mcp-adapter`, which **prefixes every tool with the server key `chorus`**. Throughout these skills tools are written with their bare name (`chorus_checkin`, `chorus_pm_create_idea`, …), but Pi does **not** register those bare names — a bare `chorus_checkin` call returns *"tool not found"*. Address each tool by its adapter name instead:
19
+ > - **Namespaced form (preferred):** `mcp__chorus__<tool>` — e.g. `mcp__chorus__chorus_checkin`, `mcp__chorus__chorus_pm_create_idea`.
20
+ > - **Flattened alias:** `chorus_<tool>` → the server prefix produces a **doubled** `chorus_chorus_*` (e.g. `chorus_chorus_pm_create_idea`). The double `chorus_` is expected, not a typo.
21
+ >
22
+ > So: wherever a skill names a tool `chorus_…`, call it as `mcp__chorus__chorus_…`. If a tool ever reads as *"not found"*, you almost certainly dropped the `mcp__chorus__` prefix. This is Pi-specific — Claude Code / Codex resolve the bare names directly.
23
+
18
24
  ---
19
25
 
20
26
  ## Overview
@@ -151,7 +157,7 @@ Projects can be organized into **Project Groups** — a single-level grouping th
151
157
 
152
158
  ### Reports
153
159
 
154
- A **report** is a short idea-completion summary persisted as a `type="report"` Document at end-of-Idea, authored via `chorus_create_report` (gated on `document:write`). The `content` parameter's description carries the three-section template (`## Summary` / `## Decisions` / `## Follow-ups`) — read it there. `/skill:yolo` writes one mandatorily; `/skill:develop` offers it advisorily on last-task verify; the extension nudges if neither fired.
160
+ A **report** is a short idea-completion summary persisted as a `type="report"` Document at end-of-Idea, authored via `chorus_create_report` (gated on `document:write`). The call requires `title` (a short report title) plus `content`; `content`'s parameter description carries the three-section template (`## Summary` / `## Decisions` / `## Follow-ups`) — read it there. `/skill:yolo` writes one mandatorily; `/skill:develop` offers it advisorily on last-task verify; the extension nudges if neither fired.
155
161
 
156
162
  ### References
157
163
 
@@ -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
 
@@ -259,13 +259,13 @@ Once Admin verifies (status: `done`), move to the next available task (back to S
259
259
 
260
260
  ### Step 11: Idea Completion Report (advisory)
261
261
 
262
- If the task you just self-verified was the LAST one of its Idea (every Task across every approved Proposal is now `done`/`closed`) and you have `document:write`, offer to call `chorus_create_report` via `AskUserQuestion`. The `content` parameter's description carries the section template. Skip on decline — the extension will remind on the next run.
262
+ If the task you just self-verified was the LAST one of its Idea (every Task across every approved Proposal is now `done`/`closed`) and you have `document:write`, offer to call `chorus_create_report` via `AskUserQuestion`. The call requires `title` (a short report title) plus `content`; `content`'s parameter description carries the three-section template (`## Summary` / `## Decisions` / `## Follow-ups`). Skip on decline — the extension will remind on the next run.
263
263
 
264
264
  ---
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).
@@ -376,11 +376,18 @@ The hook is read-only; you (the agent) perform the archive:
376
376
 
377
377
  3. **Halt on any error** from `openspec archive` or `chorus_pm_update_document`. Print stderr verbatim, post a comment on the proposal recording the failure (`chorus_add_comment` with `targetType: "proposal"`, `targetUuid: <proposalUuid>`), then stop. No retry. Matches §6 "no silent errors." (Comment on the proposal, not the idea: the failure is in archiving proposal-derived specs, and proposals can be `inputType: "document"` with no idea attached.)
378
378
 
379
- 4. **Confirm success.** Resolve each matching Document UUID and run
380
- `verify-document-roundtrip.sh <local-spec-path> <document-uuid>`. This
381
- performs exact-byte comparison and metadata-only mismatch diagnostics. Do
382
- not replace it with recursive `jq`, `head`, command substitution, or newline
383
- normalization.
379
+ 4. **Confirm success.** For each capability, verify that
380
+ `openspec/specs/<capability>/spec.md` round-trips **byte-equal (modulo a
381
+ single trailing `\n`)** with its Chorus Document. The `--arg-file` mirror path
382
+ already guarantees this, so a spot check is enough: fetch the Document
383
+ `content` and `cmp` it against the local file. **Do NOT use `jq -r`** to
384
+ extract the content — it appends a trailing newline and manufactures a phantom
385
+ 1-byte drift (a spec that mirrored correctly will read as 1 byte longer on the
386
+ server). Use `jq -j` (no trailing newline) or `cmp` directly, and never rely
387
+ on recursive `jq`, `head`, command substitution, or newline normalization.
388
+ (Unlike the Claude Code / Kiro / Codex plugins, the `chorus-pi` package ships
389
+ no `verify-document-roundtrip.sh` — the `--arg-file` byte-equality guarantee
390
+ makes it unnecessary.)
384
391
 
385
392
  **Strict opt-in:** if the verified task is not the last of its idea, OR the proposal description carries no `OpenSpec change slug: <slug>` line, OR the local shell has no `openspec` CLI, the hook exits 0 silently and no archive reminder is injected. Existing free-form behavior is preserved.
386
393
 
@@ -159,7 +159,7 @@ In /yolo mode, the agent generates elaboration questions and answers them itself
159
159
  { id: "b", label: "<option B>" }
160
160
  ]
161
161
  }
162
- // ... 5-8 questions covering functional, technical, scope aspects
162
+ // ... 5-8 questions covering functional, technical_context, scope aspects
163
163
  ]
164
164
  })
165
165
  ```
@@ -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:
@@ -510,7 +514,7 @@ After all waves complete, output a markdown summary:
510
514
 
511
515
  ### Phase 5b: Idea Completion Report (mandatory)
512
516
 
513
- A successful `/yolo` run always finishes the Idea — call `chorus_create_report` once with `proposalUuid` set to the last verified proposal. The `content` parameter's description carries the section template; follow it. Surface the returned `documentUuid` in the Phase 5 summary. Skipping is a protocol violation.
517
+ A successful `/yolo` run always finishes the Idea — call `chorus_create_report` once with `proposalUuid` set to the last verified proposal. The call requires `title` (a short report title) plus `content`; `content`'s parameter description carries the three-section template (`## Summary` / `## Decisions` / `## Follow-ups`); follow it. Surface the returned `documentUuid` in the Phase 5 summary. Skipping is a protocol violation.
514
518
 
515
519
  > **Order:** the completion report is written only **after** the Phase 4.5 code-review gateway returns PASS / PASS WITH NOTES. Never write it while a code-review FAIL is outstanding — the report is a ship-time summary, and the gateway is what clears the feature to ship.
516
520