@chorus-aidlc/chorus-openclaw-plugin 0.17.2 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/bin/resolve-spec-mode.sh +107 -0
- package/dist/commands.d.ts +2 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +49 -7
- package/dist/commands.js.map +1 -1
- package/dist/event-router.d.ts +16 -5
- package/dist/event-router.d.ts.map +1 -1
- package/dist/event-router.js +33 -6
- package/dist/event-router.js.map +1 -1
- package/dist/spec-mode.d.ts +81 -0
- package/dist/spec-mode.d.ts.map +1 -0
- package/dist/spec-mode.js +153 -0
- package/dist/spec-mode.js.map +1 -0
- package/package.json +2 -1
- package/skills/brainstorm/SKILL.md +1 -1
- package/skills/chorus/SKILL.md +9 -6
- package/skills/chorus-cli/SKILL.md +1 -1
- package/skills/code-reviewer/SKILL.md +2 -1
- package/skills/develop/SKILL.md +11 -9
- package/skills/docs/SKILL.md +1 -1
- package/skills/idea/SKILL.md +1 -1
- package/skills/openspec-aware/SKILL.md +46 -34
- package/skills/orchestrate/SKILL.md +9 -1
- package/skills/proposal/SKILL.md +13 -10
- package/skills/proposal-reviewer/SKILL.md +4 -2
- package/skills/quick-dev/SKILL.md +3 -3
- package/skills/review/SKILL.md +5 -5
- package/skills/spec-lite/SKILL.md +159 -0
- package/skills/task-reviewer/SKILL.md +5 -1
- package/skills/yolo/SKILL.md +37 -22
- package/src/commands.ts +58 -7
- package/src/event-router.ts +43 -6
- package/src/spec-mode.ts +208 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec-mode resolver for the Chorus OpenClaw plugin.
|
|
3
|
+
*
|
|
4
|
+
* This is the TypeScript reimplementation of the canonical bash resolver
|
|
5
|
+
* `public/chorus-plugin/bin/resolve-spec-mode.sh` (which the bash ports copy
|
|
6
|
+
* byte-identically; the TS ports reimplement + ship a same-contract test). It
|
|
7
|
+
* mirrors the chorus-pi port's `resolveSpecMode` in
|
|
8
|
+
* `packages/chorus-pi/lib/lib.ts` and is the **single source of truth** for the
|
|
9
|
+
* spec mode on OpenClaw.
|
|
10
|
+
*
|
|
11
|
+
* OpenClaw has no SessionStart hook and no per-session context-injection
|
|
12
|
+
* channel, so nothing precomputes the mode into the agent's context. Instead:
|
|
13
|
+
* - the `/chorus` command calls `resolveSpecModeFromEnv` so the resolved mode
|
|
14
|
+
* is a user-visible surface (its one real runtime caller), and
|
|
15
|
+
* - the stage skills (proposal / develop / yolo / openspec-aware) resolve the
|
|
16
|
+
* SAME contract inline, pointing back at this file as the authoritative rule.
|
|
17
|
+
*
|
|
18
|
+
* `resolveSpecMode` itself is pure given injectable fs + execSync, so it can be
|
|
19
|
+
* unit-tested without touching the disk or PATH.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { execSync } from "node:child_process";
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the active Chorus spec mode for a repo. Pure given injectable fs +
|
|
25
|
+
* execSync.
|
|
26
|
+
*
|
|
27
|
+
* Rule (per owner): an explicit `CHORUS_SPEC_MODE` wins; when unset, OpenSpec
|
|
28
|
+
* stays the default whenever it is usable (openspec/ dir + CLI, not disabled),
|
|
29
|
+
* and lite is the fallback only when OpenSpec is absent or disabled. An explicit
|
|
30
|
+
* `=openspec` that isn't usable fails fast (`specFail`).
|
|
31
|
+
*/
|
|
32
|
+
export function resolveSpecMode(inputs, fs, execSync) {
|
|
33
|
+
const projectRoot = inputs.projectRoot || "";
|
|
34
|
+
// --- Is OpenSpec usable? (needs openspec/ dir + CLI on PATH + not disabled) ---
|
|
35
|
+
// enableOpenSpec toggle is checked BEFORE the legacy CHORUS_OPENSPEC_MODE, so a
|
|
36
|
+
// plugin-level opt-out wins the reason string (matches the bash resolver order).
|
|
37
|
+
let openspecDisabled = false;
|
|
38
|
+
let disabledReason = "";
|
|
39
|
+
if ((inputs.enableOpenSpec ?? "true") !== "true") {
|
|
40
|
+
openspecDisabled = true;
|
|
41
|
+
disabledReason = "enableOpenSpec userConfig=false (plugin-level opt-out)";
|
|
42
|
+
}
|
|
43
|
+
else if (inputs.openspecMode === "off") {
|
|
44
|
+
openspecDisabled = true;
|
|
45
|
+
disabledReason = "CHORUS_OPENSPEC_MODE=off (legacy opt-out)";
|
|
46
|
+
}
|
|
47
|
+
let openspecUsable = false;
|
|
48
|
+
let openspecUsableReason = "";
|
|
49
|
+
let openspecHint = "";
|
|
50
|
+
if (openspecDisabled) {
|
|
51
|
+
openspecUsableReason = disabledReason;
|
|
52
|
+
}
|
|
53
|
+
else if (!fs.existsSync(`${projectRoot}/openspec`)) {
|
|
54
|
+
openspecUsableReason = `no openspec/ directory at ${projectRoot}/openspec`;
|
|
55
|
+
openspecHint = "npm i -g @fission-ai/openspec && openspec init";
|
|
56
|
+
}
|
|
57
|
+
else if (!openspecCliPresent(execSync)) {
|
|
58
|
+
openspecUsableReason = "openspec/ directory present but `openspec` CLI not on PATH";
|
|
59
|
+
openspecHint = "npm i -g @fission-ai/openspec";
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
openspecUsable = true;
|
|
63
|
+
openspecUsableReason = "openspec/ directory + openspec CLI both present";
|
|
64
|
+
}
|
|
65
|
+
// --- Resolve CHORUS_SPEC_MODE (unset and "" are treated the same, as in bash) ---
|
|
66
|
+
let specMode;
|
|
67
|
+
let specReason;
|
|
68
|
+
let specFail = "";
|
|
69
|
+
const raw = inputs.specMode ?? "";
|
|
70
|
+
switch (raw) {
|
|
71
|
+
case "lite":
|
|
72
|
+
specMode = "lite";
|
|
73
|
+
specReason = "explicit — Chorus-native lightweight specs in .chorus/specs/<slug>/";
|
|
74
|
+
break;
|
|
75
|
+
case "off":
|
|
76
|
+
specMode = "off";
|
|
77
|
+
specReason = "explicit — free-form, no spec artifact";
|
|
78
|
+
break;
|
|
79
|
+
case "openspec":
|
|
80
|
+
specMode = "openspec";
|
|
81
|
+
if (openspecUsable) {
|
|
82
|
+
specReason = `explicit; ${openspecUsableReason}`;
|
|
83
|
+
}
|
|
84
|
+
else if (openspecDisabled) {
|
|
85
|
+
specReason = `explicit, but OpenSpec is disabled: ${openspecUsableReason}`;
|
|
86
|
+
specFail = `config conflict — CHORUS_SPEC_MODE=openspec vs OpenSpec disabled (${openspecUsableReason}); re-enable OpenSpec or set CHORUS_SPEC_MODE=lite`;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
specReason = `explicit, but OpenSpec is not installed: ${openspecUsableReason}`;
|
|
90
|
+
specFail = `OpenSpec not usable (${openspecUsableReason})`;
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
case "":
|
|
94
|
+
// Unset: OpenSpec is the default when usable; lite is the fallback otherwise.
|
|
95
|
+
if (openspecUsable) {
|
|
96
|
+
specMode = "openspec";
|
|
97
|
+
specReason = `default — ${openspecUsableReason}; set CHORUS_SPEC_MODE=lite for Chorus-native specs, =off to disable`;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
specMode = "lite";
|
|
101
|
+
specReason = `default — OpenSpec not usable (${openspecUsableReason}); using Chorus-native lightweight specs in .chorus/specs/<slug>/`;
|
|
102
|
+
}
|
|
103
|
+
break;
|
|
104
|
+
default:
|
|
105
|
+
// Unrecognized value: treat like unset (OpenSpec-if-usable, else lite).
|
|
106
|
+
if (openspecUsable) {
|
|
107
|
+
specMode = "openspec";
|
|
108
|
+
specReason = `CHORUS_SPEC_MODE='${raw}' unrecognized; falling back to default (${openspecUsableReason})`;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
specMode = "lite";
|
|
112
|
+
specReason = `CHORUS_SPEC_MODE='${raw}' unrecognized; OpenSpec not usable, defaulting to lite`;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const chorusOpenspecActive = specMode === "openspec" && specFail === "";
|
|
116
|
+
return {
|
|
117
|
+
specMode,
|
|
118
|
+
specReason,
|
|
119
|
+
specFail,
|
|
120
|
+
openspecUsable,
|
|
121
|
+
openspecUsableReason,
|
|
122
|
+
openspecHint,
|
|
123
|
+
chorusOpenspecActive,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function openspecCliPresent(execSync) {
|
|
127
|
+
try {
|
|
128
|
+
execSync("command -v openspec", { stdio: "ignore" });
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Convenience wrapper that wires the real Node `fs.existsSync` + `child_process.execSync`
|
|
137
|
+
* and reads the spec-mode env vars off a process-env-shaped bag. This is the
|
|
138
|
+
* `/chorus` command's real runtime caller. Kept out of `resolveSpecMode` so the
|
|
139
|
+
* core stays pure/injectable for tests.
|
|
140
|
+
*/
|
|
141
|
+
export function resolveSpecModeFromEnv(env, projectRoot) {
|
|
142
|
+
const fs = { existsSync: (p) => existsSync(p) };
|
|
143
|
+
const exec = (cmd, opts) => {
|
|
144
|
+
execSync(cmd, opts);
|
|
145
|
+
};
|
|
146
|
+
return resolveSpecMode({
|
|
147
|
+
specMode: env.CHORUS_SPEC_MODE,
|
|
148
|
+
openspecMode: env.CHORUS_OPENSPEC_MODE,
|
|
149
|
+
enableOpenSpec: env.CLAUDE_PLUGIN_OPTION_ENABLEOPENSPEC,
|
|
150
|
+
projectRoot,
|
|
151
|
+
}, fs, exec);
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=spec-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-mode.js","sourceRoot":"","sources":["../src/spec-mode.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chorus-aidlc/chorus-openclaw-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "OpenClaw plugin for Chorus AI-DLC collaboration platform — native MCP + SSE real-time events",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"!src/**/__tests__",
|
|
50
50
|
"dist",
|
|
51
51
|
"skills",
|
|
52
|
+
"bin/resolve-spec-mode.sh",
|
|
52
53
|
"openclaw.plugin.json",
|
|
53
54
|
"README.md"
|
|
54
55
|
]
|
package/skills/chorus/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Chorus AI Agent collaboration platform — overview, common tools,
|
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
@@ -321,18 +321,20 @@ The plugin bundles three independent **review skills**: `/proposal-reviewer`, `/
|
|
|
321
321
|
|
|
322
322
|
Results are advisory — they do not hard-block approval, verification, or ship (the code-review gateway is behavioral — it does not change the Idea's stored status), but you should act on a FAIL by fixing the listed BLOCKERs before proceeding. For a code-review FAIL, the orchestrator invokes **quick-dev** (`/quick-dev`) to create new tasks on the original approved proposal; it does not reopen completed tasks or apply untracked fixes. Group related small BLOCKERs by default and split only materially large or independently testable fixes. Every fix task must pass AC self-check, independent task review, and admin verification. Re-run aggregate review only after all fixes are successfully `done`; a failed or cancelled fix stops the loop and escalates. Keep `maxCodeReviewRounds` authoritative.
|
|
323
323
|
|
|
324
|
-
### 6.
|
|
324
|
+
### 6. Spec mode: OpenSpec (default when usable) vs spec-lite (fallback)
|
|
325
325
|
|
|
326
|
-
|
|
326
|
+
Every PM authoring flow (`/proposal`, `/develop`, `/yolo`) runs in one **spec mode**. OpenClaw has **no SessionStart hook** to precompute it, so the stage skills resolve the mode by sourcing the resolver the plugin ships (`bin/resolve-spec-mode.sh`, byte-identical to the Claude Code copy and drift-guarded; `/chorus spec` prints the same result from the TS mirror `src/spec-mode.ts`). Resolution: an explicit `CHORUS_SPEC_MODE` (`lite`/`openspec`/`off`) wins; when unset, **OpenSpec is the default whenever it is usable** (`CHORUS_OPENSPEC_MODE` ≠ `off`, an `openspec/` directory at the project root, and the `openspec` CLI on `PATH`). When OpenSpec is absent or disabled, the mode falls back to **spec-lite** — a Chorus-native, git-tracked model with a durable local `.chorus/specs/<slug>/spec.md` per capability (never synced) plus dated per-change folders `<slug>/<YYYY-MM-DD>-<change-slug>/` of Chorus-typed docs mirrored 1:1 into Chorus (see the `/spec-lite` skill). `CHORUS_SPEC_MODE=off` selects free-form (no spec artifact).
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
In the OpenSpec path, `/proposal`, `/develop`, `/yolo` write `proposal.md` / `design.md` / spec deltas on disk and mirror them into Chorus drafts (see `/openspec-aware`).
|
|
329
|
+
|
|
330
|
+
**When the user wants OpenSpec on** (they saw spec-lite/off from `/chorus spec` and want the OpenSpec path), actually **enable it for them** — run whichever steps are missing, don't just describe them:
|
|
329
331
|
|
|
330
332
|
```bash
|
|
331
333
|
npm i -g @fission-ai/openspec # 1. install the CLI if it's not on PATH (global, pure Node)
|
|
332
334
|
openspec init --tools none # 2. scaffold the openspec/ directory
|
|
333
335
|
```
|
|
334
336
|
|
|
335
|
-
OpenSpec has no OpenClaw integration (it's not in the `--tools` list), so `--tools none` is correct — Chorus's
|
|
337
|
+
OpenSpec has no OpenClaw integration (it's not in the `--tools` list), so `--tools none` is correct — Chorus's resolution only needs the `openspec/` directory + the CLI, and the stage skills drive the CLI directly. There's no SessionStart banner on OpenClaw — the stage skills re-resolve the mode by sourcing the shipped resolver, so once the directory and CLI are both present the mode resolves to `openspec` and they fold in `/openspec-aware` automatically. To turn OpenSpec off, set `CHORUS_OPENSPEC_MODE=off` — the mode then falls back to **spec-lite** (or set `CHORUS_SPEC_MODE=off` for free-form). `/chorus spec` always prints the resolved mode + reason.
|
|
336
338
|
|
|
337
339
|
---
|
|
338
340
|
|
|
@@ -456,7 +458,8 @@ This is the core overview skill. For stage-specific workflows, use:
|
|
|
456
458
|
| **Development** | `/develop` | Claim Tasks, report work, manual session & sub-agent management |
|
|
457
459
|
| **Review** | `/review` | Approve/reject Proposals, verify Tasks, project governance |
|
|
458
460
|
| **Docs** | `/docs` | Consult the live Chorus documentation site to answer product-usage questions — UI workflow, agent/plugin setup, API/MCP, deployment, operations |
|
|
459
|
-
| **OpenSpec mode** | `openspec-aware` |
|
|
461
|
+
| **OpenSpec mode** | `openspec-aware` | **Shared sub-procedure** invoked by `/proposal`, `/develop`, `/yolo` when the resolved spec mode is a usable OpenSpec (the default when `openspec/` + CLI present and not disabled). Scaffolds `openspec/changes/<slug>/` on disk and mirrors files into Chorus document drafts via `chorus mcp call --arg-file` (`chorus-api.sh` wrapper as fallback). Resolves the whole spec-mode contract by sourcing the shipped `bin/resolve-spec-mode.sh` (no SessionStart hook on OpenClaw). No-op when the mode isn't a usable OpenSpec. |
|
|
462
|
+
| **spec-lite mode** | `spec-lite` | **Shared sub-procedure** and the fallback when OpenSpec isn't usable (or `CHORUS_SPEC_MODE=lite`). Durable local `.chorus/specs/<slug>/spec.md` (never synced) + dated per-change folders of Chorus-typed docs mirrored 1:1 into Chorus via `--arg-file`. No CLI/validation/archive. |
|
|
460
463
|
|
|
461
464
|
### Getting Started
|
|
462
465
|
|
|
@@ -4,7 +4,7 @@ description: Final ship-time review of an Idea's aggregate code change — the w
|
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
@@ -61,6 +61,7 @@ Read each task's work report (in its comments) — the developers describe what
|
|
|
61
61
|
4. **Regression risk / impact on untouched areas / performance** — does the change break or degrade code no single task owned? N+1s, hot-path cost, shared-state contention.
|
|
62
62
|
5. **Feature-level test coverage adequacy** — across the whole feature, are integration seams and end-to-end paths tested, or only per-task units? Gaps between tasks.
|
|
63
63
|
6. **Code soundness, simplicity, correctness** — is the aggregate change correct, reasonably simple, free of obvious defects read as one body of work.
|
|
64
|
+
7. **Intent alignment (whole-feature)** — Also read the Idea's resolved elaboration (`chorus_get_elaboration`); using ONLY human-authored intent (Idea body + human-answered elaboration + human-authored comments; agent-authored entries are audit context, not intent) as the baseline, judge whether the aggregate change still serves the original intent. Flag scope creep, dropped requirements, or intent missed despite passing AC as a **BLOCKER**, unless a cited human entry / human override authorizes it.
|
|
64
65
|
|
|
65
66
|
**Step 4: Run feature-level build/test.** Run the project's declared commands. A broken build or failing tests is an automatic FAIL. Record command + exit code + relevant output. Results are context — verify each dimension independently.
|
|
66
67
|
|
package/skills/develop/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Chorus Development workflow — claim tasks, report work, manage se
|
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
@@ -25,7 +25,7 @@ Developer Agents take Tasks created by PM Agents (via `/proposal`) and turn them
|
|
|
25
25
|
claim --> in_progress --> report work --> self-check AC --> submit for verify --> reviewer --> Admin /review
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
For multi-task execution,
|
|
28
|
+
For multi-task execution, dispatch **one sub-agent per unblocked task** with `sessions_spawn` (whole wave in one message), falling back to **sequential waves** (the main agent works tasks in dependency order) when `sessions_spawn` is unavailable or workers fail repeatedly — see [Wave-Based Execution](#wave-based-execution-on-openclaw) below.
|
|
29
29
|
|
|
30
30
|
---
|
|
31
31
|
|
|
@@ -151,8 +151,10 @@ Each task and proposal includes a `commentCount` field — use it to decide whic
|
|
|
151
151
|
> **⛔ Do not** call `chorus_pm_update_document` directly from the MCP harness with a hand-typed `content` field in OpenSpec mode. The local file is the source of truth; agent-typed content drifts and burns tokens (`openspec-aware` §2 Rule 1).
|
|
152
152
|
>
|
|
153
153
|
> When the LAST task of an OpenSpec idea is verified, run the archive flow yourself (`openspec-aware` §3.9): run `openspec archive <slug> --yes`, then mirror each emitted `openspec/specs/<capability>/spec.md` back via §3.8. **OpenClaw has no PostToolUse hook to remind you** — check after each verify whether the just-verified task was the last of its idea, and if so trigger the archive flow yourself.
|
|
154
|
+
|
|
155
|
+
> **Document update flow (spec-lite mode):** if the originating proposal `description` contains a locator line `Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/`, the `prd` / `tech_design` / … Documents are **persistent mirrors** of the Chorus-typed docs in that **dated change folder**. Load the `spec-lite` skill. Locate the dated folder from the locator line (not by title/type). Edit those `<type>.md` files in place and update the capability's durable `.chorus/specs/<slug>/spec.md` in place too — but **`spec.md` is never mirrored** (local only, no ids). Tick `- [ ]` acceptance points, then re-mirror each edited dated-folder file via `chorus mcp call chorus_pm_update_document … --arg-file content=.chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/<type>.md` against its `documentUuid` (each update auto-increments the Document version = its modification history; `chorus-api.sh mcp-tool …` fallback when `chorus` not on `PATH`), with `chorus_check_response` halting on error. **Git history is the audit trail** (`git log -- .chorus/specs/<slug>/`) — no archive flow, no changelog section. (OpenClaw resolves the spec mode inline; see `openspec-aware` §1.)
|
|
154
156
|
>
|
|
155
|
-
> In the no-OpenSpec fallback (no
|
|
157
|
+
> In the no-OpenSpec, no-spec-lite fallback (no locator line, or resolved mode = free-form), edit the Document content directly via the existing MCP tool with no wrapper, no local file step.
|
|
156
158
|
|
|
157
159
|
### Step 5: Start Working
|
|
158
160
|
|
|
@@ -250,12 +252,12 @@ Obtain an independent VERDICT before the task is verified:
|
|
|
250
252
|
```
|
|
251
253
|
chorus_get_comments({ targetType: "task", targetUuid: "<task-uuid>" })
|
|
252
254
|
```
|
|
253
|
-
Find
|
|
255
|
+
Find THIS round's `VERDICT:` comment — the one posted after your dispatch, not an older round's:
|
|
254
256
|
- **VERDICT: PASS** — All AC verified, no issues. Proceed to admin verification.
|
|
255
257
|
- **VERDICT: PASS WITH NOTES** — All AC verified, minor notes. Proceed to admin verification (notes are non-blocking).
|
|
256
258
|
- **VERDICT: FAIL** — BLOCKERs found. Do NOT verify. Fix the BLOCKERs listed in the reviewer's comment, then resubmit (Step 9).
|
|
257
259
|
|
|
258
|
-
If
|
|
260
|
+
If no new `VERDICT:` comment appears after the reviewer returns, check what it *did* post. A comment reporting that the round limit was reached, or any other explicit refusal to review, is a deliberate escalation to a human: STOP — do not respawn, do not self-review, do not post a VERDICT of your own. If it posted nothing at all, respawn it ONCE, telling it to stay within its turn budget and reserve its last turns for the VERDICT, then apply this same check again to what the retry posts. An explicit refusal from the retry still means STOP; only a second true silence lets you fall back to reviewing manually (Step 8.5 fallback) and post the VERDICT yourself. **Absence is never a PASS.**
|
|
259
261
|
|
|
260
262
|
> **Final code-review gateway (after the Idea's LAST task is verified):** when the task you just verified is the **last** task of its idea-rooted proposal, the feature is about to ship — run the ship-time code-review gateway before declaring the Idea done. Inline (no hook on OpenClaw), same mechanism as Step 8.5: spawn a sub-agent via `sessions_spawn` whose `task` tells it to **invoke the `/code-reviewer` skill** against the idea (pass the `ideaUuid` + round number), and wait for it; fallback is a read-only self-review following the `/code-reviewer` procedure. It reviews the Idea's **aggregate** code change (cross-task integration, architecture, security, regression, feature-level coverage) and posts one `VERDICT:` comment on the **idea**. `PASS` / `PASS WITH NOTES` → ship; `FAIL` → fix via the **quick-dev** workflow (`/quick-dev`): `chorus_create_tasks` with `proposalUuid` set to the **current approved proposal** so the fix tasks attach to it (do not reopen old tasks). Group related small BLOCKERs into one cohesive task by default; split only materially large or independently testable fixes. Each fix task must self-check its acceptance criteria and pass independent task review plus admin verification. Re-run the gateway only after every fix task is successfully `done`; if there is a failed or cancelled fix task, stop and escalate instead. Advisory/behavioral. Run it **before** any idea-completion report.
|
|
261
263
|
|
|
@@ -301,9 +303,9 @@ To keep a long-running session visible/active, send `chorus_session_heartbeat({
|
|
|
301
303
|
|
|
302
304
|
## Wave-Based Execution on OpenClaw
|
|
303
305
|
|
|
304
|
-
> **OpenClaw difference:**
|
|
306
|
+
> **OpenClaw difference:** there is no team or group object to create. Parallelism, where available, comes from dispatching **one sub-agent per unblocked task** with OpenClaw's own `sessions_spawn` tool, issuing the whole wave in a single message — see §"Optional: sub-agent dispatch" below, which also covers the manual session instructions workers need (no SubagentStart hook here). When `sessions_spawn` is unavailable or workers fail repeatedly, you (the main agent) execute tasks **sequentially** in dependency order. That is slower but completes the same pipeline.
|
|
305
307
|
|
|
306
|
-
### Sequential wave loop
|
|
308
|
+
### Sequential wave loop (fallback, always safe)
|
|
307
309
|
|
|
308
310
|
```
|
|
309
311
|
loop:
|
|
@@ -332,11 +334,11 @@ loop:
|
|
|
332
334
|
|
|
333
335
|
> **Critical:** `to_verify` does NOT resolve dependencies — only `done` or `closed` does. A task must be **verified to `done`** (by an Admin, or by you if you hold `task:admin`) before its dependents become unblocked. If you lack `task:admin`, submit each task for verify and ask the project's admin to verify between waves, then re-run `chorus_get_unblocked_tasks`.
|
|
334
336
|
|
|
335
|
-
> **
|
|
337
|
+
> **Parallel form:** to run a wave in parallel, dispatch one sub-agent per unblocked task in a single message (`sessions_spawn`) instead of the serial `for` loop above, then wait for the wave and verify. Everything else in the loop is unchanged.
|
|
336
338
|
|
|
337
339
|
### Optional: sub-agent dispatch
|
|
338
340
|
|
|
339
|
-
If your OpenClaw host *does* support spawning worker sub-agents (
|
|
341
|
+
If your OpenClaw host *does* support spawning worker sub-agents (`sessions_spawn`), you may hand each a task — one per unblocked task, all dispatched in one message so the wave runs in parallel. Because there is no SubagentStart hook, the worker prompt **must** include the manual session instructions explicitly:
|
|
340
342
|
|
|
341
343
|
```
|
|
342
344
|
Your Chorus task UUID: <task-uuid>
|
package/skills/docs/SKILL.md
CHANGED
package/skills/idea/SKILL.md
CHANGED
|
@@ -1,61 +1,73 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: openspec-aware
|
|
3
|
-
description:
|
|
3
|
+
description: OpenSpec-mode authoring for Chorus PM workflows on OpenClaw — the default whenever OpenSpec is usable. Resolves the whole spec-mode contract (lite/openspec/off) by sourcing the plugin's shipped `bin/resolve-spec-mode.sh` (no SessionStart hook on OpenClaw), scaffolds `openspec/changes/<slug>/` on disk, and mirrors Markdown files into Chorus document drafts via `chorus mcp call --arg-file` (bash `chorus-api.sh` wrapper as fallback). When OpenSpec isn't usable the mode resolves to spec-lite (see the spec-lite skill). Required reading for the proposal, develop, and yolo skills.
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# OpenSpec-aware Authoring (OpenClaw plugin)
|
|
13
13
|
|
|
14
|
-
This skill is a **shared sub-procedure** invoked by the Chorus stage skills (proposal, develop, yolo)
|
|
14
|
+
This skill is a **shared sub-procedure** invoked by the Chorus stage skills (proposal, develop, yolo) when the resolved spec mode is a **usable OpenSpec** — spec-driven authoring through the [OpenSpec CLI](https://github.com/Fission-AI/OpenSpec):
|
|
15
15
|
|
|
16
|
-
- Activates when **
|
|
17
|
-
- Otherwise the calling skill
|
|
16
|
+
- Activates when the resolved spec mode is a **usable OpenSpec** (see §1): `CHORUS_SPEC_MODE=openspec` *or* unset, **and** `CHORUS_OPENSPEC_MODE` not `off`, an `openspec/` directory at the project root, and the `openspec` CLI on `PATH`.
|
|
17
|
+
- Otherwise the calling skill follows the resolved mode — **spec-lite** (the default when OpenSpec isn't usable) or free-form (`CHORUS_SPEC_MODE=off`).
|
|
18
|
+
|
|
19
|
+
> **See also — `spec-lite` (the lightweight fallback):** OpenSpec (this skill) stays the default whenever it is usable. When OpenSpec is absent or disabled — or `CHORUS_SPEC_MODE=lite` — the mode resolves to **spec-lite**: a durable local `.chorus/specs/<slug>/spec.md` (never synced) + per-change dated folders `<slug>/<YYYY-MM-DD>-<change-slug>/` of Chorus-typed docs mirrored 1:1 into Chorus via the same `--arg-file` transport. See the `spec-lite` skill.
|
|
18
20
|
|
|
19
21
|
> **Tool namespace:** Chorus MCP tools are exposed under a `chorus__` prefix on OpenClaw (e.g. `chorus__chorus_pm_create_proposal`). Bare names are used in prose for readability — prepend `chorus__` when invoking the MCP tools directly. **Document-mirror calls do NOT go through the MCP harness at all** — they go through the `chorus` CLI (`chorus mcp call`, preferred) or the `chorus-api.sh` wrapper (fallback) (see §2 Rule 1), which talk to the Chorus MCP endpoint over HTTP using your API key, independent of the `chorus__` namespacing.
|
|
20
22
|
|
|
21
23
|
---
|
|
22
24
|
|
|
23
|
-
## §1.
|
|
25
|
+
## §1. Resolve the spec mode — run the shipped resolver, every time (no SessionStart hook on OpenClaw)
|
|
24
26
|
|
|
25
|
-
> **OpenClaw difference:** the Claude Code
|
|
27
|
+
> **OpenClaw difference:** the Claude Code / Codex / Pi ports precompute the spec mode once (in a SessionStart hook or an extension handler) and inject a `## Spec Mode` value into context. **OpenClaw does none of that.** You MUST resolve the mode yourself, at the moment you reach this skill from a stage skill. Do not look for an injected `CHORUS_OPENSPEC_ACTIVE` / `## Spec Mode` value — it will not exist on OpenClaw. Resolve the **whole** contract (lite / openspec / off), not just "is OpenSpec active".
|
|
28
|
+
>
|
|
29
|
+
> **Never hand-roll the rule in this Markdown.** The plugin ships the *canonical* resolver — `bin/resolve-spec-mode.sh`, byte-identical to the Claude Code copy and enforced so by `test-resolver-drift.sh` — precisely so this skill can **source** it instead of reproducing it. A prose copy of the rule drifts from the real one (it has); a sourced script cannot.
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
**The rule:** an explicit `CHORUS_SPEC_MODE` (`lite`/`openspec`/`off`) wins; when unset, **OpenSpec is the default whenever it is usable** — else **spec-lite**. OpenSpec is *usable* only when **all three** hold:
|
|
28
32
|
|
|
29
|
-
1. `CHORUS_OPENSPEC_MODE`
|
|
33
|
+
1. OpenSpec is not disabled (`CHORUS_OPENSPEC_MODE` **not** `off`; the `enableOpenSpec` plugin toggle not `false`).
|
|
30
34
|
2. The project root contains an `openspec/` directory (i.e. someone ran `openspec init` here).
|
|
31
35
|
3. The `openspec` CLI is on `PATH`.
|
|
32
36
|
|
|
33
|
-
Both signals (2) and (3) are required because the OpenSpec authoring path needs the working directory **and** the CLI — having one without the other leaves the workflow unrunnable.
|
|
37
|
+
Both signals (2) and (3) are required because the OpenSpec authoring path needs the working directory **and** the CLI — having one without the other leaves the workflow unrunnable. When OpenSpec is *requested but usable=false* (signal 2 holds but 3 does not, say), surface a hint to the user — "OpenSpec repo detected — install with: `npm i -g @fission-ai/openspec`".
|
|
34
38
|
|
|
35
|
-
###
|
|
39
|
+
### Resolution block (run this)
|
|
36
40
|
|
|
37
41
|
```bash
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
# PROJECT_ROOT is your project root — OpenClaw does not export
|
|
43
|
+
# CLAUDE_PROJECT_DIR, so default to $PWD. The resolver reads it.
|
|
44
|
+
PROJECT_ROOT="${PWD}"
|
|
45
|
+
|
|
46
|
+
# Locate the resolver the plugin ships. Covers the npm install, a global npm
|
|
47
|
+
# install, and a linked dev checkout; the first hit wins.
|
|
48
|
+
RESOLVER=""
|
|
49
|
+
for candidate in \
|
|
50
|
+
"$PWD/node_modules/@chorus-aidlc/chorus-openclaw-plugin/bin/resolve-spec-mode.sh" \
|
|
51
|
+
"$(npm root -g 2>/dev/null)/@chorus-aidlc/chorus-openclaw-plugin/bin/resolve-spec-mode.sh" \
|
|
52
|
+
"$PWD/packages/openclaw-plugin/bin/resolve-spec-mode.sh"
|
|
53
|
+
do
|
|
54
|
+
[ -f "$candidate" ] && { RESOLVER="$candidate"; break; }
|
|
55
|
+
done
|
|
56
|
+
|
|
57
|
+
# shellcheck source=/dev/null
|
|
58
|
+
. "$RESOLVER" # sets SPEC_MODE, SPEC_REASON, SPEC_FAIL, OPENSPEC_HINT, CHORUS_OPENSPEC_ACTIVE
|
|
59
|
+
echo "SPEC_MODE=$SPEC_MODE CHORUS_OPENSPEC_ACTIVE=$CHORUS_OPENSPEC_ACTIVE SPEC_FAIL=${SPEC_FAIL} REASON=${SPEC_REASON}"
|
|
51
60
|
```
|
|
52
61
|
|
|
62
|
+
If `RESOLVER` came out empty (the loop found nothing), **halt** and ask the user to run `/chorus spec` — which resolves the same contract from the plugin's `src/spec-mode.ts` — and paste the result. Do **not** substitute your own detection.
|
|
63
|
+
|
|
53
64
|
Branch on the result:
|
|
54
65
|
|
|
66
|
+
- `SPEC_FAIL` non-empty (explicit `CHORUS_SPEC_MODE=openspec` that can't be honored — either a config conflict or OpenSpec not installed; `OPENSPEC_HINT` carries the install command when it is merely missing) → the caller MUST **halt** and surface it verbatim. Do not silently fall back.
|
|
55
67
|
- `CHORUS_OPENSPEC_ACTIVE=1` → follow §3 (OpenSpec authoring).
|
|
56
|
-
- `
|
|
68
|
+
- Otherwise (`SPEC_MODE=lite` or `off`, no fail) → this skill is a **no-op**; return to the calling skill, which follows the resolved mode: **spec-lite** (the default when OpenSpec isn't usable — see the `spec-lite` skill) or free-form (`off`). **Do not** scaffold `openspec/changes/`. **Do not** add the slug line to the proposal description.
|
|
57
69
|
|
|
58
|
-
Run this
|
|
70
|
+
Run this resolution whenever proposal / develop / yolo reference this skill. There is no host-injected value to read on OpenClaw — but "resolve it yourself" means *run the shipped resolver*, never re-derive the rule from this document's prose.
|
|
59
71
|
|
|
60
72
|
---
|
|
61
73
|
|
|
@@ -363,15 +375,15 @@ When the trigger holds, you perform the archive:
|
|
|
363
375
|
|
|
364
376
|
---
|
|
365
377
|
|
|
366
|
-
## §4. Fallback authoring (
|
|
378
|
+
## §4. Fallback authoring (resolved mode is not a usable OpenSpec)
|
|
367
379
|
|
|
368
|
-
When the §1
|
|
380
|
+
When the §1 resolution does not yield a usable OpenSpec (`CHORUS_OPENSPEC_ACTIVE=0`, no `SPEC_FAIL`), this skill is a **no-op** — return to the calling skill, which follows the resolved mode: **spec-lite** (the default when OpenSpec isn't usable — see the `spec-lite` skill) or free-form (`CHORUS_SPEC_MODE=off`). From this skill's side, regardless of which:
|
|
369
381
|
|
|
370
382
|
- No `openspec/changes/` folder is created or referenced.
|
|
371
383
|
- No `OpenSpec change slug: …` line is added to the proposal description.
|
|
372
|
-
-
|
|
373
|
-
|
|
374
|
-
-
|
|
384
|
+
- The §3.9 archive flow does nothing (no OpenSpec slug → no archive).
|
|
385
|
+
|
|
386
|
+
In **spec-lite** the caller mirrors the dated-folder docs under `.chorus/specs/<slug>/` via the same `--arg-file` transport + Rule 1 / Rule 2 (that is the `spec-lite` skill's job). In **free-form** (`off`) there is no local file source of truth, so document drafts are authored via direct MCP `chorus_pm_add_document_draft` calls with inline `content` — same as before this skill existed, and Rule 1 (file-fill mirror) does not apply.
|
|
375
387
|
|
|
376
388
|
---
|
|
377
389
|
|
|
@@ -455,9 +467,9 @@ This is project-wide policy: no silent errors.
|
|
|
455
467
|
|
|
456
468
|
When invoked from a stage skill (proposal / develop / yolo):
|
|
457
469
|
|
|
458
|
-
1. **Run the §1
|
|
459
|
-
2. If `CHORUS_OPENSPEC_ACTIVE=0` → return to caller
|
|
460
|
-
3. Otherwise:
|
|
470
|
+
1. **Run the §1 resolution yourself** (no SessionStart hook on OpenClaw) by sourcing the shipped `bin/resolve-spec-mode.sh`. It resolves the whole contract (lite / openspec / off); do NOT hand-roll an OpenSpec-only check or re-derive the rule from prose.
|
|
471
|
+
2. If `SPEC_FAIL` is set (explicit `CHORUS_SPEC_MODE=openspec` unusable) → **halt** and surface it. If `CHORUS_OPENSPEC_ACTIVE=0` (resolved mode = spec-lite or free-form) → no-op; return to the caller per the resolved mode (§4).
|
|
472
|
+
3. Otherwise (`CHORUS_OPENSPEC_ACTIVE=1`):
|
|
461
473
|
a. Pick `$SLUG` (§3.1).
|
|
462
474
|
b. `openspec new change "$SLUG"` (§3.2).
|
|
463
475
|
c. Author `proposal.md`, `design.md`, `specs/<capability>/spec.md` (§3.2–§3.3). Mix `ADDED` / `MODIFIED` / `REMOVED` / `RENAMED` blocks as needed; remember `MODIFIED` overwrites the whole Requirement.
|
|
@@ -4,7 +4,7 @@ description: Multi-agent orchestration playbook — coordinate OTHER agents and
|
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
@@ -106,6 +106,14 @@ Guidance: start narrow. If a single owner can hold the whole feature in their he
|
|
|
106
106
|
|
|
107
107
|
---
|
|
108
108
|
|
|
109
|
+
## Replying to the agent who woke you (advisory)
|
|
110
|
+
|
|
111
|
+
When an agent wakes a peer on a shared idea or task — an orchestrator dispatching a worker, or any agent `@mention`-ing another — the wake surfaces the **waker's live session anchor**: a note naming the waking agent and telling the woken peer that the waker has an open conversation on this idea. If you are the woken peer, **reply on the same idea/task resource** (comment there rather than opening a brand-new session) and your reply lands back in the waker's existing live session, keeping the collaboration on one thread instead of scattering into a fresh one.
|
|
112
|
+
|
|
113
|
+
This is **advisory, not routing.** There is no automatic server subscription and nothing is force-delivered — replying on the shared resource is simply *where a reply lands* (via the existing return path), not a guaranteed channel. When the waker's origin is **offline** at wake time, no live anchor is surfaced and the exchange degrades to **notify-only**: the reply reaches the waker as an ordinary notification it picks up on its next turn. Only idea/theme-anchored wakes carry this anchor; ad-hoc wakes with no shared idea do not.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
109
117
|
## Reversed-Conversation gates (you never auto-ship)
|
|
110
118
|
|
|
111
119
|
Chorus is **AI proposes, humans verify**. As orchestrator you enforce that, you do not bypass it:
|
package/skills/proposal/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Chorus Proposal workflow — create proposals with document and tas
|
|
|
4
4
|
license: AGPL-3.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: chorus
|
|
7
|
-
version: "0.
|
|
7
|
+
version: "0.18.0"
|
|
8
8
|
category: project-management
|
|
9
9
|
mcp_server: chorus
|
|
10
10
|
---
|
|
@@ -71,7 +71,9 @@ Elaboration resolved --> Create Proposal --> Add drafts --> Validate --> Submit
|
|
|
71
71
|
|
|
72
72
|
### Step 1: Create an Empty Proposal
|
|
73
73
|
|
|
74
|
-
**
|
|
74
|
+
**Resolve the spec mode (Step 1.5) BEFORE this create.** In OpenSpec and spec-lite modes the container's `description` MUST carry a locator line (`OpenSpec change slug: <slug>` or `Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/`), and `description` can only be set at creation — decide the mode + slug/dated-path first and include that line in this single call. Do NOT create a bare container and then realize you needed it. Free-form mode omits any locator line. (OpenClaw has no SessionStart hook — you resolve the mode inline here; see Step 1.5.)
|
|
75
|
+
|
|
76
|
+
**Recommended approach:** Create the proposal container first (with the mode's locator line in `description` when applicable), then incrementally add document and task drafts one by one.
|
|
75
77
|
|
|
76
78
|
```
|
|
77
79
|
chorus_pm_create_proposal({
|
|
@@ -87,19 +89,20 @@ chorus_pm_create_proposal({
|
|
|
87
89
|
|
|
88
90
|
> **A theme cannot be a proposal input** — `chorus_pm_create_proposal` rejects any input idea with `isContainer = true`. Derive a child idea from the theme and write the proposal on the child instead. (See the theme-ideas section of the `/idea` skill.)
|
|
89
91
|
|
|
90
|
-
### Step 1.5:
|
|
92
|
+
### Step 1.5: Select spec mode
|
|
91
93
|
|
|
92
|
-
|
|
94
|
+
Resolve the spec mode **inline** — OpenClaw has no SessionStart hook to precompute it, so you compute the **whole** contract yourself (not just "is OpenSpec active"), every time you reach this step. Load the `openspec-aware` skill and run its **§1 resolution block (which sources the plugin's shipped `bin/resolve-spec-mode.sh`)**, which yields one of `lite` / `openspec` / `off` (the canonical resolver, byte-identical to the Claude Code copy; `/chorus spec` prints the same result from the TS mirror `src/spec-mode.ts`). The rule: an explicit `CHORUS_SPEC_MODE` (`lite`/`openspec`/`off`) wins; when unset, **OpenSpec is the default whenever usable** (`CHORUS_OPENSPEC_MODE` ≠ `off`, an `openspec/` directory at the project root, and the `openspec` CLI on `PATH`), else **spec-lite**.
|
|
93
95
|
|
|
94
|
-
|
|
96
|
+
- If the resolution says the mode **cannot be honored** (explicit `CHORUS_SPEC_MODE=openspec` but OpenSpec unusable — config-conflict or not-installed), **halt** and surface it; do not silently fall back.
|
|
97
|
+
- Otherwise branch on the resolved mode:
|
|
95
98
|
|
|
96
|
-
|
|
99
|
+
- **resolved = spec-lite** (the default when OpenSpec isn't usable, or explicit `CHORUS_SPEC_MODE=lite`) → load the `spec-lite` skill and follow it: pick `$SLUG` (a **capability**, not one change). Ensure the durable `.chorus/specs/<slug>/spec.md` exists (local-only, **no Chorus ids**; use the `spec-lite` skill's inline durable-spec template) and update it in place. Create this change's **dated folder** `.chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/` with its **synced** Chorus-typed docs (`prd.md` primary, optional `tech_design.md`…; use the `spec-lite` skill's inline dated-folder document template). Put the literal locator line `Spec-lite: .chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/` in the **Step 1 create** `description`, then mirror **each** dated-folder `<type>.md` to its persistent Document (`chorus_pm_add_document_draft --arg-file` first time, `chorus_pm_update_document --arg-file` after) via `chorus mcp call … --arg-file content=.chorus/specs/<slug>/<YYYY-MM-DD>-<change-slug>/<type>.md` (fallback = `chorus-api.sh mcp-tool …` when `chorus` is not on `PATH`). **`spec.md` is never mirrored.** Skip Step 2 below. (Tasks via `chorus_pm_add_task_draft`; no `tasks.md`.)
|
|
97
100
|
|
|
98
|
-
- **OpenSpec
|
|
101
|
+
- **resolved = OpenSpec** (unset with `openspec/` + CLI present and not disabled, or explicit `CHORUS_SPEC_MODE=openspec` that is usable) → follow `openspec-aware` §3. Pick `$SLUG`, scaffold `openspec/changes/<slug>/`, author `proposal.md` / `design.md` / `specs/<capability>/spec.md` locally, then put the literal line `OpenSpec change slug: <slug>` in the **Step 1 create** `description`, and mirror each local file into a document draft.
|
|
99
102
|
|
|
100
103
|
> **⛔ Mandatory in OpenSpec mode:** mirror calls fill `content` from the local file — prefer `chorus mcp call … --arg-file content=<file>`, falling back to the `chorus-api.sh` wrapper with `json_encode_file` when `chorus` is not on `PATH` — see `openspec-aware` §3.6. Do **not** call `chorus_pm_add_document_draft` directly from the MCP harness with a hand-typed `content` field. Re-typing thousands of lines through the LLM burns 20k+ content tokens per proposal and breaks byte-equality with the local source of truth (`openspec-aware` §2 Rule 1 explains the full reasoning). Skip Step 2 below when in OpenSpec mode — the file-fill flow in `openspec-aware` §3.6 replaces it for documents.
|
|
101
104
|
|
|
102
|
-
- **
|
|
105
|
+
- **resolved = free-form** (explicit `CHORUS_SPEC_MODE=off`) → proceed with Step 2 unchanged. Author drafts inline as free-form Markdown via direct MCP `chorus_pm_add_document_draft`.
|
|
103
106
|
|
|
104
107
|
### Step 2: Add Document Drafts
|
|
105
108
|
|
|
@@ -236,11 +239,11 @@ Obtain an independent VERDICT before considering the proposal ready for Admin ap
|
|
|
236
239
|
```
|
|
237
240
|
chorus_get_comments({ targetType: "proposal", targetUuid: "<proposal-uuid>" })
|
|
238
241
|
```
|
|
239
|
-
Find
|
|
242
|
+
Find THIS round's `VERDICT:` comment — the one posted after your dispatch, not an older round's:
|
|
240
243
|
- **PASS** / **PASS WITH NOTES** — proceed; an Admin can approve (notes are non-blocking).
|
|
241
244
|
- **FAIL** — go to Step 6 and fix the BLOCKERs before resubmitting.
|
|
242
245
|
|
|
243
|
-
If
|
|
246
|
+
If no new `VERDICT:` comment appears after the reviewer returns, check what it *did* post. A comment reporting that the round limit was reached, or any other explicit refusal to review, is a deliberate escalation to a human: STOP — do not respawn, do not self-review, do not post a VERDICT of your own. If it posted nothing at all, respawn it ONCE, telling it to stay within its turn budget and reserve its last turns for the VERDICT, then apply this same check again to what the retry posts. An explicit refusal from the retry still means STOP; only a second true silence lets you fall back to reviewing manually (Step 5.5 fallback) and post the VERDICT yourself. **Absence is never a PASS.**
|
|
244
247
|
|
|
245
248
|
### Step 6: Handle Feedback
|
|
246
249
|
|