@esneiderbravo/speclaw 1.0.1 → 2.0.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.
Files changed (47) hide show
  1. package/README.md +66 -55
  2. package/dist/cli/commands/cortex.js +49 -0
  3. package/dist/cli/commands/init.js +21 -15
  4. package/dist/cli/commands/lawbook.js +34 -1
  5. package/dist/cli/commands/update.js +14 -2
  6. package/dist/cli/index.js +10 -1
  7. package/dist/modules/cortex/brief.js +75 -0
  8. package/dist/modules/cortex/harness.js +270 -0
  9. package/dist/modules/cortex/register.js +49 -0
  10. package/dist/modules/foundation/assets/AGENTS.template.md +13 -6
  11. package/dist/modules/foundation/assets/CLAUDE.template.md +15 -11
  12. package/dist/modules/foundation/assets/docs/standards/lawbook.template.md +24 -37
  13. package/dist/modules/foundation/assets/workflows/speclaw.yml +1 -1
  14. package/dist/modules/foundation/context-budget.js +2 -0
  15. package/dist/modules/foundation/setup-tool.js +3 -2
  16. package/dist/modules/lawbook/assets/agents/archiver.md +19 -0
  17. package/dist/modules/lawbook/assets/agents/explorer.md +24 -0
  18. package/dist/modules/lawbook/assets/agents/implementer.md +20 -0
  19. package/dist/modules/lawbook/assets/agents/planner.md +27 -0
  20. package/dist/modules/lawbook/assets/agents/reviewer.md +25 -0
  21. package/dist/modules/lawbook/assets/agents/tester.md +21 -0
  22. package/dist/modules/lawbook/assets/commands/cortex.md +11 -0
  23. package/dist/modules/lawbook/assets/rules/spec-tasks-mandatory-steps.md +11 -10
  24. package/dist/modules/lawbook/assets/skills/build/steps/03-implement.md +1 -1
  25. package/dist/modules/lawbook/assets/skills/build/steps/04-hand-off.md +17 -0
  26. package/dist/modules/lawbook/assets/skills/cortex/SKILL.md +13 -0
  27. package/dist/modules/lawbook/assets/skills/cortex/steps/01-load-or-start.md +25 -0
  28. package/dist/modules/lawbook/assets/skills/cortex/steps/02-dispatch-loop.md +19 -0
  29. package/dist/modules/lawbook/assets/skills/cortex/steps/03-complete.md +10 -0
  30. package/dist/modules/lawbook/assets/skills/test/SKILL.md +11 -0
  31. package/dist/modules/lawbook/assets/skills/{build/steps/04-quality-gates.md → test/steps/01-quality-gates.md} +1 -1
  32. package/dist/modules/lawbook/assets/skills/{build/steps/05-manual-verification.md → test/steps/02-manual-verification.md} +1 -1
  33. package/dist/modules/lawbook/assets/skills/{build/steps/06-discipline-reports.md → test/steps/03-discipline-reports.md} +5 -2
  34. package/dist/modules/lawbook/change-tool.js +22 -0
  35. package/dist/modules/lawbook/engine.js +4 -0
  36. package/dist/modules/lawbook/levels.js +9 -3
  37. package/dist/modules/lawbook/register.js +7 -0
  38. package/dist/modules/tools/assets/packs.json +1 -6
  39. package/dist/server.js +4 -1
  40. package/dist/shared/agents.js +3 -3
  41. package/dist/shared/exposure.js +2 -2
  42. package/dist/shared/tool-catalog.js +3 -2
  43. package/package.json +2 -2
  44. package/dist/modules/lawbook/assets/skills/build/steps/07-hand-off.md +0 -9
  45. package/dist/modules/tools/assets/packs/agents/backend-developer.md +0 -61
  46. package/dist/modules/tools/assets/packs/agents/frontend-developer.md +0 -62
  47. package/dist/modules/tools/assets/packs/agents/product-strategy-analyst.md +0 -56
package/README.md CHANGED
@@ -9,16 +9,17 @@
9
9
  &nbsp;<a href="https://www.npmjs.com/package/@esneiderbravo/speclaw?activeTab=versions"><img src="https://img.shields.io/badge/provenance-SLSA-0E8E8E?labelColor=0B0F10&style=flat-square" alt="npm provenance"></a>
10
10
  &nbsp;<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0E8E8E?labelColor=0B0F10&style=flat-square" alt="MIT"></a>
11
11
  &nbsp;<img src="https://img.shields.io/badge/node-%E2%89%A522.16-0E8E8E?labelColor=0B0F10&style=flat-square" alt="Node >= 22.16">
12
- &nbsp;<img src="https://img.shields.io/badge/v1.0-0E8E8E?labelColor=0B0F10&style=flat-square" alt="v1.0">
12
+ &nbsp;<img src="https://img.shields.io/badge/v2.0-0E8E8E?labelColor=0B0F10&style=flat-square" alt="v2.0">
13
13
 
14
14
  <br/><br/>
15
15
 
16
16
  <p align="center">
17
17
  <b>AI agents are brilliant and blind</b> — brilliant at writing code, blind to <i>your</i>
18
- project's rules. <b>speclaw 1.0</b> hands them what they're missing: the codebase's
19
- <b>written laws</b> (a constitution built from your real code), a <b>local map</b> to
20
- navigate it without burning tokens, a <b>disciplined workflow</b> for every change,
21
- and the <b>gates</b> that make those laws hold in the editor, in CI, and in the PR.
18
+ project's rules. <b>speclaw 2.0</b> hands them what they're missing: the codebase's
19
+ <b>written laws</b> (Foundation), a <b>local map</b> (Compass), a <b>spec-driven lawbook</b>,
20
+ and <b>Cortex</b> — <i>One brain. Many agents.</i> — the multi-agent loop that plans,
21
+ builds, reviews, and archives every non-trivial change. Plus the <b>gates</b> that make
22
+ those laws hold in the editor, in CI, and in the PR.
22
23
  <br/>
23
24
  One command. No cloud, no LLM, no API keys — <b>everything runs on your machine.</b>
24
25
  </p>
@@ -26,7 +27,8 @@ One command. No cloud, no LLM, no API keys — <b>everything runs on your machin
26
27
  <img src="https://img.shields.io/badge/100%25_local-0E8E8E?labelColor=0B0F10&style=flat-square" alt="100% local">
27
28
  &nbsp;<img src="https://img.shields.io/badge/no_LLM_·_no_cloud-0E8E8E?labelColor=0B0F10&style=flat-square" alt="no LLM">
28
29
  &nbsp;<img src="https://img.shields.io/badge/CLI_+_MCP-0E8E8E?labelColor=0B0F10&style=flat-square" alt="CLI + MCP">
29
- &nbsp;<img src="https://img.shields.io/badge/8_canonical_tools-0E8E8E?labelColor=0B0F10&style=flat-square" alt="8 tools">
30
+ &nbsp;<img src="https://img.shields.io/badge/9_canonical_tools-0E8E8E?labelColor=0B0F10&style=flat-square" alt="9 tools">
31
+ &nbsp;<img src="https://img.shields.io/badge/Cortex-One_brain._Many_agents.-0E8E8E?labelColor=0B0F10&style=flat-square" alt="Cortex">
30
32
  &nbsp;<img src="https://img.shields.io/badge/any_agent-0E8E8E?labelColor=0B0F10&style=flat-square" alt="any agent">
31
33
 
32
34
  </div>
@@ -37,10 +39,10 @@ One command. No cloud, no LLM, no API keys — <b>everything runs on your machin
37
39
  > **One command. Detects your agents and wires only those.** Paste
38
40
  > `npx @esneiderbravo/speclaw@latest init` — speclaw detects Claude Code, Cursor,
39
41
  > Codex, Windsurf, and generic `AGENTS.md` surfaces, scaffolds the constitution +
40
- > lawbook, indexes your code, and registers the local MCP server — only for the
41
- > agents you pick. This one-liner is a **stable contract** (see
42
- > [CONTRIBUTING.md](CONTRIBUTING.md)); do not invent alternate install commands in
43
- > directories or newsletters.
42
+ > lawbook + Cortex roles, indexes your code, and registers the local MCP server
43
+ > (nine tools including `cortex`) — only for the agents you pick. This one-liner
44
+ > is a **stable contract** (see [CONTRIBUTING.md](CONTRIBUTING.md)); do not invent
45
+ > alternate install commands in directories or newsletters.
44
46
 
45
47
  <br/>
46
48
 
@@ -74,7 +76,7 @@ The `speclaw` command is then available everywhere — run `speclaw index`,
74
76
  **`speclaw.lock`** baseline for rule-file integrity.
75
77
  3. **Index your code** with a live progress bar and a summary of what it found.
76
78
  4. Register the speclaw **MCP server** in each chosen agent's config
77
- (eight canonical tools; use `--minimal` to omit setup/lifecycle tools).
79
+ (nine canonical tools; use `--minimal` to omit setup/lifecycle tools).
78
80
  5. Print a prompt to paste into your agent so it fills the constitution with your
79
81
  project's real architecture and conventions.
80
82
 
@@ -109,15 +111,16 @@ gh attestation verify <tarball> --owner esneiderbravo
109
111
 
110
112
  <br/>
111
113
 
112
- ## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle">&nbsp; The suite — five modules
114
+ ## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle">&nbsp; The suite — six modules
113
115
 
114
116
  | Module | What it does |
115
117
  | :-- | :-- |
116
118
  | **Foundation** | The project's constitution: `LAWS.md` binding granular standards under `docs/standards/`, plus `CLAUDE.md` / `AGENTS.md`. **Enforced** via agent hooks (`speclaw check`), deterministic graph laws (`speclaw verify` / `laws verify`), multidialect compile (`laws compile`), and committed **`speclaw.lock`** digests + injection scan (`laws lock` / `accept` / `scan`). |
117
119
  | **Compass** | Local code graph (tree-sitter → `node:sqlite`): hybrid find (FTS5 + vectors + RRF + PageRank), impact, affected-tests, hotspots, coupling, visualize. Schema **10**. No LLM — lives in `.speclaw/` (gitignored). |
118
- | **Lawbook** | Spec-driven workflow with **adaptive ceremony** (levels 0–3), bugfix changes + `lawbook_investigate`, EARS linting, requirement **coverage**, and sealed **drift** anchors. Loop: `explore → draft → build → sync → archive`. |
120
+ | **Lawbook** | Spec-driven workflow with **adaptive ceremony** (levels 0–3), EARS linting, requirement **coverage**, sealed **drift** anchors, bugfix + `lawbook_investigate`. Artifacts under `lawbook/`. |
121
+ | **Cortex** | **One brain. Many agents.** The multi-agent loop: durable `harness.json`, MCP tool `cortex` (`status`/`start`/`advance`/`rework`/`brief`), CLI `speclaw cortex`, skill `/lawbook/cortex`. Dispatches explorer → planner → implementer → reviewer → tester → archiver. |
119
122
  | **Team** | Declare `team.owners` in `lawbook/config.yaml`; `speclaw owners --write` compiles a managed trailing block in `.github/CODEOWNERS` (GitHub: last match wins). Doctor checks the posture. CLI-only — no MCP tool. |
120
- | **Tools** | Opt-in packs of skills and subagents (currently the dev-agents). |
123
+ | **Tools** | Opt-in pack catalog (empty by default). Role agents (explorer/planner/implementer/reviewer/tester/archiver) ship with Lawbook + Cortex. |
121
124
 
122
125
  Compass is inspired by [CodeGraph](https://github.com/colbymchenry/codegraph) and the Lawbook module by [OpenSpec](https://github.com/Fission-AI/openspec) — both MIT. speclaw reimplements the ideas as its own code and gives full credit; see [ATTRIBUTION.md](ATTRIBUTION.md).
123
126
 
@@ -131,7 +134,7 @@ tokenizer on this corpus — not a BPE dependency):
131
134
 
132
135
  | | Tokens |
133
136
  | :-- | --: |
134
- | **speclaw budget (always-on)** | **~13.7k** (8 MCP tools · ceiling **14.0k**) |
137
+ | **speclaw budget (always-on)** | **~13.7k** (9 MCP tools · ceiling **14.6k**) |
135
138
  | Spec Kit commands alone | ~18.6k ([spec-kit#1401](https://github.com/github/spec-kit/issues/1401)) |
136
139
 
137
140
  ```bash
@@ -150,28 +153,45 @@ definitions, omitted registration (`--minimal`), and JIT skill steps.
150
153
 
151
154
  <br/>
152
155
 
153
- ## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle">&nbsp; The spec-driven workflow (Lawbook)
156
+ ## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle">&nbsp; Cortex — One brain. Many agents.
154
157
 
155
- Lawbook is speclaw's answer to the biggest risk with AI agents: **code that
156
- drifts from intent.** The intent is written first, the code is made to match it,
157
- and the spec is promoted to the project's canonical record — so nothing
158
- non-trivial lands without a spec change. It's a loop of five steps:
158
+ The biggest risk with AI agents isn't capability — it's **one session doing
159
+ everything**: explore, code, "review," test, and archive with no durable state
160
+ and no role boundaries. **Cortex** is speclaw's answer: a coordinator brain that
161
+ dispatches specialized roles through a durable harness. Lawbook holds the specs;
162
+ Cortex runs the loop. Cheat sheet: [`docs/cortex.md`](docs/cortex.md).
159
163
 
160
- ```
161
- ┌─────────┐ ┌───────┐ ┌───────┐ ┌──────┐ ┌─────────┐
162
- │ explore │ ─▶ │ draft │ ─▶ │ build │ ─▶ │ sync │ ─▶ │ archive │
163
- └─────────┘ └───────┘ └───────┘ └──────┘ └─────────┘
164
- ```
164
+ <p align="center">
165
+ <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/cortex-loop.png" width="800" alt="Cortex — One brain. Many agents.">
166
+ </p>
165
167
 
166
- | Step | What happens |
167
- | :-- | :-- |
168
- | **explore** | Think an idea through *before* committing to it — should we do this, and how. Writes nothing. |
169
- | **draft** | Propose a **ceremony level** (0–3) from graph signals, confirm it, then scaffold only what that level needs under `lawbook/changes/<name>/`. |
170
- | **build** | Implement the tasks in order, keeping code and spec in agreement, and record test results under `reports/`. |
171
- | **sync** | Reconcile the delta specs against what was actually built, then promote them into the canonical `lawbook/specs/`. |
172
- | **archive** | Reconcile, then validate, promote, and move the change to `lawbook/changes/archive/` — **in the same PR**. Gated on tasks, reports, synced specs, and coverage. |
168
+ | Role | Stage | Owns |
169
+ | :-- | :-- | :-- |
170
+ | **explorer** | exploring | Compass-first investigation; writes nothing under `lawbook/` / `src/` |
171
+ | **planner** | planning | Ceremony level + change artifacts; questions always go to the human |
172
+ | **implementer** | implementing | Code + tests; stops at hand-off (no final gates, no archive) |
173
+ | **reviewer** | reviewing | `reports/review.md` PASS/FAIL; no code patches (skipped at level 0) |
174
+ | **tester** | testing | Quality gates, manual verification, discipline reports |
175
+ | **archiver** | archiving | Sync + `lawbook_archive` **in the same PR** |
176
+
177
+ State lives in `lawbook/changes/<name>/harness.json`. Archive is gated on
178
+ harness verdicts (test PASS; review PASS when level ≥ 1) plus tasks, reports,
179
+ sync, and coverage. Max 3 reworks; then the coordinator asks you.
180
+
181
+ <p align="center">
182
+ <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/terminal-cortex.png" width="800" alt="speclaw cortex brief">
183
+ </p>
184
+
185
+ **Drive it three ways — same engine:**
186
+
187
+ - **In your agent** — `/lawbook/cortex` (coordinator) plus per-role skills
188
+ - **MCP** — canonical tool `cortex` (`status` / `start` / `advance` / `rework` / `brief`)
189
+ - **CLI** — `speclaw cortex …`
173
190
 
174
- **Ceremony levels** (confirmed in `change.json`; missing ⇒ level 3):
191
+ ### Lawbook — the specs Cortex runs
192
+
193
+ Lawbook is the **artifact layer**: adaptive ceremony (levels 0–3), EARS linting,
194
+ requirement **coverage**, sealed **drift** anchors, bugfix + investigate.
175
195
 
176
196
  | Level | When | Artifacts |
177
197
  | :-- | :-- | :-- |
@@ -181,25 +201,15 @@ non-trivial lands without a spec change. It's a loop of five steps:
181
201
  | **3** | Full ceremony | proposal + design + tasks + deltas + `reports/` |
182
202
  | **bug** | Regression / RCA | `speclaw lawbook draft --bug` → `bugfix.md` + investigate first |
183
203
 
184
- Plus a **`reports/`** folder — scaffolded at draft, filled at build with one report
185
- per discipline (`backend.md`, `frontend.md`, `api.md`, …). `lawbook_archive`
186
- refuses to archive without it.
187
-
188
204
  > [!NOTE]
189
205
  > **Delta specs are normative and testable.** Requirements use `SHALL`/`MUST`
190
206
  > under `### Requirement:` headers (EARS-friendly), each with `#### Scenario:`
191
207
  > blocks. `lawbook_validate` checks structure; `speclaw coverage` tracks
192
208
  > `req~…~N` → impl/test via `// Covers:` comments.
193
209
 
194
- **Three ways to drive it — same engine, no external CLI:**
195
-
196
- - **In your agent** — `/lawbook:explore`, `/lawbook:draft`, `/lawbook:build`, `/lawbook:sync`, `/lawbook:archive` (and `/lawbook:quick`, investigate).
197
- - **MCP tools** — eight canonical: `compass_explore`, `compass_find`, `compass_diff_context`, `compass_index`, `lawbook_change`, `lawbook_investigate`, `speclaw_setup`, `speclaw_check`.
198
- - **CLI** — `speclaw lawbook …`, `speclaw quick`, `speclaw coverage`, `speclaw drift`.
199
-
200
- The workspace is committed under `lawbook/`: `specs/`, `changes/`,
201
- `changes/archive/`, `anchors/` (drift photographs), and `config.yaml`
202
- (mandatory tasks, ceremony cuts, `team.owners`, EARS knobs).
210
+ The workspace is committed under `lawbook/`: `specs/`, `changes/` (with
211
+ `harness.json` per active change), `changes/archive/`, `anchors/`, and
212
+ `config.yaml`.
203
213
 
204
214
  <br/>
205
215
 
@@ -208,12 +218,12 @@ The workspace is committed under `lawbook/`: `specs/`, `changes/`,
208
218
  speclaw meets you where you are. Everything works through the **CLI** — so no one
209
219
  is blocked by MCP setup — and the same capabilities are exposed as **MCP tools**
210
220
  for a smoother, integrated experience once configured. An agent without MCP can
211
- still use Compass and the lawbook engine by calling the CLI from its shell.
221
+ still use Compass, Cortex, and the lawbook engine by calling the CLI from its shell.
212
222
 
213
223
  <p align="center"><b>CLI</b> — the installer &amp; operator, runs anywhere <code>node</code> does</p>
214
224
  <p align="center"><img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/terminal-cli.png" width="800" alt="speclaw CLI commands"></p>
215
225
 
216
- <p align="center"><b>MCP</b> — eight canonical tools, auto-registered by <code>init</code></p>
226
+ <p align="center"><b>MCP</b> — nine canonical tools (incl. <code>cortex</code>), auto-registered by <code>init</code></p>
217
227
  <p align="center"><img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/terminal-mcp.png" width="800" alt="speclaw MCP tools"></p>
218
228
 
219
229
  <br/>
@@ -225,10 +235,10 @@ still use Compass and the lawbook engine by calling the CLI from its shell.
225
235
  </p>
226
236
 
227
237
  **Committed vs. local.** Your **personalized source** is committed — `LAWS.md`,
228
- `CLAUDE.md`, `AGENTS.md`, `docs/standards/*`, `docs/compass.md`, the `lawbook/`
229
- workspace, and **`speclaw.lock`** (rule digests at the repo root). speclaw's
230
- **regenerable workflow content is local, not committed**: only `ai-specs/`
231
- (skills, commands, rules, agent packs, and its `.speclaw.json` manifest) is
238
+ `CLAUDE.md`, `AGENTS.md`, `docs/standards/*`, `docs/compass.md`, `docs/cortex.md`,
239
+ the `lawbook/` workspace, and **`speclaw.lock`** (rule digests at the repo root).
240
+ speclaw's **regenerable workflow content is local, not committed**: only `ai-specs/`
241
+ (skills, commands, rules, role agents, and its `.speclaw.json` manifest) is
232
242
  gitignored, because `init`/`update` reconstruct it from the package. So **after
233
243
  cloning a speclaw project, run `speclaw init` (or `speclaw update`)** to
234
244
  regenerate `ai-specs/` locally. Optional **`team.owners`** in
@@ -252,7 +262,8 @@ follows `apps/*/src`, `packages/*/src`, or `src/` rather than copying
252
262
  > of AI coding agents isn't lack of capability — it's working without the project's
253
263
  > tacit knowledge: the rules the team actually lives by. speclaw makes that
254
264
  > knowledge explicit, executable, and binding, and gives agents a local map
255
- > (Compass) and a disciplined workflow (Lawbook) to act on it — without burning tokens.
265
+ > (Compass), a lawbook of specs, and **Cortex** to run the multi-agent loop —
266
+ > without burning tokens.
256
267
 
257
268
  This is why "enforced" is literal, not a metaphor. Anthropic's own guidance puts
258
269
  it plainly:
@@ -308,7 +319,7 @@ of the lock in this release. Regenerable IDE mirrors (e.g. `.cursor/rules` →
308
319
  On GitHub:
309
320
 
310
321
  ```yaml
311
- - uses: esneiderbravo/speclaw@v1
322
+ - uses: esneiderbravo/speclaw@v2
312
323
  ```
313
324
 
314
325
  `init` / `update` write `.github/workflows/speclaw.yml` only when that path is
@@ -357,6 +368,6 @@ without a re-init, splitting files by who owns them:
357
368
  [CodeGraph](https://github.com/colbymchenry/codegraph) &nbsp;·&nbsp;
358
369
  see [ATTRIBUTION.md](ATTRIBUTION.md)
359
370
 
360
- <i>speclaw 1.0 · where specs become law</i>
371
+ <i>speclaw 2.0 · where specs become law</i>
361
372
 
362
373
  </div>
@@ -0,0 +1,49 @@
1
+ import { handleHarness, readHarness } from "../../modules/cortex/harness.js";
2
+ import { briefForStage } from "../../modules/cortex/brief.js";
3
+ import { list } from "../lib/args.js";
4
+ import { ui } from "../lib/ui.js";
5
+ const OPS = ["status", "start", "advance", "rework", "brief"];
6
+ /**
7
+ * Run `speclaw cortex <op> --change <name> […]`.
8
+ *
9
+ * @param flags - Parsed flags; `_[0]` is the op.
10
+ */
11
+ export async function runCortex(flags) {
12
+ const cwd = process.cwd();
13
+ const opRaw = flags._[0];
14
+ const op = opRaw;
15
+ if (!OPS.includes(op)) {
16
+ ui.err("Usage: speclaw cortex <status|start|advance|rework|brief> --change <name> [--verdict PASS|FAIL] [--question …] [--pause-questions] [--note …] [--json]");
17
+ process.exit(1);
18
+ }
19
+ const changeName = typeof flags.change === "string" ? flags.change : flags._[1];
20
+ if (!changeName) {
21
+ ui.err("Usage: speclaw cortex <op> --change <name>");
22
+ process.exit(1);
23
+ }
24
+ try {
25
+ if (op === "brief") {
26
+ const state = readHarness(cwd, changeName);
27
+ const brief = briefForStage(state?.stage ?? null);
28
+ const result = { state, ...brief };
29
+ console.log(JSON.stringify(result, null, 2));
30
+ return;
31
+ }
32
+ const verdictRaw = typeof flags.verdict === "string" ? flags.verdict.toUpperCase() : undefined;
33
+ const verdict = verdictRaw === "PASS" || verdictRaw === "FAIL" ? verdictRaw : undefined;
34
+ const result = handleHarness({
35
+ projectPath: cwd,
36
+ change: changeName,
37
+ harnessOp: op,
38
+ verdict: verdict ?? null,
39
+ openQuestions: list(flags.question),
40
+ pauseForQuestions: Boolean(flags["pause-questions"]),
41
+ note: typeof flags.note === "string" ? flags.note : undefined,
42
+ });
43
+ console.log(JSON.stringify(result, null, 2));
44
+ }
45
+ catch (err) {
46
+ ui.err(err.message);
47
+ process.exit(1);
48
+ }
49
+ }
@@ -10,9 +10,7 @@ import { list } from "../lib/args.js";
10
10
  import { ui, c, banner, renderProgress, clearProgress } from "../lib/ui.js";
11
11
  import { checkForUpdates } from "../lib/update-check.js";
12
12
  import { reportTrackedLocalContent } from "../lib/untrack.js";
13
- const PACK_LABELS = {
14
- agents: "dev-agents (backend · frontend · product)",
15
- };
13
+ const PACK_LABELS = {};
16
14
  /** Best-effort project name: the package.json name (unscoped) or the directory name. */
17
15
  export function detectProjectName(cwd) {
18
16
  try {
@@ -26,7 +24,8 @@ export function detectProjectName(cwd) {
26
24
  return path.basename(cwd);
27
25
  }
28
26
  /**
29
- * Interactive setup: pick agents and packs, scaffold, index, and print the handoff prompt.
27
+ * Interactive setup: pick agents (and packs when any exist), scaffold, index,
28
+ * and print the handoff prompt.
30
29
  *
31
30
  * @param flags - Parsed flags; runs interactively on a TTY unless `--agents`, `--yes`, or
32
31
  * `-y` is set. Honors `--project-name`, `--packs`, and `--no-index`.
@@ -37,6 +36,8 @@ export async function runInit(flags) {
37
36
  const interactive = Boolean(process.stdin.isTTY) && !flags.agents && !flags.yes && !flags.y;
38
37
  let agents;
39
38
  let packs;
39
+ const availablePacks = loadPacks();
40
+ const packIds = Object.keys(availablePacks);
40
41
  banner();
41
42
  // Scaffolding with a stale version writes yesterday's foundation, so recommend
42
43
  // upgrading first — prominently, before any prompts, so there's time to cancel.
@@ -48,30 +49,34 @@ export async function runInit(flags) {
48
49
  ui.plain();
49
50
  }
50
51
  if (interactive) {
51
- const answers = await clack.group({
52
+ // Covers: req~remove-agents-pack~1
53
+ const prompts = {
52
54
  agents: () => clack.multiselect({
53
55
  message: "Which agents do you use? (space to select)",
54
56
  options: AGENTS.map((a) => ({ value: a.id, label: a.label })),
55
57
  initialValues: ["claude"],
56
58
  required: true,
57
59
  }),
58
- packs: () => clack.multiselect({
60
+ };
61
+ if (packIds.length > 0) {
62
+ prompts.packs = () => clack.multiselect({
59
63
  message: "Which tool packs to install?",
60
- options: Object.entries(loadPacks()).map(([id, def]) => ({
64
+ options: packIds.map((id) => ({
61
65
  value: id,
62
66
  label: id,
63
- hint: def.description.slice(0, 50),
67
+ hint: availablePacks[id].description.slice(0, 50),
64
68
  })),
65
- initialValues: ["agents"],
69
+ initialValues: [],
66
70
  required: false,
67
- }),
68
- }, { onCancel: () => process.exit(1) });
71
+ });
72
+ }
73
+ const answers = await clack.group(prompts, { onCancel: () => process.exit(1) });
69
74
  agents = answers.agents;
70
- packs = answers.packs;
75
+ packs = answers.packs ?? [];
71
76
  }
72
77
  else {
73
78
  agents = list(flags.agents).length ? list(flags.agents) : ["claude"];
74
- packs = list(flags.packs).length ? list(flags.packs) : ["agents"];
79
+ packs = list(flags.packs);
75
80
  }
76
81
  const unknownAgents = agents.filter((a) => !agentById(a));
77
82
  if (unknownAgents.length) {
@@ -91,7 +96,8 @@ export async function runInit(flags) {
91
96
  minimal: Boolean(flags.minimal),
92
97
  });
93
98
  ui.ok(`Foundation ${c.muted("— LAWS.md + 8 standards + CLAUDE.md/AGENTS.md")}`);
94
- ui.ok(`Lawbook workflow ${c.muted("— draft · build · sync · archive · explore")}`);
99
+ ui.ok(`Lawbook workflow ${c.muted("— cortex · explore · draft · build · sync · archive")}`);
100
+ ui.ok(`Role agents ${c.muted("— explorer · planner · implementer · reviewer · tester · archiver")}`);
95
101
  for (const p of packs)
96
102
  ui.ok(`${PACK_LABELS[p] ?? p + " pack"}`);
97
103
  specInit(cwd);
@@ -132,7 +138,7 @@ export async function runInit(flags) {
132
138
  "commit messages, branch names, PR and ticket language — don't assume. " +
133
139
  "Start with init_project."));
134
140
  ui.plain();
135
- ui.info(`The dev-agents read those standards for your stack — filling them well makes them stack-aware.`);
141
+ ui.info(`Non-trivial work runs through Cortex — use ${ui.code("/lawbook/cortex")} (or the cortex skill).`);
136
142
  ui.plain();
137
143
  ui.info(`Add an agent: ${ui.code("speclaw agent add cursor")}`);
138
144
  ui.info(`Refresh index: ${ui.code("speclaw index")}`);
@@ -2,6 +2,7 @@ import { specInit, specValidate, specSync, specArchive, specList, } from "../../
2
2
  import { handleLevel } from "../../modules/lawbook/quick.js";
3
3
  import { scaffoldBugfix } from "../../modules/lawbook/bugfix.js";
4
4
  import { investigate, formatInvestigateResult } from "../../modules/lawbook/investigate.js";
5
+ import { handleHarness } from "../../modules/cortex/harness.js";
5
6
  import { list } from "../lib/args.js";
6
7
  import { ui } from "../lib/ui.js";
7
8
  function today() {
@@ -144,8 +145,40 @@ export async function runSpec(flags) {
144
145
  }
145
146
  return;
146
147
  }
148
+ case "harness": {
149
+ const opRaw = change;
150
+ const op = opRaw;
151
+ if (!["status", "start", "advance", "rework"].includes(op)) {
152
+ ui.err("Usage: speclaw lawbook harness <status|start|advance|rework> --change <name> [--verdict PASS|FAIL] [--question …] [--pause-questions] [--note …] [--json]");
153
+ process.exit(1);
154
+ }
155
+ const changeName = typeof flags.change === "string" ? flags.change : flags._[2];
156
+ if (!changeName) {
157
+ ui.err("Usage: speclaw lawbook harness <op> --change <name>");
158
+ process.exit(1);
159
+ }
160
+ const verdictRaw = typeof flags.verdict === "string" ? flags.verdict.toUpperCase() : undefined;
161
+ const verdict = verdictRaw === "PASS" || verdictRaw === "FAIL"
162
+ ? verdictRaw
163
+ : undefined;
164
+ const result = handleHarness({
165
+ projectPath: cwd,
166
+ change: changeName,
167
+ harnessOp: op,
168
+ verdict: verdict ?? null,
169
+ openQuestions: list(flags.question),
170
+ pauseForQuestions: Boolean(flags["pause-questions"]),
171
+ note: typeof flags.note === "string" ? flags.note : undefined,
172
+ });
173
+ if (flags.json) {
174
+ console.log(JSON.stringify(result, null, 2));
175
+ return;
176
+ }
177
+ console.log(JSON.stringify(result, null, 2));
178
+ return;
179
+ }
147
180
  default:
148
- ui.err("Usage: speclaw lawbook <init|list|validate|sync|archive|level|draft|investigate> [change]");
181
+ ui.err("Usage: speclaw lawbook <init|list|validate|sync|archive|level|draft|investigate|harness> [change]");
149
182
  process.exit(1);
150
183
  }
151
184
  }
@@ -168,8 +168,9 @@ const MIGRATIONS = [
168
168
  version: "1.0.0",
169
169
  describe: "speclaw 1.0 — official release (enforcement + graph + lawbook + owners)",
170
170
  agentPrompt: "- speclaw **1.0** is the official release: Foundation (hooks + `speclaw.lock` integrity), " +
171
- "Compass (schema 10, eight canonical MCP tools), Lawbook (ceremony 0–3, coverage, drift, " +
172
- "bugfix), and Team (`team.owners` → `speclaw owners --write`). Install remains " +
171
+ "Compass (schema 10), Lawbook (ceremony 0–3, coverage, drift, bugfix), " +
172
+ "Cortex (multi-agent loop; nine canonical MCP tools including `cortex`), " +
173
+ "and Team (`team.owners` → `speclaw owners --write`). Install remains " +
173
174
  "`npx @esneiderbravo/speclaw@latest init`. CI consumers use `esneiderbravo/speclaw@v1`.\n" +
174
175
  "- Preserve all project-specific wording; only apply these speclaw-authored changes.",
175
176
  },
@@ -184,6 +185,17 @@ const MIGRATIONS = [
184
185
  "`speclaw laws compile` if agent rule files look stale, then `speclaw index`.\n" +
185
186
  "- Preserve all project-specific wording; only apply these speclaw-authored changes.",
186
187
  },
188
+ {
189
+ version: "2.0.0",
190
+ describe: "speclaw 2.0 — Cortex (One brain. Many agents.) + nine MCP tools",
191
+ agentPrompt: "- speclaw **2.0** ships **Cortex**: durable multi-agent loop (`harness.json`), " +
192
+ "MCP tool `cortex` (`status`/`start`/`advance`/`rework`/`brief`), CLI " +
193
+ "`speclaw cortex`, skill `/lawbook/cortex`, and role agents " +
194
+ "(explorer → planner → implementer → reviewer → tester → archiver). " +
195
+ "Canonical MCP surface is **nine** tools. CI consumers: " +
196
+ "`esneiderbravo/speclaw@v2`. See `docs/cortex.md`.\n" +
197
+ "- Preserve all project-specific wording; only apply these speclaw-authored changes.",
198
+ },
187
199
  ];
188
200
  /**
189
201
  * Update speclaw and bring the current project up to date without a full re-init:
package/dist/cli/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { parseFlags } from "./lib/args.js";
3
3
  import { ui, header } from "./lib/ui.js";
4
4
  import { maybeNotifyUpdate } from "./lib/update-check.js";
5
- const HELP = `speclaw — spec-driven, agent-ready projects (foundation + Compass + Lawbook)
5
+ const HELP = `speclaw — spec-driven, agent-ready projects (Foundation + Compass + Lawbook + Cortex)
6
6
 
7
7
  Usage: speclaw <command> [options]
8
8
 
@@ -31,6 +31,9 @@ Compass (code intelligence — the same surface agents use via MCP)
31
31
  trace <from> <to> A call path between two nodes
32
32
  visualize [node] Interactive HTML graph → .speclaw/graph.html
33
33
 
34
+ Cortex (One brain. Many agents. — multi-agent loop)
35
+ cortex <op> status|start|advance|rework|brief — drive harness.json (--change)
36
+
34
37
  Lawbook (spec-driven workflow)
35
38
  quick <name> Scaffold a level-0 change (record.md + reports)
36
39
  lawbook init Create the lawbook/ workspace
@@ -41,6 +44,7 @@ Lawbook (spec-driven workflow)
41
44
  lawbook validate <c> Validate a change's artifacts
42
45
  lawbook sync <c> Promote delta specs to canonical
43
46
  lawbook archive <c> Finalize and archive a change
47
+ lawbook harness <op> Deprecated alias for \`speclaw cortex\` (compat)
44
48
 
45
49
  Other
46
50
  doctor Verify the installation (--json, --offline, --strict)
@@ -84,6 +88,7 @@ const HEADER_COMMANDS = new Set([
84
88
  "index",
85
89
  "watch",
86
90
  "lawbook",
91
+ "cortex",
87
92
  "quick",
88
93
  ]);
89
94
  /**
@@ -116,6 +121,8 @@ function maybeHeader(cmd, flags) {
116
121
  return;
117
122
  if (cmd === "lawbook" && flags.json && flags._[0] === "draft")
118
123
  return;
124
+ if (cmd === "cortex" && flags.json)
125
+ return;
119
126
  header();
120
127
  }
121
128
  /** Run the handler for a single command. Returns when the command completes. */
@@ -160,6 +167,8 @@ async function dispatch(cmd, flags) {
160
167
  return (await import("./commands/visualize.js")).runVisualize(flags);
161
168
  case "quick":
162
169
  return (await import("./commands/quick.js")).runQuick(flags);
170
+ case "cortex":
171
+ return (await import("./commands/cortex.js")).runCortex(flags);
163
172
  case "lawbook":
164
173
  return (await import("./commands/lawbook.js")).runSpec(flags);
165
174
  case "doctor":
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Stage → role brief for Cortex coordinators.
3
+ *
4
+ * // Covers: req~cortex-module~1
5
+ */
6
+ /**
7
+ * Map a harness stage to the role the coordinator should dispatch.
8
+ *
9
+ * @param stage - Current harness stage, or null when not started.
10
+ */
11
+ export function briefForStage(stage) {
12
+ switch (stage) {
13
+ case "exploring":
14
+ return {
15
+ role: "explorer",
16
+ agentPath: "ai-specs/agents/explorer.md",
17
+ skillHints: ["explore"],
18
+ nextOps: ["advance"],
19
+ };
20
+ case "planning":
21
+ return {
22
+ role: "planner",
23
+ agentPath: "ai-specs/agents/planner.md",
24
+ skillHints: ["draft"],
25
+ nextOps: ["advance", "pauseForQuestions"],
26
+ };
27
+ case "questions":
28
+ return {
29
+ role: "planner",
30
+ agentPath: "ai-specs/agents/planner.md",
31
+ skillHints: ["draft"],
32
+ nextOps: ["advance"],
33
+ };
34
+ case "implementing":
35
+ return {
36
+ role: "implementer",
37
+ agentPath: "ai-specs/agents/implementer.md",
38
+ skillHints: ["build"],
39
+ nextOps: ["advance"],
40
+ };
41
+ case "reviewing":
42
+ return {
43
+ role: "reviewer",
44
+ agentPath: "ai-specs/agents/reviewer.md",
45
+ skillHints: [],
46
+ nextOps: ["advance", "rework"],
47
+ };
48
+ case "testing":
49
+ return {
50
+ role: "tester",
51
+ agentPath: "ai-specs/agents/tester.md",
52
+ skillHints: ["test"],
53
+ nextOps: ["advance", "rework"],
54
+ };
55
+ case "archiving":
56
+ return {
57
+ role: "archiver",
58
+ agentPath: "ai-specs/agents/archiver.md",
59
+ skillHints: ["sync", "archive"],
60
+ nextOps: ["advance"],
61
+ };
62
+ case "done":
63
+ case null:
64
+ return {
65
+ role: null,
66
+ agentPath: null,
67
+ skillHints: [],
68
+ nextOps: [],
69
+ };
70
+ default: {
71
+ const _exhaustive = stage;
72
+ throw new Error(`unknown stage ${String(_exhaustive)}`);
73
+ }
74
+ }
75
+ }