@esneiderbravo/speclaw 1.0.0 → 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.
- package/README.md +70 -56
- package/dist/cli/commands/cortex.js +49 -0
- package/dist/cli/commands/init.js +21 -15
- package/dist/cli/commands/lawbook.js +34 -1
- package/dist/cli/commands/update.js +25 -2
- package/dist/cli/index.js +10 -1
- package/dist/modules/cortex/brief.js +75 -0
- package/dist/modules/cortex/harness.js +270 -0
- package/dist/modules/cortex/register.js +49 -0
- package/dist/modules/foundation/assets/AGENTS.template.md +13 -6
- package/dist/modules/foundation/assets/CLAUDE.template.md +15 -11
- package/dist/modules/foundation/assets/docs/standards/lawbook.template.md +24 -37
- package/dist/modules/foundation/assets/laws/laws-manifest.json +16 -7
- package/dist/modules/foundation/assets/workflows/speclaw.yml +1 -1
- package/dist/modules/foundation/compile-laws.js +5 -7
- package/dist/modules/foundation/context-budget.js +2 -0
- package/dist/modules/foundation/graph.js +7 -3
- package/dist/modules/foundation/laws.js +30 -32
- package/dist/modules/foundation/scaffold.js +9 -6
- package/dist/modules/foundation/seed-laws.js +263 -0
- package/dist/modules/foundation/setup-tool.js +3 -2
- package/dist/modules/foundation/verify.js +2 -2
- package/dist/modules/lawbook/assets/agents/archiver.md +19 -0
- package/dist/modules/lawbook/assets/agents/explorer.md +24 -0
- package/dist/modules/lawbook/assets/agents/implementer.md +20 -0
- package/dist/modules/lawbook/assets/agents/planner.md +27 -0
- package/dist/modules/lawbook/assets/agents/reviewer.md +25 -0
- package/dist/modules/lawbook/assets/agents/tester.md +21 -0
- package/dist/modules/lawbook/assets/commands/cortex.md +11 -0
- package/dist/modules/lawbook/assets/rules/spec-tasks-mandatory-steps.md +11 -10
- package/dist/modules/lawbook/assets/skills/build/steps/03-implement.md +1 -1
- package/dist/modules/lawbook/assets/skills/build/steps/04-hand-off.md +17 -0
- package/dist/modules/lawbook/assets/skills/cortex/SKILL.md +13 -0
- package/dist/modules/lawbook/assets/skills/cortex/steps/01-load-or-start.md +25 -0
- package/dist/modules/lawbook/assets/skills/cortex/steps/02-dispatch-loop.md +19 -0
- package/dist/modules/lawbook/assets/skills/cortex/steps/03-complete.md +10 -0
- package/dist/modules/lawbook/assets/skills/test/SKILL.md +11 -0
- package/dist/modules/lawbook/assets/skills/{build/steps/04-quality-gates.md → test/steps/01-quality-gates.md} +1 -1
- package/dist/modules/lawbook/assets/skills/{build/steps/05-manual-verification.md → test/steps/02-manual-verification.md} +1 -1
- package/dist/modules/lawbook/assets/skills/{build/steps/06-discipline-reports.md → test/steps/03-discipline-reports.md} +5 -2
- package/dist/modules/lawbook/change-tool.js +22 -0
- package/dist/modules/lawbook/engine.js +4 -0
- package/dist/modules/lawbook/levels.js +9 -3
- package/dist/modules/lawbook/register.js +7 -0
- package/dist/modules/tools/assets/packs.json +1 -6
- package/dist/server.js +4 -1
- package/dist/shared/agents.js +3 -3
- package/dist/shared/exposure.js +2 -2
- package/dist/shared/tool-catalog.js +3 -2
- package/package.json +2 -2
- package/dist/modules/lawbook/assets/skills/build/steps/07-hand-off.md +0 -9
- package/dist/modules/tools/assets/packs/agents/backend-developer.md +0 -61
- package/dist/modules/tools/assets/packs/agents/frontend-developer.md +0 -62
- package/dist/modules/tools/assets/packs/agents/product-strategy-analyst.md +0 -56
package/README.md
CHANGED
|
@@ -9,16 +9,17 @@
|
|
|
9
9
|
<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
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-0E8E8E?labelColor=0B0F10&style=flat-square" alt="MIT"></a>
|
|
11
11
|
<img src="https://img.shields.io/badge/node-%E2%89%A522.16-0E8E8E?labelColor=0B0F10&style=flat-square" alt="Node >= 22.16">
|
|
12
|
-
<img src="https://img.shields.io/badge/
|
|
12
|
+
<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
|
|
19
|
-
<b>written laws</b> (a
|
|
20
|
-
|
|
21
|
-
and the <b>gates</b> that make
|
|
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
|
<img src="https://img.shields.io/badge/no_LLM_·_no_cloud-0E8E8E?labelColor=0B0F10&style=flat-square" alt="no LLM">
|
|
28
29
|
<img src="https://img.shields.io/badge/CLI_+_MCP-0E8E8E?labelColor=0B0F10&style=flat-square" alt="CLI + MCP">
|
|
29
|
-
<img src="https://img.shields.io/badge/
|
|
30
|
+
<img src="https://img.shields.io/badge/9_canonical_tools-0E8E8E?labelColor=0B0F10&style=flat-square" alt="9 tools">
|
|
31
|
+
<img src="https://img.shields.io/badge/Cortex-One_brain._Many_agents.-0E8E8E?labelColor=0B0F10&style=flat-square" alt="Cortex">
|
|
30
32
|
<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
|
|
41
|
-
> agents you pick. This one-liner
|
|
42
|
-
> [CONTRIBUTING.md](CONTRIBUTING.md)); do not invent
|
|
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
|
-
(
|
|
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"> The suite —
|
|
114
|
+
## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle"> 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),
|
|
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
|
|
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** (
|
|
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">
|
|
156
|
+
## <img src="https://raw.githubusercontent.com/esneiderbravo/speclaw/main/brand/diamond.png" height="20" alt="◆" align="absmiddle"> Cortex — One brain. Many agents.
|
|
154
157
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
and
|
|
158
|
-
|
|
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
|
-
|
|
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
|
-
|
|
|
167
|
-
| :-- | :-- |
|
|
168
|
-
| **
|
|
169
|
-
| **
|
|
170
|
-
| **
|
|
171
|
-
| **
|
|
172
|
-
| **
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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 & 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> —
|
|
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`,
|
|
229
|
-
workspace, and **`speclaw.lock`** (rule digests at the repo root).
|
|
230
|
-
**regenerable workflow content is local, not committed**: only `ai-specs/`
|
|
231
|
-
(skills, commands, rules,
|
|
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
|
|
@@ -238,7 +248,10 @@ regenerate `ai-specs/` locally. Optional **`team.owners`** in
|
|
|
238
248
|
**Enforcement artifacts.** For agents that support hooks, speclaw merges its law
|
|
239
249
|
hooks into that agent's settings **by identity** — it never touches hooks you
|
|
240
250
|
added yourself. The compiled law manifest lives in `.speclaw/laws-manifest.json`
|
|
241
|
-
(gitignored)
|
|
251
|
+
(gitignored) and is **adapted to the target tree** on `init`/`update` — speclaw's
|
|
252
|
+
own architecture laws are seeded only when those paths exist, and the cycle law
|
|
253
|
+
follows `apps/*/src`, `packages/*/src`, or `src/` rather than copying
|
|
254
|
+
`src/modules/**` from this package. A context-coverage log feeds `speclaw doctor`.
|
|
242
255
|
|
|
243
256
|
<br/>
|
|
244
257
|
|
|
@@ -249,7 +262,8 @@ added yourself. The compiled law manifest lives in `.speclaw/laws-manifest.json`
|
|
|
249
262
|
> of AI coding agents isn't lack of capability — it's working without the project's
|
|
250
263
|
> tacit knowledge: the rules the team actually lives by. speclaw makes that
|
|
251
264
|
> knowledge explicit, executable, and binding, and gives agents a local map
|
|
252
|
-
> (Compass)
|
|
265
|
+
> (Compass), a lawbook of specs, and **Cortex** to run the multi-agent loop —
|
|
266
|
+
> without burning tokens.
|
|
253
267
|
|
|
254
268
|
This is why "enforced" is literal, not a metaphor. Anthropic's own guidance puts
|
|
255
269
|
it plainly:
|
|
@@ -305,7 +319,7 @@ of the lock in this release. Regenerable IDE mirrors (e.g. `.cursor/rules` →
|
|
|
305
319
|
On GitHub:
|
|
306
320
|
|
|
307
321
|
```yaml
|
|
308
|
-
- uses: esneiderbravo/speclaw@
|
|
322
|
+
- uses: esneiderbravo/speclaw@v2
|
|
309
323
|
```
|
|
310
324
|
|
|
311
325
|
`init` / `update` write `.github/workflows/speclaw.yml` only when that path is
|
|
@@ -354,6 +368,6 @@ without a re-init, splitting files by who owns them:
|
|
|
354
368
|
[CodeGraph](https://github.com/colbymchenry/codegraph) ·
|
|
355
369
|
see [ATTRIBUTION.md](ATTRIBUTION.md)
|
|
356
370
|
|
|
357
|
-
<i>speclaw
|
|
371
|
+
<i>speclaw 2.0 · where specs become law</i>
|
|
358
372
|
|
|
359
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,
|
|
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
|
-
|
|
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
|
-
|
|
60
|
+
};
|
|
61
|
+
if (packIds.length > 0) {
|
|
62
|
+
prompts.packs = () => clack.multiselect({
|
|
59
63
|
message: "Which tool packs to install?",
|
|
60
|
-
options:
|
|
64
|
+
options: packIds.map((id) => ({
|
|
61
65
|
value: id,
|
|
62
66
|
label: id,
|
|
63
|
-
hint:
|
|
67
|
+
hint: availablePacks[id].description.slice(0, 50),
|
|
64
68
|
})),
|
|
65
|
-
initialValues: [
|
|
69
|
+
initialValues: [],
|
|
66
70
|
required: false,
|
|
67
|
-
})
|
|
68
|
-
}
|
|
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)
|
|
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
|
|
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(`
|
|
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,11 +168,34 @@ 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
|
|
172
|
-
"
|
|
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
|
},
|
|
177
|
+
{
|
|
178
|
+
version: "1.0.1",
|
|
179
|
+
describe: "Seed laws match the target repository layout",
|
|
180
|
+
agentPrompt: "- After this update, speclaw rewrites `.speclaw/laws-manifest.json` from the " +
|
|
181
|
+
"target tree: dogfood laws (compass/foundation, ATTRIBUTION.md, local-first, " +
|
|
182
|
+
"protect-templates, shared-stays-inner) are dropped when those paths do not exist; " +
|
|
183
|
+
"the cycle law is scoped to detected source roots (`apps/*/src`, `packages/*/src`, " +
|
|
184
|
+
"`src/`, `lib/`) excluding test files, and considers import edges only. Run " +
|
|
185
|
+
"`speclaw laws compile` if agent rule files look stale, then `speclaw index`.\n" +
|
|
186
|
+
"- Preserve all project-specific wording; only apply these speclaw-authored changes.",
|
|
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
|
+
},
|
|
176
199
|
];
|
|
177
200
|
/**
|
|
178
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 (
|
|
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
|
+
}
|