@mlmcps/ml-specs 1.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 (86) hide show
  1. package/.claude-plugin/marketplace.json +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +106 -0
  4. package/ml-specs/.claude-plugin/plugin.json +11 -0
  5. package/ml-specs/.mcp.json +17 -0
  6. package/ml-specs/CHANGELOG.md +860 -0
  7. package/ml-specs/LICENSE +21 -0
  8. package/ml-specs/README.md +347 -0
  9. package/ml-specs/agents/coder.md +76 -0
  10. package/ml-specs/agents/developer.md +78 -0
  11. package/ml-specs/agents/pr-author.md +36 -0
  12. package/ml-specs/agents/reviewer.md +65 -0
  13. package/ml-specs/agents/scanner.md +66 -0
  14. package/ml-specs/agents/spec-author.md +91 -0
  15. package/ml-specs/agents/spec-reviewer.md +59 -0
  16. package/ml-specs/commands/code.md +29 -0
  17. package/ml-specs/commands/fix.md +67 -0
  18. package/ml-specs/commands/nfr.md +114 -0
  19. package/ml-specs/commands/pr.md +32 -0
  20. package/ml-specs/commands/repo-adopt.md +86 -0
  21. package/ml-specs/commands/repo-doctor.md +57 -0
  22. package/ml-specs/commands/repo-estate.md +79 -0
  23. package/ml-specs/commands/repo-impact.md +77 -0
  24. package/ml-specs/commands/repo-init.md +155 -0
  25. package/ml-specs/commands/repo-refresh.md +58 -0
  26. package/ml-specs/commands/repo-rollout.md +84 -0
  27. package/ml-specs/commands/repo-status.md +59 -0
  28. package/ml-specs/commands/spec-advance.md +81 -0
  29. package/ml-specs/commands/spec-build.md +66 -0
  30. package/ml-specs/commands/spec-fanout.md +64 -0
  31. package/ml-specs/commands/spec-review.md +24 -0
  32. package/ml-specs/commands/spec-verify.md +55 -0
  33. package/ml-specs/commands/spec.md +73 -0
  34. package/ml-specs/hooks/hooks.json +23 -0
  35. package/ml-specs/hooks/knowledge-drift.sh +43 -0
  36. package/ml-specs/hooks/secret-scan.sh +56 -0
  37. package/ml-specs/mcp/README.md +173 -0
  38. package/ml-specs/mcp/ml-specs-server.mjs +708 -0
  39. package/ml-specs/mcp/ml-specs-server.test.mjs +225 -0
  40. package/ml-specs/package.json +44 -0
  41. package/ml-specs/scripts/branch-policy.mjs +71 -0
  42. package/ml-specs/scripts/fix-specs.mjs +289 -0
  43. package/ml-specs/scripts/lib/cli.mjs +43 -0
  44. package/ml-specs/scripts/lib/estate.mjs +108 -0
  45. package/ml-specs/scripts/lib/http.mjs +73 -0
  46. package/ml-specs/scripts/lib/knowledge.mjs +91 -0
  47. package/ml-specs/scripts/lib/knowledge.test.mjs +70 -0
  48. package/ml-specs/scripts/lib/nfr.mjs +119 -0
  49. package/ml-specs/scripts/lib/nfr.test.mjs +89 -0
  50. package/ml-specs/scripts/lib/policy.mjs +114 -0
  51. package/ml-specs/scripts/lib/policy.test.mjs +139 -0
  52. package/ml-specs/scripts/lib/scm.mjs +189 -0
  53. package/ml-specs/scripts/lib/scm.test.mjs +155 -0
  54. package/ml-specs/scripts/lib/specs.mjs +192 -0
  55. package/ml-specs/scripts/lib/specs.test.mjs +69 -0
  56. package/ml-specs/scripts/lib/trace.mjs +90 -0
  57. package/ml-specs/scripts/lib/trace.test.mjs +110 -0
  58. package/ml-specs/scripts/lib/tracker.mjs +257 -0
  59. package/ml-specs/scripts/lib/tracker.test.mjs +177 -0
  60. package/ml-specs/scripts/nfr-compile.mjs +120 -0
  61. package/ml-specs/scripts/scripts.test.mjs +182 -0
  62. package/ml-specs/scripts/spec-brief.mjs +127 -0
  63. package/ml-specs/scripts/spec-dashboard.mjs +331 -0
  64. package/ml-specs/scripts/spec-fanout.mjs +120 -0
  65. package/ml-specs/scripts/spec-gate.mjs +329 -0
  66. package/ml-specs/scripts/spec-trace.mjs +91 -0
  67. package/ml-specs/scripts/survey-estate.mjs +230 -0
  68. package/ml-specs/scripts/tracker-sync.mjs +91 -0
  69. package/ml-specs/skills/knowledge-retrieval/SKILL.md +75 -0
  70. package/ml-specs/templates/CLAUDE.fragment.md +87 -0
  71. package/ml-specs/templates/ci/azure-pipelines-spec-gate.yml +64 -0
  72. package/ml-specs/templates/ci/knowledge-check.mjs +176 -0
  73. package/ml-specs/templates/ci/knowledge-layer.yml +35 -0
  74. package/ml-specs/templates/ci/spec-gate.yml +69 -0
  75. package/ml-specs/templates/docs/ARCHITECTURE.template.md +110 -0
  76. package/ml-specs/templates/docs/ESTATE.template.md +55 -0
  77. package/ml-specs/templates/docs/PATTERNS.template.md +80 -0
  78. package/ml-specs/templates/gitattributes +18 -0
  79. package/ml-specs/templates/hooks/settings.hooks.example.json +32 -0
  80. package/ml-specs/templates/mcp/.mcp.json +34 -0
  81. package/ml-specs/templates/settings.json +18 -0
  82. package/ml-specs/templates/specs/AGENTS.md +57 -0
  83. package/ml-specs/templates/specs/README.md +104 -0
  84. package/ml-specs/templates/specs/TEMPLATE.md +114 -0
  85. package/ml-specs/templates/standards/.mlskills.json +24 -0
  86. package/package.json +36 -0
@@ -0,0 +1,860 @@
1
+ # Changelog — ml-specs
2
+
3
+ All notable changes to this plugin. Bump `version` in `.claude-plugin/plugin.json`, `package.json`,
4
+ **and** the `ml-specs` entry in `../.claude-plugin/marketplace.json` together on each release —
5
+ `release.yml` checks all three against the tag and refuses to publish if any disagrees.
6
+
7
+ Entries before 1.0.0 refer to this plugin under its former name, `sdd-toolkit`.
8
+
9
+ ## [1.0.0]
10
+
11
+ **Breaking.** The plugin is renamed and eight commands change name with it. Existing installs will
12
+ not upgrade in place — see *Migrating* at the end of this entry.
13
+
14
+ ### Changed
15
+
16
+ - **`sdd-toolkit` is now `ml-specs`, in the `ml-tools` marketplace.** "SDD" named a methodology,
17
+ not a product, and it meant nothing to anyone who had not already met the acronym. The plugin now
18
+ sits under the same house prefix as its sibling: `ml-skills` says what good looks like here,
19
+ `ml-specs` is the loop that proves you met it. Marketplace owner, npm package
20
+ (`@mlmcps/ml-specs`), mirror repo and release tag prefix (`ml-specs-v*`) move with it.
21
+
22
+ - **The eight knowledge-layer commands are now `/repo-*`.** `/sdd-init`, `/sdd-refresh`,
23
+ `/sdd-doctor`, `/sdd-adopt`, `/sdd-estate`, `/sdd-impact`, `/sdd-rollout` and `/sdd-status`
24
+ become `/repo-init`, `/repo-refresh`, and so on. None of them was ever about specs — they learn,
25
+ refresh and audit the repo's knowledge layer, and the `sdd-` prefix said only which plugin they
26
+ came from, which the client already namespaces. The surface now splits along what it does:
27
+ **`/spec-*` is the loop, `/repo-*` is the knowledge layer.** The loop commands are unchanged.
28
+
29
+ - **Agents lose their `sdd-` prefix**: `sdd-developer` → `developer`, `sdd-reviewer` → `reviewer`,
30
+ `sdd-scanner` → `scanner`, `sdd-spec-author` → `spec-author`, `sdd-spec-reviewer` →
31
+ `spec-reviewer`. `coder` and `pr-author` already had no prefix; the two conventions were an
32
+ accident of history.
33
+
34
+ - **MCP server renamed** to `ml-specs`, its file to `mcp/ml-specs-server.mjs`, and its resource
35
+ scheme from `sdd://` to `mlspec://`. Tools now arrive as `mcp__ml-specs__*`.
36
+
37
+ ### Added
38
+
39
+ - **The architecture standards are wired into the loop at four points**, replacing prose that told
40
+ each agent to work the routing out for itself. Where a command previously said *"call
41
+ `skill_list`, then `skill_get` for the ones that apply — `openapi-contract` if §4.1 describes
42
+ HTTP, `entity-relationships` if §4.2 changes a schema"*, it now calls one tool that knows that
43
+ mapping:
44
+
45
+ | Phase | Tool | What it replaced |
46
+ |---|---|---|
47
+ | `/spec` | `spec_standards` | hand-picking standards per §4.x |
48
+ | `/spec`, `/spec-review` | `spec_precheck` | nothing — there was no pre-code check |
49
+ | `/spec-verify`, `/spec-advance` | `verify_evidence` | interpreting `check_repo` by hand |
50
+ | `/nfr` | `gate_manifest` | drafting a rule and hoping it fires |
51
+
52
+ `spec_precheck` is the one with no predecessor. It runs the real checkers over the fenced blocks
53
+ in a **draft spec** and reports findings at the spec's own line numbers, so a versioning, money-
54
+ type or idempotency mistake is caught while it still costs one edit. Sections with no fenced
55
+ contract are reported as **not checked** rather than folded into a clean result.
56
+
57
+ - **`verify_evidence` gives the `Verified` gate four verdicts, not two.** `/spec-advance` already
58
+ said in prose that "`Verified` against a gate nothing could fail is a weaker claim than it
59
+ looks"; that judgement is now a field. `inconclusive` — clean, but no standard in scope was
60
+ ratified, so nothing *could* have failed — is reported as the absence of evidence rather than
61
+ rounded up to a pass. Only `pass` clears the gate on its own.
62
+
63
+ - **Five deterministic scripts are exposed as MCP tools** — `spec_gate`, `spec_trace`,
64
+ `spec_brief`, `nfr_check`, `estate_survey`. `scripts/` holds the half of the toolkit that must
65
+ not be a model call, and until now only Claude Code could reach it, which left the most
66
+ load-bearing check in the toolkit — *does this spec have the evidence for `Verified`?* —
67
+ unavailable to CI, to Cursor, and to any other agent. They are invoked as subprocesses rather
68
+ than imported, so they run the same execution path a human gets, and the write-capable flags
69
+ are never passed.
70
+
71
+ - **The developer agent can reach a third-party skill catalog** via `skill_search` / `skill_fetch`
72
+ for the things the eleven standards do not cover — a payment provider, a niche integration.
73
+ Those results are reference material with no authority: where one contradicts a standard, the
74
+ standard wins.
75
+
76
+ ### Fixed
77
+
78
+ - **`/spec-fanout` gave a false all-clear when the estate index was missing.** A repo with no
79
+ `docs/ESTATE.md` reported no affected consumers, which is indistinguishable from "there are
80
+ none" and is the more dangerous of the two answers.
81
+ - **`/spec-brief` refused a Draft spec but not one with no acceptance criteria**, so the emptier
82
+ failure got through the check written to catch it.
83
+ - **The release now fails when `MIRROR_TOKEN` is missing**, instead of shipping npm and reporting
84
+ green while the public mirror — the channel Claude Code actually installs from — sat on an old
85
+ version. 0.20.0, 0.20.1 and 0.21.0 all reported success against a mirror stuck at 0.19.0.
86
+
87
+ ### Migrating
88
+
89
+ Existing installs point at a marketplace and plugin that no longer exist under those names:
90
+
91
+ ```
92
+ /plugin uninstall sdd-toolkit
93
+ /plugin marketplace remove ace-tools
94
+ /plugin marketplace add MLMCPS/ml-claude-plugins
95
+ /plugin install ml-specs
96
+ ```
97
+
98
+ Repo-level `.claude/settings.json` files that enable the plugin need the same edit. Two strings are
99
+ deliberately **not** renamed, because both are live contracts with things outside this repo: the
100
+ `sdd-spec-gate` required-status-check context (renaming it breaks branch protection on every repo
101
+ already configured) and the `<!-- sdd:constraints -->` markers already written into consumers'
102
+ `CLAUDE.md` (renaming them orphans every block already generated). Both need a migration, not a
103
+ find-and-replace.
104
+
105
+ ## [0.21.0]
106
+
107
+ ### Added
108
+ - **The MCP server now serves the plugin's commands as prompts**, so a client outside Claude Code
109
+ gets the workflow and not just the lookups. Until now `@mlmcps/sdd-mcp` exposed four read-only
110
+ tools and nothing else: someone wiring it into Cursor or a custom agent could ask *what specs
111
+ exist* but had no `/spec`, `/spec-build` or `/code` to act on the answer. The commands were
112
+ already the shape of an MCP prompt — frontmatter over a body with an `$ARGUMENTS` placeholder —
113
+ so they are served as one. All 18 arrive, described from their own frontmatter.
114
+
115
+ Clients namespace MCP prompts, so `spec` shows up as `/mcp__sdd-toolkit__spec`, not `/spec`.
116
+ That is the client's doing and cannot be opted out of.
117
+
118
+ - **Agents a command delegates to are inlined into the prompt.** Several commands hand real work
119
+ to a subagent, and MCP has no way to register one — so those steps would have silently done
120
+ nothing, which is the worst failure available here: the command appears to run and quietly skips
121
+ its adversarial pass. Any agent a command names in bold now has its instructions appended to the
122
+ prompt under a heading that says why. The client follows them inline, losing the isolated
123
+ context, tool restrictions and parallelism the plugin gets. `/spec-fanout` degrades most, being
124
+ parallel by design.
125
+
126
+ Matching the bolded name in the command's prose, rather than adding a machine-readable field,
127
+ is deliberate: it is the same string a reader of the command sees, so the two halves cannot
128
+ drift apart without the prose being wrong too.
129
+
130
+ - **Protocol tests for the MCP server** (`mcp/sdd-server.test.mjs`), which had none. They drive it
131
+ the way a client does — spawn the process, write newline-delimited JSON-RPC to stdin, read the
132
+ replies — so they also catch the one failure a unit test cannot: the server not starting at all.
133
+
134
+ ### Changed
135
+ - `commands/` and `agents/` are now part of the `@mlmcps/sdd-mcp` package, since the prompts are
136
+ read from them at runtime. Both directories are already on the public mirror, so this discloses
137
+ nothing new. Skills, hooks, and the plugin's real subagent execution remain Claude Code only.
138
+
139
+ ## [0.20.1]
140
+
141
+ ### Fixed
142
+ - **`/nfr` and `/spec-fanout` were missing from the plugin's own description**, so the two commands
143
+ 0.20.0 added shipped invisible: the description is the command list a user sees in the marketplace
144
+ and in `/plugin`, and neither new command appeared in it. They worked perfectly for anyone who
145
+ already knew they existed, which is not how anyone finds a command.
146
+
147
+ The cause is worth recording because it will recur otherwise. Two manifests carry that list —
148
+ `plugin.json` and the `marketplace.json` entry — and nothing kept either in step with `commands/`.
149
+ Preparing 0.20.0 one was updated and the other was not, and every existing check passed: the
150
+ release gate verifies versions, and this is not a version. `validate-plugin.mjs` now fails when a
151
+ command is missing from either description, and warns when a description names one that no longer
152
+ exists, so the next release cannot repeat it.
153
+
154
+ Git-source installs were unaffected — they resolve from the default branch, which had the fix
155
+ within the hour. This release is for the npm packages and the public mirror, where 0.20.0 is
156
+ immutable.
157
+
158
+ ## [0.20.0]
159
+
160
+ ### Added
161
+ - **The chain from ticket to test case is now checkable — `scripts/spec-trace.mjs`.**
162
+ `spec-gate.mjs` already checked that a spec's claimed evidence exists on disk. Nothing checked
163
+ that the branch, the pull-request title and the test-case ids all carry the *same* spec id — which
164
+ is the chain an auditor actually asks about, and the way it silently stops being true is a
165
+ hand-typed branch name. Every downstream id is now produced by a function with a matching parser,
166
+ so a link that lost the key is a parse failure rather than a divergence nobody notices. Exits
167
+ non-zero, so it gates a pull request.
168
+
169
+ It reports **broken** and **unverifiable** separately, and that distinction is deliberate. A
170
+ `Ticket` typed into a spec's header table cannot be checked from inside the repo; counting it as
171
+ passing would make the whole report a lie, so it is named as unchecked instead.
172
+
173
+ - **`/nfr` — non-functional requirements stop vanishing.** NFRs are the requirements most likely to
174
+ be agreed and then lost, because they do not decompose into user stories: a story breakdown
175
+ flattens "the API shall be performant" into prose that nothing checks, and nobody notices until
176
+ the load test that was never written would have caught it. This compiles each NFR into the two
177
+ things that actually enforce it — a standing constraint in `docs/CONSTRAINTS.md`, and a blocking
178
+ pipeline gate — and **refuses** one with no machine-checkable threshold, because an NFR nothing
179
+ can fail is not a requirement. It also fails when an NFR id has been written into an acceptance
180
+ criterion, which is the exact moment enforcement turns back into a sentence.
181
+
182
+ The constraints it writes are carried into the next spec automatically, so a rule agreed in
183
+ August is in front of whoever writes a spec in November without anyone remembering it exists.
184
+
185
+ - **`/spec-fanout` — a change spanning four services is one change, provably.** Today that is four
186
+ pull requests a reviewer correlates by hand and hopes they got right. Every branch in a fan-out
187
+ now carries the same derived name, and `docs/ESTATE.md` supplies the consumers — including the
188
+ service one hop out that nobody remembered. Plans first, then `--dry-run` prints the exact
189
+ requests, then opens them. Partial failure is reported rather than thrown: a permissions error on
190
+ the fourth repository must not hide that three succeeded.
191
+
192
+ - **`scripts/branch-policy.mjs` — the gate can be checked for still being a gate.** A pipeline that
193
+ runs and reports changes nothing; the load-bearing artifact is the branch policy. The quiet
194
+ failure mode is someone demoting it to advisory to unblock a release on a Friday — nothing breaks,
195
+ no test fails, and merges simply stop being gated until an audit finds the holes months later.
196
+ `install` has no flag that can produce an advisory gate, and `audit` treats advisory, disabled,
197
+ `manualQueueOnly` and GitHub's `enforce_admins: false` as blockers rather than warnings.
198
+
199
+ - **`scripts/tracker-sync.mjs` — governed sync with Azure DevOps or Jira.** A spec and a work item
200
+ can both hold a title, a status and a list of criteria; two stores for one truth diverge silently.
201
+ Exactly one system may now write each field — the spec owns the contract, the tracker owns status,
202
+ assignee and sprint — and an attempt to write the other's field is refused rather than winning.
203
+
204
+ - **`scripts/spec-brief.mjs` — the handoff to whoever implements a spec.** An approved spec is a
205
+ contract, but a scattered one: the criteria are in one section, the constraints in force in
206
+ another file, the gates that will fail the build in a third. The parts most often skipped are the
207
+ ones that cause the rework. This assembles them, and refuses a Draft spec — the contract is still
208
+ being negotiated. It is deliberately **not a prompt**: the same document for a person or an agent,
209
+ because anything an agent needs that a new engineer would not is a sign the spec is
210
+ underspecified, and that fix belongs in the spec.
211
+
212
+ - **`templates/ci/spec-gate.yml` and `templates/ci/azure-pipelines-spec-gate.yml`** — the merge gate
213
+ for both hosts. Both carry the same adoption note as `knowledge-layer.yml`: run it non-blocking
214
+ for a fortnight first, because a gate that fails on day one gets disabled on day two. The Azure
215
+ one audits its own branch policy on every run, which is the only check that survives someone
216
+ changing that setting.
217
+
218
+ - **The first tests in this package — 99 of them**, on Node's built-in runner, no dependencies.
219
+ They run offline: the tracker and source-control clients take an injectable transport, so the
220
+ documents they build are asserted without credentials. `npm test` runs them.
221
+
222
+ ### Changed
223
+ - **`scripts/lib/specs.mjs` gains `criteria[]`, `repos`, `nfrs`, `approvedBy` and `author`.**
224
+ Additive only — `mcp/sdd-server.mjs` and `spec-dashboard.mjs` both read this shape and are
225
+ unaffected. Acceptance criteria now parse as structured rows, so a script can pair each with its
226
+ test case rather than counting checkboxes.
227
+
228
+ ### Fixed
229
+ - **Test files would have shipped in the `@mlmcps/sdd-mcp` tarball.** `files[]` includes
230
+ `scripts/lib/` wholesale, so the new `*.test.mjs` files were being packaged. Excluded via a
231
+ negation pattern; `npm pack --dry-run` now contains none.
232
+
233
+ ### Notes
234
+ - The Azure DevOps, Jira and GitHub clients are **contract-tested, not integration-tested**. They
235
+ build what ADO 7.1, Jira Cloud v3 and GitHub 2022-11-28 document, verified offline against a
236
+ recording transport. **None has run against a live organisation.** Every write path has
237
+ `--dry-run`, which prints the exact requests and needs no credentials — which is also the thing
238
+ to hand whoever has to approve an access token.
239
+ - The read/write split is enforced at runtime, not by convention: the read-only tracker and SCM
240
+ clients are frozen objects carrying only read methods, so a write path from the planning side is
241
+ absent and cannot be re-attached.
242
+
243
+ ## [0.19.0]
244
+
245
+ ### Changed
246
+ - **Both packages are now public on npmjs.org, under MIT.** `npm install @mlmcps/sdd-mcp` and
247
+ `npm install @mlmcps/sdd-toolkit` now work for anyone, with no `.npmrc` scope line and no token.
248
+ Until now they were published to GitHub Packages, which requires authentication *even for public
249
+ packages* and inherited this repository's private access control — so "install the toolkit" meant
250
+ "first get a GitHub PAT with `read:packages`, then map the `@mlmcps` scope in your `.npmrc`". That
251
+ was the friction this change removes.
252
+
253
+ The source repository stays private. What is public is the two published tarballs and nothing
254
+ else — which makes each manifest's `files[]` a disclosure boundary rather than a tidiness rule.
255
+ `@mlmcps/sdd-toolkit` carries the marketplace manifest and the plugin directory;
256
+ `@mlmcps/sdd-mcp` carries the MCP server, `scripts/lib/`, and the CI knowledge-check. Neither
257
+ ships `scripts/`, `examples/`, `CONTRIBUTING.md`, `PUBLISHING.md`, `.github/`, or git history, and
258
+ `validate-plugin.mjs` fails the build if the plugin package's `files[]` widens.
259
+
260
+ **Existing installs keep working but stop receiving updates.** Anything pinned to the GitHub
261
+ Packages registry resolves to 0.18.0 forever — versions from 0.19.0 on exist only on npmjs. Drop
262
+ the `@mlmcps:registry=` line from your `.npmrc` to pick them up.
263
+ - **License changed from `UNLICENSED` to `MIT`** in both manifests, with a `LICENSE` file at the
264
+ repo root. A public package under `UNLICENSED` tells people they may not use what you just handed
265
+ them; MIT is the grant that makes a public publish coherent. This applies from 0.19.0 onward —
266
+ it does not retroactively relicense 0.16.0–0.18.0.
267
+ - **`release.yml` publishes to npmjs with an `NPM_TOKEN` secret** instead of the built-in
268
+ `GITHUB_TOKEN`, and fails fast when that secret is missing — before the manifest and CHANGELOG
269
+ gates, so a release can never get half-published. `packages: write` is no longer requested.
270
+
271
+ ## [0.18.0]
272
+
273
+ This release is about what the toolkit *costs to run*. Nothing changes about the workflow; the same
274
+ commands do the same work while reading less, reasoning less about what a script can settle, and
275
+ running the expensive parts concurrently.
276
+
277
+ ### Added
278
+ - **`sdd-scanner` agent — the learn phase no longer fills the calling session's context.** The
279
+ commands that study a codebase (`/sdd-init`, `/sdd-refresh`, `/sdd-estate`) used to read source
280
+ files inline, so every file sampled to write a doc stayed in the window for the rest of the run —
281
+ while the model was writing docs, not reading code. Those commands now spawn scanners instead, in
282
+ a single message so they run concurrently, and each returns a **capped findings block of
283
+ `file:line` citations and never file contents**. `/sdd-init` fans out three briefs (stack,
284
+ structure, patterns); `/sdd-estate` fans out one per peer repo, so N peers cost roughly one peer's
285
+ wall-clock instead of N.
286
+ - **`scripts/spec-gate.mjs` — the mechanical half of a `/spec-advance` gate, checked exactly.**
287
+ Lifecycle ordering, leftover `<placeholder>` text, whether every acceptance criterion is ticked,
288
+ whether **every test file named in the §6 table exists on disk**, and whether the recorded branch
289
+ is merged. That work was being done by a model re-reading the spec and globbing — slow, paid for
290
+ on every run, and the half most likely to be done sloppily, since a named-but-missing test is the
291
+ most common way a status ends up claiming evidence that is not there. It deliberately refuses to
292
+ judge what a script cannot witness (human approval, whether a §8 question is blocking, whether the
293
+ suite ran green) and marks those `MANUAL`, because a `PASS` there would be believed. Pure Node, no
294
+ dependencies, no network calls; exits non-zero on any `FAIL` so it also works as a CI gate.
295
+
296
+ ### Changed
297
+ - **`/sdd-refresh` re-learns only what moved.** It now derives the changed surface from
298
+ `git diff --name-only <last-doc-commit>..HEAD` and scopes the scanners to those paths, re-detecting
299
+ the stack only when the manifest itself changed — and stops early, saying so, when nothing has
300
+ changed at all. Re-learning an entire repo to update a few drifted sections was the single most
301
+ wasteful path in the toolkit. It still falls back to a full re-learn when most of the source moved
302
+ or the last-doc commit is unreachable, and says which it did.
303
+ - **`CLAUDE.fragment.md` trimmed from 118 lines to 80** (~1,690 → ~1,220 tokens). This file is
304
+ merged into every adopted repo's `CLAUDE.md`, so it is paid for on every session in every repo —
305
+ the one place in the toolkit where prose has a recurring cost. What went: the
306
+ `PLAN/FILES/IMPLEMENTATION/REVIEW/TESTS` block and the nine-rule working agreement, both of which
307
+ the `coder` agent already carries in full and only needs when it actually runs. What stayed,
308
+ verbatim: the no-AI-attribution policy and the knowledge-layer retrieval order, which is the part
309
+ that pays for itself by keeping later reads small.
310
+ - **Model routing on the mechanical commands.** `/spec-advance`, `/sdd-impact`, `/sdd-estate` and
311
+ `/sdd-rollout` now run on Sonnet — checking a fixed gate table, classifying a diff against a fixed
312
+ taxonomy, filling a template, and summarizing a script's output are not Opus-shaped work.
313
+ `/spec-review`, `/spec-verify` and both reviewer agents deliberately stay on the inherited model:
314
+ adversarial review is exactly what the larger model is for, and cheapening it would trade the
315
+ toolkit's main guarantee for a small saving.
316
+ - **Agent and command descriptions trimmed to what routing actually needs** (~1,390 → ~1,260 tokens
317
+ including the new agent). Descriptions are loaded on every session whether or not the command
318
+ runs, so an enumeration of supported languages or an output format in a `description` is paid for
319
+ continuously and used never.
320
+
321
+ ## [0.17.0]
322
+
323
+ ### Added
324
+ - **`@mlmcps/sdd-toolkit` — install the plugin without read access to the marketplace repo.** Until
325
+ now the only marketplace source was `github`, and Claude Code installs that with a `git clone`, so
326
+ anyone who could install could also take a full copy of the repo — history, tooling, everything.
327
+ Read access on GitHub *is* download access; there is no install-only permission, so the fix had to
328
+ be a different artifact rather than a different setting. This package carries the marketplace
329
+ manifest and the plugin directory and nothing else, letting a team be granted the package alone.
330
+ Point `.claude/settings.json` at `{ "source": "npm", "package": "@mlmcps/sdd-toolkit" }` instead of
331
+ the github source. The trade-off is when updates arrive: the git source updates on merge to the
332
+ default branch, this one only when a tag is published.
333
+
334
+ ### Changed
335
+ - **One tag now publishes both packages** — `@mlmcps/sdd-mcp` (the MCP server, for non-Claude
336
+ clients) and `@mlmcps/sdd-toolkit` (the plugin) — with the marketplace package published second,
337
+ so a failure there still leaves the MCP server shipped rather than advertising a plugin version
338
+ that never existed.
339
+ - `validate-plugin.mjs` gained the fifth version location and a guard that **fails the build if the
340
+ plugin package's `files[]` widens beyond the plugin**. That package exists specifically to
341
+ withhold repo tooling, and a well-meaning `"scripts/"` added later would hand it over with no
342
+ visible symptom — the kind of regression only an explicit check catches.
343
+
344
+ ## [0.16.0]
345
+
346
+ ### Changed
347
+ - **Moved to the `MLMCPS` organisation** — the marketplace source is now
348
+ `MLMCPS/ace-claude-plugins`. Existing installs keep working because GitHub redirects the old path,
349
+ but update the `repo` value in your `.claude/settings.json` rather than relying on that redirect
350
+ outliving the move. The point of the move is how access is granted: an org team with read
351
+ permission lets teammates install the toolkit without being able to change it, which per-person
352
+ collaborator invites on a personal account do not scale to.
353
+ - **Breaking, npm consumers only: the package is now `@mlmcps/sdd-mcp`.** GitHub Packages requires
354
+ the npm scope to match the owning account, so moving the repo forced the rename — it was not a
355
+ preference. `@venkatmotivity/sdd-mcp` stays published at 0.13.0–0.15.0 and keeps working, but will
356
+ never receive another version: published package versions cannot be renamed or transferred. Anyone
357
+ pinning the old name in `.mcp.json` must change it to keep getting updates, and **0.16.0 is the
358
+ first version to exist under the new scope** — pinning `@mlmcps/sdd-mcp` at anything earlier
359
+ resolves to nothing. Claude Code users are unaffected either way: the MCP server ships inside the
360
+ plugin and was never installed from npm.
361
+
362
+ ## [0.15.0]
363
+
364
+ ### Added
365
+ - **`templates/settings.json`** — committed project settings that stop AI attribution reaching
366
+ commits and PRs, by setting `attribution.commit` and `attribution.pr` to empty. 0.14.1 stated that
367
+ rule in `CLAUDE.fragment.md`, but prose is something a model has to read and remember; this is
368
+ enforced by Claude Code itself, so the guarantee no longer depends on an instruction being
369
+ followed. The two work together — `CLAUDE.md` explains why, the setting makes it true.
370
+
371
+ ### Changed
372
+ - **`/sdd-init` and `/sdd-adopt` now install that setting** (step 10 and step 9 respectively)
373
+ rather than merely offering it, because it is policy rather than something project-specific like
374
+ hook commands or CI invocations. Both merge only the `attribution` key into
375
+ `.claude/settings.json`, leaving every other key untouched, and both keep an existing
376
+ `attribution` value and report it rather than overwriting a deliberate choice. Because the file is
377
+ committed, it applies to everyone who clones the repo with no per-machine setup — the alternative
378
+ was a per-developer git hook, which secures exactly one laptop and silently misses every teammate,
379
+ every cloud session, and CI.
380
+
381
+ ## [0.14.1]
382
+
383
+ ### Added
384
+ - **`TEAM-SETUP.md`** at the marketplace root — the per-repo auto-enable rollout, what to verify
385
+ afterwards, and the private-repo access prerequisite that causes most failed setups. A
386
+ marketplace installs over a plain `git clone`, so a teammate without repo access hits a confusing
387
+ failure rather than a permission error; that prerequisite now has a documented home instead of
388
+ living in the head of whoever set it up first. `README.md` links to it, and the validator checks
389
+ its relative links along with the other docs.
390
+
391
+ ### Changed
392
+ - **No AI attribution in commits or PRs.** The `pr-author` agent, `/pr`, `/fix`, `/spec-build`, and
393
+ the `CLAUDE.fragment.md` template now all state that commit messages, trailers, PR titles, and PR
394
+ bodies name the humans who own the change and nothing else — no assistant `Co-Authored-By:` line,
395
+ no "Generated with" line, no model or vendor name, no badge or emoji. The fragment and
396
+ `/spec-build` also spell out why a stray trailer is not a local problem: a squash merge
397
+ aggregates trailers from **every** commit on the branch, so one line added early resurfaces on
398
+ the merge commit long after, attributed to a tool rather than to the people who own the work.
399
+ - **Releases no longer cut a GitHub Release** (`release.yml`). Every Release carries
400
+ auto-generated "Source code (zip/tar.gz)" archives that GitHub builds from the tag, with no
401
+ setting to suppress them — so the tag plus the published package is now the release, and
402
+ `CHANGELOG.md` is where per-version notes live. The CHANGELOG gate survives the change (a
403
+ version with no section still fails before anything publishes), and the workflow's `contents`
404
+ permission drops from `write` to `read`, since creating the Release was the only step that
405
+ needed it.
406
+
407
+ ## [0.14.0]
408
+
409
+ ### Added
410
+ - **Release automation** (`.github/workflows/release.yml`), fired by pushing a
411
+ `sdd-toolkit-vX.Y.Z` tag. It re-checks the tag against **all three manifests before publishing
412
+ anything** — an npm version can be deprecated but never replaced, so a wrong tag has to fail
413
+ before it ships, not after — then validates, publishes to GitHub Packages, and cuts a GitHub
414
+ Release. It authenticates with the built-in `GITHUB_TOKEN`, so there is no secret to configure
415
+ and the package stays behind the same access control as the private repo.
416
+ - `scripts/changelog-section.mjs` — extracts one version's CHANGELOG section for the release body,
417
+ and **exits non-zero when that section is missing or empty**, so a release cannot ship with
418
+ unreadable notes.
419
+ - `CONTRIBUTING.md` and `/release` now state plainly that the two halves ship differently: the
420
+ **plugin** releases by merging to the default branch (a marketplace installs from a branch, so no
421
+ tag is involved), while the **npm package** releases on a tag. Conflating the two is the obvious
422
+ way to think you've shipped and haven't.
423
+
424
+ ## [0.13.0]
425
+
426
+ ### Added
427
+ - **The MCP server is publishable as a standalone npm package** (`sdd-toolkit/package.json`,
428
+ `@venkatmotivity/sdd-mcp`), so a team can use it without cloning the marketplace repo. The
429
+ package ships only `mcp/`, `scripts/lib/`, and the single CI module the server imports — ~18KB,
430
+ **zero dependencies**, no agents, commands, or templates. `publishConfig` targets GitHub
431
+ Packages, which keeps distribution behind the same access control as the private repo rather
432
+ than requiring a new registry account. Teammates then point `.mcp.json` at
433
+ `npx -y @venkatmotivity/sdd-mcp`, which is safe to commit because it names a package instead of
434
+ a path on someone's laptop. Verified end to end: packed, installed into a clean project, and
435
+ driven over stdio through the published `sdd-mcp` binary.
436
+ - `mcp/README.md` documents the three sharing options with their real costs, including the point
437
+ that **you cannot ship JavaScript and prevent it being read** — `node_modules` is source and a
438
+ compiled executable is unpackable — and that **remote hosting cannot work for this server**,
439
+ since every tool answers questions about the repo the caller is sitting in.
440
+ - `--version` / `-v` on the server, printing the version **and the resolved file path** — version
441
+ skew across a team is the predictable failure of distributing this (one stale npx cache, one
442
+ freshly-updated plugin, two different answers), and "which copy am I running?" should be one line
443
+ rather than archaeology. `mcp/README.md` documents how updates actually reach people per
444
+ distribution path, including that plugin users get the server updated *with the plugin* and need
445
+ no npm package at all.
446
+ - Validator: the version now has four homes (plugin manifest, marketplace entry, npm package,
447
+ and the version the server reports over the wire) and all four must agree — the last two drift
448
+ invisibly, which this release caught in itself. It also fails the build if the package ever
449
+ declares a dependency or its `bin` target is missing or non-executable.
450
+
451
+ ## [0.12.1]
452
+
453
+ ### Fixed
454
+ - **`fix-specs.mjs` would have written statuses their authors never claimed.** Found by running the
455
+ dry run against a real 190-spec repo — which is what dry runs are for. Two compounding mistakes:
456
+ - The lifecycle word was matched by position in the **enum**, not position in the **text**, so a
457
+ Status reading "Phase 1 ✓ + Phase 2a ✓ … branch master verified" resolved to whichever stage
458
+ came first in `[Draft, Approved, Implemented, Verified, Archived]` rather than what the author
459
+ led with. Now matched by where the word actually appears.
460
+ - Even matched correctly, promoting a stage word found *mid-sentence* turns narration into a
461
+ claim. Normalization now requires the word to **lead** the cell ("Implemented (2026-07-07) — …"
462
+ is a declaration; "…branch master verified" is discussion). Anything else is left untouched and
463
+ reported, alongside the existing no-lifecycle-word case, with the reason given per file.
464
+ `resolveStatus()` moved into `scripts/lib/specs.mjs` so the dashboard and MCP server apply the
465
+ same rule, and exposes `leading` / `ambiguous` / `candidates` for callers that want to flag rather
466
+ than resolve.
467
+ - **`survey-estate.mjs` reported a parent directory as "not a git repo".** It only expanded a
468
+ directory into the repos beneath it when given exactly one argument — so any extra argument made
469
+ it treat every path as a repo. Each target is now expanded independently. It also detects the
470
+ cause of the extra arguments: zsh does not treat `#` as a comment interactively, so a pasted
471
+ trailing `# comment` arrives as arguments, and the script now says that instead of listing six
472
+ English words as failed repos.
473
+
474
+ ## [0.12.0]
475
+
476
+ ### Added
477
+ - **`scripts/spec-dashboard.mjs`** — a self-contained HTML dashboard of every spec, generated
478
+ locally. No CDN, no fonts, no network calls, so it works offline and the spec data never leaves
479
+ the machine — which is the point for a repo that can't be shared. Lifecycle bars,
480
+ acceptance-criteria completion, a severity-ordered needs-attention list, duplicate ids, and a
481
+ searchable table.
482
+ - **In-flight view for parallel work.** Running several specs at once (the three-developers
483
+ pattern) means several worktrees on several branches, and telling them apart was guesswork.
484
+ The dashboard joins each live `git worktree` back to the spec it's building — branch, commits
485
+ ahead, dirty or clean, path — so four concurrent builds are four labelled rows.
486
+ - One chart, deliberately: the lifecycle bars are single-hue with the stage named on the axis and
487
+ the count direct-labeled, because colouring five stages five ways would be decoration. Status
488
+ colours stay reserved for the attention list and always ship with an icon and a word, so meaning
489
+ is never carried by colour alone. Light and dark are both explicitly stepped.
490
+ - `scripts/lib/specs.mjs` — spec parsing extracted so the dashboard and the MCP server share one
491
+ implementation of "what a spec says" instead of two that drift. It also resolves a Status cell
492
+ holding prose down to its lifecycle word, and reads header cells to the last pipe rather than the
493
+ first, so prose containing `|` is no longer silently truncated.
494
+ - MCP `spec_list` now returns a **summary** (counts by status, AC totals, duplicate ids,
495
+ needs-attention count) alongside the rows, plus a `summaryOnly` argument — so a client can answer
496
+ "what's the state?" on a repo with hundreds of specs without rendering every row.
497
+
498
+ ## [0.11.0]
499
+
500
+ ### Added
501
+ - **The MCP server now ships bundled with the plugin** (`sdd-toolkit/.mcp.json`), declared with a
502
+ `${CLAUDE_PLUGIN_ROOT}`-relative path so it resolves wherever the plugin was installed — any
503
+ machine, any checkout. Previously each person had to hand-edit an absolute path into their repo's
504
+ `.mcp.json`, which is fine for the author's laptop and broken for everyone else; that template
505
+ remains as a fallback. The validator now **rejects absolute paths** in the bundled config, since
506
+ that is precisely the bug that makes a git-distributed plugin work only for whoever wrote it.
507
+
508
+ ### Fixed
509
+ - **The documented repo did not exist.** Manifests and READMEs pointed at an org that does not host
510
+ this repo, in 7 places — so `/plugin marketplace add <documented path>` 404'd and git-based
511
+ distribution could not have worked at all. Corrected to the real remote, and `PUBLISHING.md` now
512
+ carries a rename recipe that ends in a validator run rather than a hand-written `sed` that had
513
+ itself drifted.
514
+
515
+ ## [0.10.0]
516
+
517
+ ### Added
518
+ - **`/fix <bug>`** — bugs had no home. `/spec` is built for features (it asks what the contract
519
+ *should* be), but a defect already has a contract and the code is just violating it, so a
520
+ feature-shaped spec is wasted ceremony. Bugs were therefore falling through to `/code`, which
521
+ applies no discipline at all. `/fix` is the middle path, and its discipline is a single rule:
522
+ **reproduce it with a test that fails, and show the failure, before changing anything.** A fix
523
+ without a test that failed first is a guess, and nothing stops the bug returning. Then: root cause
524
+ stated in one sentence with `file:line` (and an explicit admission when the symptom is suppressed
525
+ rather than understood), the smallest change that turns it green, real verification output, and a
526
+ search for the same defect in sibling code paths. Escalates to `/spec` when the fix would change a
527
+ contract — at that point it isn't a bugfix, it's a change of intent.
528
+
529
+ ### Fixed
530
+ - **`/sdd-status` was unusable on a mature repo.** It rendered one table row per spec, which is fine
531
+ at 12 specs and unreadable at 184 — and expensive, since it read every file into context to do it.
532
+ It now summarizes above ~25 specs (counts by status, overall AC completion) and tables **only the
533
+ specs needing a decision**, saying how many rows it withheld and how to see them
534
+ (`/sdd-status all`, or a status to filter). It also prefers the MCP `spec_list` tool when
535
+ available, which parses the specs locally instead of loading them all. New checks in the
536
+ needs-attention list: a Status holding free-text prose rather than a lifecycle word, and duplicate
537
+ spec numbers — both pointing at `scripts/fix-specs.mjs` rather than proposing to fix them one at
538
+ a time.
539
+
540
+ ## [0.9.0]
541
+
542
+ ### Added
543
+ - **`/sdd-rollout`** — onboarding an estate, which is the bottleneck everything else waits on:
544
+ `/sdd-impact` and the MCP `estate_lookup` both correctly refuse to answer until the peer repos
545
+ have knowledge layers, so a toolkit installed in one service out of seventeen is mostly inert.
546
+ The command exists to **aim the expensive part** rather than spray it. `/sdd-init` is the costliest
547
+ operation here, and running it unattended across an estate buys both a large bill and a pile of
548
+ knowledge layers nobody reviewed — the exact failure this toolkit exists to prevent. So:
549
+ - Survey first, mechanically and free (below), then order repos by **cross-service surface** rather
550
+ than alphabetically — onboarding a hub unlocks `/sdd-impact` for its peers, a leaf unlocks nothing.
551
+ - **The first repo is an explicit calibration run**: onboard exactly one, stop, have a human read
552
+ the generated docs. Something is almost always systematically off, and fixing it before repo two
553
+ is the difference between 17 good knowledge layers and 17 copies of one mistake.
554
+ - Routes each repo to `/sdd-init` or `/sdd-adopt` from the survey, never `/sdd-init` over existing
555
+ docs. Leaves everything uncommitted. Ends with `/sdd-estate`, which is the actual payoff.
556
+ - Resumable with no ledger: the survey re-derives each repo's state from disk, so onboarded repos
557
+ show as `refresh` and fall out of the queue.
558
+ - **`scripts/survey-estate.mjs`** — the cheap half, split out so it needs no model: per repo, the
559
+ stack from its manifest, knowledge-layer state, spec count, 90-day commit activity, uncommitted
560
+ changes, and cross-service edge signals (event listeners, HTTP clients, contract files), ending in
561
+ an init / adopt / refresh / review recommendation. Detects other tools' agent instructions
562
+ (`AGENTS.md`, `.cursorrules`, Copilot) and routes those repos to `/sdd-adopt`, since `/sdd-init`
563
+ would clobber them. Bounded file walk so a survey stays cheap on a monorepo, and it says when the
564
+ cap truncated its counts rather than reporting a floor as a total. Read-only, no dependencies,
565
+ no network calls.
566
+
567
+ ## [0.8.0]
568
+
569
+ ### Added
570
+ - **`scripts/fix-specs.mjs`** — repairs the two spec-hygiene problems that accumulate in a repo
571
+ that adopted `specs/` before the newer commands existed. 0.6.0 stopped `/spec` from *creating*
572
+ duplicate numbers but did nothing about ones already on disk, and the evidence-gated `Status`
573
+ from 0.4.0 assumes a one-word value that older specs don't have.
574
+ - **Duplicate numbers** — keeps the earliest-added file on the number and renumbers the rest to
575
+ the next free id across **all** branches, `git mv` so history follows, rewriting exact filename
576
+ references in `specs/`, `docs/`, and the root READMEs. Only exact filenames are rewritten;
577
+ prose like "see spec 0043" is reported, not guessed at. Sub-spec suffixes (`0165b`, `0171c`)
578
+ are distinct ids, not collisions.
579
+ - **Prose in `Status`** — moves the lifecycle word into `Status` and preserves the original text
580
+ **verbatim** as a `> **Status note:**` under the header table. That text is usually real
581
+ information sitting in the wrong field, so it is relocated, never deleted. A status with no
582
+ recognisable lifecycle word is left alone and reported for a human.
583
+ - Dry run by default, `--apply` to write, `--force` to override the guard that refuses to apply
584
+ over a dirty `specs/`/`docs/` (so the script's diff stays reviewable on its own). Idempotent.
585
+ Pure Node, no dependencies, **no network calls** — it runs entirely on the user's machine, which
586
+ matters when the repo it repairs can't be shared.
587
+ - `/sdd-doctor` now points at the script when it finds either problem, rather than proposing to fix
588
+ them one file at a time.
589
+
590
+ ## [0.7.0]
591
+
592
+ ### Added
593
+ - **MCP server** (`mcp/sdd-server.mjs`) — the deterministic half of the toolkit, exposed to any MCP
594
+ client (Cursor, a custom agent, CI), read-only and dependency-free.
595
+ - `estate_lookup` — who produces/consumes a contract, from `docs/ESTATE.md`, with each row marked
596
+ confirmed or unverified. Returns `present: false` with an explicit note when there's no index:
597
+ "no index" is not "no consumers", and a false all-clear on a cross-service change is worse than
598
+ no answer because it gets believed.
599
+ - `knowledge_check` — the CI gate's checks as structured data. **Imports** the implementation from
600
+ `templates/ci/knowledge-check.mjs` rather than copying it, so the two can't drift; that file is
601
+ now a module with a CLI guard, and importing it is silent (a stray `console.log` would corrupt
602
+ the JSON-RPC stream).
603
+ - `spec_list`, `spec_next_number` — specs as structured data, with the across-all-branches
604
+ numbering from 0.6.0, reporting explicitly when it couldn't fetch instead of assuming.
605
+ - Templates served as `sdd://templates/…` resources, with path traversal rejected.
606
+ No dependencies: stdio MCP is newline-delimited JSON-RPC 2.0, implemented directly, by the same
607
+ convention that keeps `validate-plugin.mjs` dependency-free. `templates/mcp/.mcp.json` wires it
608
+ into a repo; `/sdd-init` offers it rather than installing it, since it needs an absolute path.
609
+ **The agents, skills, and hooks deliberately do NOT port** — MCP can't spawn a subagent with its
610
+ own tool allowlist and model, and can't register a hook. Those stay in the plugin; the two compose.
611
+ - Validator: the server's advertised `serverInfo.version` must match `plugin.json` (nothing else
612
+ keeps them in step, and the drift is visible only to clients), and its relative imports must
613
+ resolve. `templates/mcp/.mcp.json` must parse and declare `mcpServers`.
614
+
615
+ ### Fixed
616
+ - **`estate_lookup` parsed every event table with the wrong columns.** Section detection tested
617
+ `includes('synchronous')` before `includes('asynchronous')` — and "asynchronous" contains
618
+ "synchronous", so async rows were classified `sync` and their fields shifted by one, reporting an
619
+ event name as the calling service. Caught by fixture testing before release.
620
+ - `spec_next_number` reported `remoteChecked: false` identically for "no remote configured" and
621
+ "fetch failed" — the second is a real collision risk and now says so.
622
+
623
+ ## [0.6.0]
624
+
625
+ ### Added
626
+ - **Knowledge-layer CI gate** (`templates/ci/knowledge-check.mjs` + `knowledge-layer.yml`, seeded by
627
+ `/sdd-init`). 0.5.0's `SessionStart` hook made drift *visible*; this makes it *enforced*, because
628
+ advisory is exactly what got the docs to zero maintenance in the first place. It's the mechanical
629
+ half of `/sdd-doctor` — the checks needing no judgment, so CI can run them on every PR: every
630
+ `file:line` in the knowledge layer still resolves and the file is still that long, relative doc
631
+ links resolve, every shard is reachable from the router, docs are within budget. Plus an advisory
632
+ when a PR changes source and touches no doc. Pure Node, no dependencies. `--warn-only` exists for
633
+ adoption on a repo with existing drift: a gate that fails on day one gets disabled on day two.
634
+ `/sdd-doctor` now runs the script when present instead of eyeballing references.
635
+ - **`/sdd-impact [spec-file]`** — who breaks if this ships? Detects changes to *observable*
636
+ contracts (event payloads, API request/response shapes, shared tables, exported types), resolves
637
+ consumers from `docs/ESTATE.md`, classifies each as additive / compatible-with-sequence /
638
+ breaking, and produces a deploy order that's safe at every intermediate step. Nothing else in the
639
+ loop looks outside this repo — tests, `/code-review`, and `/spec-verify` all pass cleanly on a
640
+ change that breaks a consumer. If the estate index is missing or mostly `_TBD_`, it **refuses to
641
+ answer** rather than reporting "no consumers affected": that false all-clear is worse than no
642
+ answer, because it gets believed. Wired into `/spec-verify` for contract-touching changes.
643
+ - **`/sdd-adopt`** — `/sdd-init` assumes a blank slate, which is wrong for most repos that already
644
+ have a hand-written `CLAUDE.md`, `docs/`, or an RFC/ADR practice, and clobbering documentation a
645
+ team wrote is the fastest way to make them distrust the tool. This classifies every existing
646
+ section as keep-verbatim / merge / missing, keeps their structure and file names, maps the spec
647
+ loop onto their existing process instead of replacing it, and reports where their docs and the
648
+ code disagree **without changing anything** — a stale claim a human wrote is theirs to retire.
649
+ `/sdd-init` now detects an existing knowledge layer and redirects here.
650
+
651
+ ### Fixed
652
+ - **Spec numbers collided across branches.** `/spec` picked the next number from the working tree,
653
+ so two people speccing in parallel both got `0007-` and found out at merge — as a conflict in a
654
+ *filename*, which git resolves badly. It now takes the max across every branch
655
+ (`git log --all --diff-filter=A -- 'specs/[0-9]*'`) unioned with `specs/` and `specs/archive/`,
656
+ fetching first where there's a remote, and says so explicitly when it can't fetch rather than
657
+ numbering off a stale view. Documented in `specs/README.md`, including how to resolve a collision
658
+ that does land.
659
+
660
+ ## [0.5.0]
661
+
662
+ ### Added
663
+ - **Hooks that ship with the plugin and activate on install** (`hooks/hooks.json`). Usage data
664
+ showed `/sdd-refresh`, `/sdd-doctor`, and `/sdd-status` at effectively zero — the knowledge layer
665
+ was generated once by `/sdd-init` and then never re-checked, which quietly undoes the toolkit's
666
+ main claim. A command nobody remembers to type loses to automation:
667
+ - `knowledge-drift.sh` (`SessionStart`) — one line when `CLAUDE.md`/`docs/` are more than
668
+ `SDD_DRIFT_THRESHOLD` (default 30) *source* commits behind the code; doc-only commits don't
669
+ count, so refreshing the docs doesn't itself look like drift. Silent otherwise, and exits 0 on
670
+ anything unexpected — a session-start hook must never be why a session starts badly.
671
+ - `secret-scan.sh` (`PreToolUse` on Bash) — the old copy-paste example, hardened into a real
672
+ script: added lines only (removing a leaked key isn't blocked), an allowlist at
673
+ `.claude/secret-allowlist.txt`, and JWTs added to the pattern set. The only hook allowed to
674
+ block, because a committed key is unbounded damage and a false positive costs one line.
675
+ Project-specific automation (format/lint/test) still can't ship — the plugin can't know your
676
+ commands — so `templates/hooks/settings.hooks.example.json` now holds only those, and points at
677
+ what the plugin already runs for you.
678
+ - **`skills/knowledge-retrieval`** — the deep retrieval procedure (sharded-doc navigation, the 1-hop
679
+ dependency closure, designing across a service boundary: both sides of the contract, deploy order,
680
+ compatibility) moved out of the always-loaded `CLAUDE.md` fragment into a skill that loads only
681
+ when a task actually hits one of those. The always-needed ladder stayed in `CLAUDE.md` on purpose —
682
+ a rule you must know *before* you know you need it can't live on-demand.
683
+ - **`/release`** in `.claude/commands/` (the marketplace repo, not the plugin — it publishes plugins,
684
+ so it must not ship to the repos that install them). Reads the real diff since the last release,
685
+ proposes the semver level, writes the CHANGELOG entry in house style, bumps the version in both
686
+ manifests that CI requires to match, and validates. Stops before committing.
687
+
688
+ ### Changed
689
+ - **`/spec-build` now actually spawns `sdd-developer`.** It ran at 26% of skill usage while the
690
+ agent ran at ~1% — the command was reimplementing the agent's job inline, so the agent's
691
+ guarantees (test per criterion, functional/E2E for user-facing ones, real results only) silently
692
+ didn't apply, and the parallel three-worktree pattern in `specs/AGENTS.md` couldn't happen at all.
693
+ Blocking questions are resolved in the command *before* handing off, since a subagent has no
694
+ channel to the human.
695
+ - **The validator now catches dead wiring** — the check that would have made 0.4.0's two orphaned
696
+ agents impossible. A *mention* no longer counts as an invocation: it matches the idiom
697
+ `Use the **agent-name** agent`, because describing an agent in backticks is exactly how
698
+ `sdd-reviewer` and `pr-author` looked wired while nothing ran them. An agent with no command must
699
+ declare why with an `<!-- invoked-by: … -->` comment (`sdd-spec-author` does — `/spec` must ask the
700
+ human its contract questions, which a subagent can't). Also added: `${CLAUDE_PLUGIN_ROOT}/…` paths
701
+ resolve, `hooks.json` scripts exist **and are executable** (a non-executable hook fails silently),
702
+ `skills/<name>/SKILL.md` frontmatter matches its directory, and relative README links resolve.
703
+
704
+ ## [0.4.0]
705
+
706
+ ### Added
707
+ - **`/spec-verify <spec-file>` — the VERIFY phase finally has an entry point.** The `sdd-reviewer`
708
+ agent had shipped since 0.1.0 with *nothing* invoking it: `/spec-build` sent users to the built-in
709
+ `/code-review` instead, which reviews the diff for bugs and never opens the spec. The gate the
710
+ toolkit advertised — "test per criterion + adversarial review" — was reachable only if the model
711
+ happened to route to the agent on its own. `/spec-verify` delegates to it, relays the
712
+ per-criterion verdict and the real final-acceptance output unsoftened, and splits must-fixes into
713
+ *code is wrong* (fix and re-run) vs *spec is wrong* (a contract change → back through
714
+ AskUserQuestion, never a quiet widening of the spec to match what was built). Both reviews are now
715
+ prescribed, with a table saying which question each one answers.
716
+ - **`/pr <spec-file>`** — same orphan problem: `pr-author` existed with no command. Defaults to the
717
+ spec matching the current branch, flags a not-yet-`Verified` spec up front, produces text only,
718
+ and opens the PR only on an explicit ask (via `--body-file`, never a retyped body).
719
+ - **`/spec-advance <spec-file> [status]` — spec status becomes evidence-backed.** Status was written
720
+ ad hoc by whichever agent felt done, so `Verified` meant "an agent said so". It is now written
721
+ *only* here, and each transition must show its evidence: `Approved` needs the human's approval in
722
+ conversation and no blocking question parked in §8; `Implemented` needs every test named in the §6
723
+ table to **exist on disk** (a named-but-missing test being the usual lie); `Verified` needs a clean
724
+ `/spec-verify` *and* a green §6.1 suite, never an assertion; `Archived` needs the branch merged,
725
+ then `git mv`s the spec to `specs/archive/` keeping its number. Missing evidence means the
726
+ transition is **refused**, which is a successful run. Backwards moves are allowed but must add a
727
+ Revisions row. The command also records the spec's **Branch**, so `/sdd-status` reads it instead of
728
+ guessing from `git branch --all`.
729
+ - **`/sdd-estate`** — `docs/ESTATE.md` had a template but no generator, so the estate index (the
730
+ thing that makes this a multi-service toolkit rather than a per-repo one) was hand-maintained.
731
+ The command scans the peer repos read-only, indexes the real edges — HTTP/RPC clients, event
732
+ producers/consumers, shared tables/packages — with `file:line` on **both** sides, marks unconfirmed
733
+ peer-side rows `(inferred)`, merges rather than overwrites, and reports the edges it could not
734
+ resolve as the headline output (an unresolved edge is where a cross-service change breaks).
735
+
736
+ ### Changed
737
+ - `templates/docs/ESTATE.md` → **`ESTATE.template.md`** (matching `PATTERNS.template.md` /
738
+ `ARCHITECTURE.template.md`) and genericized. It shipped pre-filled with one estate's real services
739
+ and queues, which `/sdd-init` would then copy verbatim into unrelated repos. Now placeholders,
740
+ plus an evidence column and an optional shared-data table.
741
+ - Spec template: `Branch` row and the `Archived` status; a note that Status is written by
742
+ `/spec-advance`, not by hand.
743
+ - `specs/README.md` gained a **Lifecycle** table (status → meaning → gate), and the loop's VERIFY
744
+ step now names `/spec-verify` and `/pr`. `specs/AGENTS.md` maps each agent to the command that
745
+ runs it — the mapping whose absence hid the two orphans.
746
+ - `/spec-build` now hands off through `/spec-advance Implemented` → `/spec-verify` → `/code-review`
747
+ → `/spec-advance Verified` → `/pr` instead of ending at "recommend `/code-review`". `/spec` and
748
+ `/spec-review` no longer touch Status (an author doesn't approve their own spec).
749
+ - `/sdd-status` reads the spec's `Branch` row (marking fallback guesses with `?`), collapses
750
+ `specs/archive/` to a count, and flags merged-but-unarchived specs. `/sdd-doctor` now flags
751
+ `Verified` specs whose named tests don't exist and blocking questions parked in §8.
752
+ - `/sdd-init` and `/sdd-refresh` delegate `docs/ESTATE.md` to `/sdd-estate` rather than copying or
753
+ hand-editing it.
754
+
755
+ ## [0.3.0]
756
+
757
+ ### Added
758
+ - **One-pass spec review.** Human review of a spec was looping: read → find holes → answer →
759
+ re-read. Three causes, all fixed:
760
+ - `/spec` and `sdd-spec-author` gave **opposite instructions** on the same trigger — the command
761
+ said ask the user before writing; the agent said park the questions in the document. The agent
762
+ won whenever the model routed to it, so blocking contract decisions reached the human as
763
+ homework. Both now resolve blocking ambiguity *before* the spec is written, with one definition
764
+ of blocking (the answer changes an API shape, data model, error code, scope boundary, or
765
+ compatibility — i.e. you'd rewrite a section knowing it). `/spec` asks the batch directly via
766
+ AskUserQuestion, each question carrying concrete options and a recommendation; `sdd-spec-author`
767
+ is a subagent with no user channel, so it stops and returns the questions to its caller instead.
768
+ Section 8 is now non-blocking follow-ups **only**, and the template says so.
769
+ - **`/spec` never routed through `/spec-review`** — it sent the user straight from draft to
770
+ approve to `/spec-build`, making the human the first reviewer. `/spec` now runs the adversarial
771
+ pass over its own draft and fixes what it finds before the human sees anything.
772
+ - **Revisions had no bounded surface** — a sent-back spec cost a full re-read. `TEMPLATE.md` now
773
+ carries a `Revisions` table (what changed, why, which sections) so round two is a diff read.
774
+ - `sdd-spec-reviewer` agent — the adversarial spec pass as a reusable unit with **fresh context**
775
+ (a spec's author cannot see its own holes). `/spec-review` is now a thin delegator to it, and
776
+ `/spec` spawns it automatically. Also flags blocking questions parked in section 8 as blockers.
777
+ - **Per-component model tiering (quality-first).** Everything that affects code quality stays on
778
+ the inherited (Opus) model: the code-writing agents (`coder`, `sdd-developer`, `/spec-build`),
779
+ the spec author (`sdd-spec-author`, `/spec`), and both quality gates (`sdd-reviewer`,
780
+ `/spec-review`). Only work with **no** bearing on code correctness runs cheaper via frontmatter:
781
+ `pr-author` (PR prose) → **sonnet**; `/sdd-doctor`, `/sdd-status` (mechanical read-only
782
+ dashboards) → **haiku**. `spec-build`/`sdd-developer` run only the targeted tests during
783
+ implementation and the full functional/E2E suite **once** at the final-acceptance step (cheaper,
784
+ no quality loss — the full gate still runs). The validator checks `model` frontmatter values.
785
+ - **Functional/E2E tests + final-acceptance gate.** The spec template now has a functional/E2E
786
+ test type and a `## 6.1 Final acceptance` section, and a `Verified` status. Every user-facing /
787
+ contract-level acceptance criterion needs a functional/E2E test (not just a unit test), and a
788
+ spec is only `Verified` once the project's *full* suite (incl. functional/E2E) passes end to
789
+ end. Threaded through `/spec-build`, the `sdd-developer` and `sdd-reviewer` agents,
790
+ `specs/README.md`, the CLAUDE.md fragment, and `docs/PATTERNS.md`.
791
+ - `/spec-review <spec-file>` — adversarial review of a spec **before** any code: checks contracts,
792
+ acceptance criteria, and cross-module ripple are complete and testable.
793
+ - `/sdd-doctor` — read-only health check of the knowledge layer (broken `file:line` refs, stale
794
+ commands, over-budget docs, `(inferred)` markers, spec hygiene); recommends `/sdd-refresh`.
795
+ - `/sdd-status` — dashboard of every spec: lifecycle status, acceptance-criteria progress, and the
796
+ matching git branch.
797
+ - `pr-author` agent — turns a completed spec + its diff into a PR title and body with the
798
+ acceptance criteria as a review checklist (read-only; does not open the PR).
799
+ - **CI:** `.github/workflows/validate.yml` + `scripts/validate-plugin.mjs` (no-dependency) validate
800
+ manifests, agent/command frontmatter, agent-name/filename match, and **version sync** between
801
+ `plugin.json` and the `ace-tools` marketplace entry.
802
+ - `CONTRIBUTING.md` — agent/command authoring conventions and the release checklist.
803
+ - `examples/promo-service/` — a worked example of what `/sdd-init` produces (filled-in `CLAUDE.md`,
804
+ `docs/PATTERNS.md`, and a completed spec).
805
+
806
+ ### Changed
807
+ - Set the real git org across the manifests and READMEs (was a placeholder).
808
+ <!-- Corrected in 0.11.0: this pointed at an org that did not host the repo. -->
809
+
810
+ - Hardened the optional PreToolUse hook example into a working staged-diff secret scan (AWS keys,
811
+ private keys, Slack/GitHub tokens, generic `key=…` assignments) that blocks the commit.
812
+
813
+ ## [0.2.1]
814
+
815
+ ### Changed
816
+ - **Leaner agents / DRY:** collapsed the duplicated stack-detection prose (was repeated across all
817
+ 4 agents + 3 commands) into one short "detect from the manifest, mirror the code, read the docs"
818
+ procedure. `coder.md` dropped ~45 lines; per-stack/DB specifics now live only in the generated
819
+ `docs/PATTERNS.md` (where project detail belongs), not in always-loaded agent prompts.
820
+ - Added a confidence convention to `PATTERNS.template.md` — mark `(inferred)` patterns so the agent
821
+ re-checks them against code; never invent a convention to fill a section.
822
+ - Clarified `/code` vs `/spec` boundary and noted `/code-review`/`/security-review` are built-in.
823
+
824
+ ### Fixed
825
+ - Duplicate step number in `/sdd-init`; a Spring-specific `Feign` reference in the stack-neutral
826
+ knowledge layer.
827
+
828
+ ## [0.2.0]
829
+
830
+ ### Added
831
+ - `/code <task>` — one-shot coding command via the `coder` agent.
832
+ - `/sdd-refresh` — re-learn the project and update the knowledge files after the code drifts.
833
+ - `docs/PATTERNS.md` — learned "house style" memory, generated by `/sdd-init` and read by all agents.
834
+ - Optional `templates/hooks/settings.hooks.example.json` — opt-in post-edit/lint/test/secret hooks.
835
+ - Git & PR workflow section in the shared CLAUDE.md fragment.
836
+
837
+ ### Changed
838
+ - Agents and commands are now **stack-aware for any language** (Java, React, Node/Express/NestJS,
839
+ Python, Go, Ruby, .NET, …) and any database (MySQL, PostgreSQL, MongoDB, …) — detect the
840
+ manifest/commands and mirror the project's conventions instead of assuming Spring Boot.
841
+ - `/sdd-init` is now **learn-first**: it studies the codebase and generates `CLAUDE.md`,
842
+ `docs/PATTERNS.md`, and `docs/ARCHITECTURE.md` from real `file:line` evidence.
843
+ - Spec template, architecture template, and knowledge layer made stack-neutral.
844
+ - Marketplace plugin `source` switched to the relative path `./sdd-toolkit`.
845
+ - **Token/memory optimization:** tiered knowledge layer (CLAUDE.md = thin index that links, not
846
+ inlines; PATTERNS/ARCHITECTURE loaded on demand, ~200-line budgets each), `file:line` references
847
+ over pasted code, read file ranges not whole files, and `/sdd-refresh` now prunes/trims to budget.
848
+ - **Large-app mode:** sharded knowledge layer — `docs/ARCHITECTURE.md` becomes a router linking to
849
+ per-module `docs/architecture/<module>.md` (and `docs/patterns/<module>.md`) shards loaded on
850
+ demand, so each task's context is the router + only the relevant shard. `/sdd-init` generates and
851
+ `/sdd-refresh` updates shards per-module.
852
+ - **Interlinked modules (edges, not just nodes):** each shard carries a `Depends on / Used by`
853
+ header, the router holds a module **contract index** (shared events/APIs/types/tables →
854
+ producers/consumers), and the agent loads the bounded **1-hop dependency closure** (target shard +
855
+ neighbors' contract sections). Optional always-loaded `docs/architecture/_core.md` for heavily
856
+ shared contracts; tightly-coupled specs are sequenced, not parallelized.
857
+
858
+ ## [0.1.0]
859
+ - Initial release: `coder` + `sdd-spec-author`/`sdd-developer`/`sdd-reviewer` agents,
860
+ `/spec`, `/spec-build`, `/sdd-init`, and the spec/docs templates (publisher-service focused).