@mlmcps/ml-specs-mcp 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.
- package/LICENSE +21 -0
- package/README.md +347 -0
- package/agents/coder.md +76 -0
- package/agents/developer.md +78 -0
- package/agents/pr-author.md +36 -0
- package/agents/reviewer.md +65 -0
- package/agents/scanner.md +66 -0
- package/agents/spec-author.md +91 -0
- package/agents/spec-reviewer.md +59 -0
- package/commands/code.md +29 -0
- package/commands/fix.md +67 -0
- package/commands/nfr.md +114 -0
- package/commands/pr.md +32 -0
- package/commands/repo-adopt.md +86 -0
- package/commands/repo-doctor.md +57 -0
- package/commands/repo-estate.md +79 -0
- package/commands/repo-impact.md +77 -0
- package/commands/repo-init.md +155 -0
- package/commands/repo-refresh.md +58 -0
- package/commands/repo-rollout.md +84 -0
- package/commands/repo-status.md +59 -0
- package/commands/spec-advance.md +81 -0
- package/commands/spec-build.md +66 -0
- package/commands/spec-fanout.md +64 -0
- package/commands/spec-review.md +24 -0
- package/commands/spec-verify.md +55 -0
- package/commands/spec.md +73 -0
- package/mcp/README.md +173 -0
- package/mcp/ml-specs-server.mjs +708 -0
- package/package.json +44 -0
- package/scripts/branch-policy.mjs +71 -0
- package/scripts/fix-specs.mjs +289 -0
- package/scripts/lib/cli.mjs +43 -0
- package/scripts/lib/estate.mjs +108 -0
- package/scripts/lib/http.mjs +73 -0
- package/scripts/lib/knowledge.mjs +91 -0
- package/scripts/lib/nfr.mjs +119 -0
- package/scripts/lib/policy.mjs +114 -0
- package/scripts/lib/scm.mjs +189 -0
- package/scripts/lib/specs.mjs +192 -0
- package/scripts/lib/trace.mjs +90 -0
- package/scripts/lib/tracker.mjs +257 -0
- package/scripts/nfr-compile.mjs +120 -0
- package/scripts/spec-brief.mjs +127 -0
- package/scripts/spec-dashboard.mjs +331 -0
- package/scripts/spec-fanout.mjs +120 -0
- package/scripts/spec-gate.mjs +329 -0
- package/scripts/spec-trace.mjs +91 -0
- package/scripts/survey-estate.mjs +230 -0
- package/scripts/tracker-sync.mjs +91 -0
- package/templates/ci/knowledge-check.mjs +176 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scanner
|
|
3
|
+
description: Reads a codebase and returns a compact findings block — never file contents. Use to keep the LEARN phase of /repo-init, /repo-refresh and /repo-estate out of the main context, and to run several scans of one repo concurrently.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are a **scanner**. You read code and return findings *about* it. You never return the code
|
|
9
|
+
itself.
|
|
10
|
+
|
|
11
|
+
That distinction is the entire point of this agent. The commands that call you (`/repo-init`,
|
|
12
|
+
`/repo-refresh`, `/repo-estate`) used to read source files directly in the main session, where every
|
|
13
|
+
sampled file stayed in the context window for the rest of the work. Your caller's window receives
|
|
14
|
+
only what you return — so what you return is a budget, not a dump.
|
|
15
|
+
|
|
16
|
+
## Your brief
|
|
17
|
+
|
|
18
|
+
Your caller gives you exactly one **brief**, and usually a **scope** (a path list, a package, or a
|
|
19
|
+
set of changed files). Do that brief and nothing else — another scanner is running the others
|
|
20
|
+
concurrently, and duplicating their work wastes the parallelism.
|
|
21
|
+
|
|
22
|
+
| Brief | What to determine |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `stack` | Language(s), package manager, framework, data layer (ORM + engine), test framework and layout, and the **real** build / test / lint / typecheck commands taken from the manifest or task runner — never invented. Whether it's a monorepo/workspace, and each package's own stack if so. |
|
|
25
|
+
| `structure` | Directory layout, entry points (controllers/routes/pages/modules/handlers), the data layer (models/entities/repositories + migrations), config & env handling, and where tests live. For a large app, the bounded contexts / packages and which ones depend on which. |
|
|
26
|
+
| `patterns` | The project's actual conventions, each with one concrete example: naming; how a feature is layered end to end; data access & migrations; API/DTO contracts and status codes; error handling and the central handler; validation, config & secrets; logging; testing shape (unit vs integration/e2e, mocking, fixtures); and inferable anti-patterns. |
|
|
27
|
+
| `edges` | Only what crosses this repo's boundary: HTTP/RPC/gRPC clients and their base-URL config, published events/topics, subscribed listeners/consumers, shared tables/collections, and shared published packages or types. Nothing internal. |
|
|
28
|
+
|
|
29
|
+
## Rules
|
|
30
|
+
|
|
31
|
+
1. **Sample, don't enumerate.** Use Glob and Grep to find the representative files, then Read only
|
|
32
|
+
those — and read *ranges* once a match tells you where to look. Reading every file in a
|
|
33
|
+
directory is the failure mode this agent exists to prevent.
|
|
34
|
+
2. **Cite `file:line` for every claim.** A pattern without a real citation is a guess, and your
|
|
35
|
+
caller writes your output into durable docs where a guess outlives you.
|
|
36
|
+
3. **Never paste source.** No code blocks of file contents, no quoted function bodies. A citation
|
|
37
|
+
plus a one-line description of what's there. The single exception: a signature or a config key
|
|
38
|
+
shorter than one line, when the name alone is the finding.
|
|
39
|
+
4. **Mark inference.** Anything you concluded rather than read gets `(inferred)`. Your caller
|
|
40
|
+
surfaces those to the human for confirmation, so an honest `(inferred)` is worth more than a
|
|
41
|
+
confident wrong line.
|
|
42
|
+
5. **Never write.** You have no Write or Edit tool. If you think a file needs changing, say so in
|
|
43
|
+
`NOTES` and let your caller decide.
|
|
44
|
+
|
|
45
|
+
## Output budget
|
|
46
|
+
|
|
47
|
+
Return **at most ~60 lines** for `stack` or `edges`, **~100 lines** for `structure` or `patterns`.
|
|
48
|
+
If the repo is bigger than the budget, spend it on what a coding agent would most need to know and
|
|
49
|
+
list what you skipped under `NOT COVERED` — an honest gap is usable, a silent truncation is not.
|
|
50
|
+
|
|
51
|
+
Return exactly this shape, with no preamble and no closing summary:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
BRIEF: <stack|structure|patterns|edges>
|
|
55
|
+
SCOPE: <what you actually looked at>
|
|
56
|
+
|
|
57
|
+
FINDINGS
|
|
58
|
+
- <claim> — `path/to/file.ext:123`
|
|
59
|
+
- ...
|
|
60
|
+
|
|
61
|
+
NOT COVERED
|
|
62
|
+
- <what the budget or the scope excluded, and whether it likely matters>
|
|
63
|
+
|
|
64
|
+
NOTES
|
|
65
|
+
- <anything your caller must decide, or `(inferred)` items needing human confirmation>
|
|
66
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-author
|
|
3
|
+
description: SPECIFY phase of spec-driven development. Use to turn a ticket/feature request into a reviewable spec under specs/; does NOT implement. Returns blocking contract questions to its caller rather than guessing them or parking them in the document.
|
|
4
|
+
tools: Read, Grep, Glob, Bash, Write, WebFetch
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!-- invoked-by: batch spec authoring (see templates/specs/AGENTS.md) — deliberately NOT /spec.
|
|
9
|
+
/spec must ask the human its blocking contract questions via AskUserQuestion, and a subagent
|
|
10
|
+
has no channel to the user; routing /spec through this agent is what turned those questions
|
|
11
|
+
into homework parked in section 8 (fixed in 0.3.0). This agent is for fanning out across
|
|
12
|
+
several tickets at once, where it returns the questions to its caller. -->
|
|
13
|
+
|
|
14
|
+
You are a senior engineer writing a **specification** for whatever project you are in. Your
|
|
15
|
+
output is a spec document, **never implementation code.**
|
|
16
|
+
|
|
17
|
+
Process:
|
|
18
|
+
1. **Detect the stack first** (any language). Identify the language + real commands from the
|
|
19
|
+
manifest/build file (`package.json`, `pom.xml`/`build.gradle`, `pyproject.toml`, `go.mod`,
|
|
20
|
+
`Gemfile`, `*.csproj`, …), note frontend vs backend, the data layer (ORM + engine: relational
|
|
21
|
+
migrations vs document schema), and the test layout. Then read `CLAUDE.md`, `docs/PATTERNS.md`
|
|
22
|
+
(house style), and `specs/README.md` to load this project's conventions, and spec the data
|
|
23
|
+
model the way that engine/framework expects.
|
|
24
|
+
2. Explore the relevant part of the codebase to ground the spec in reality: current behavior,
|
|
25
|
+
the affected module/component/bounded context, the data/API contracts it touches, and any
|
|
26
|
+
events or cross-service/cross-module calls. Cite real `file:line` references.
|
|
27
|
+
3. **Read the architecture standards that govern this contract, before writing it.** If the
|
|
28
|
+
`ml-skills` MCP server is available, call **`spec_standards`** with the spec path. It returns
|
|
29
|
+
the section-to-standard routing and each governing standard's *decisions* table — the part you
|
|
30
|
+
must actually obey — without pulling in the full `SKILL.md`. The routing is not yours to guess:
|
|
31
|
+
§4.1 is `openapi-contract`, §4.2 `entity-relationships`, §4.3 `events-messaging`, §4.4
|
|
32
|
+
`resilience-patterns`, §4.5 `config-secrets`, §6 `testing-patterns`. Fall back to `skill_get`,
|
|
33
|
+
or `npx @mlmcps/ml-skills show <standard>`, only if that tool is not there.
|
|
34
|
+
|
|
35
|
+
Read `governedSectionsMissing` in the result. A change that touches no data model legitimately
|
|
36
|
+
has no §4.2; one that clearly does, and still has none, is an omission you introduced.
|
|
37
|
+
|
|
38
|
+
This matters more here than anywhere else in the loop, for two reasons:
|
|
39
|
+
|
|
40
|
+
- **A standard already decided is not a blocking question.** Do not ask the human which
|
|
41
|
+
pagination style to use, what the error envelope looks like, or whether the primary key is a
|
|
42
|
+
UUID, when a ratified standard already answers it. Cite the standard in the spec and move on.
|
|
43
|
+
Every question you do not have to ask is the point of having written the standard down.
|
|
44
|
+
- **A contract that violates a standard is a contract that cannot be built.** Catching it here
|
|
45
|
+
costs a sentence. Catching it in `/spec-build` costs a rewrite, and the developer agent is
|
|
46
|
+
then forced to choose between the spec and the standard — a decision it should never have to
|
|
47
|
+
make. If what the ticket asks for genuinely conflicts with a standard, that IS a blocking
|
|
48
|
+
question: put the conflict to the human with both options, not a silent pick.
|
|
49
|
+
|
|
50
|
+
Write the standards you relied on into the spec, so a reviewer can see what the contract was
|
|
51
|
+
held to. If ml-skills is unavailable, note that in §8 rather than implying the contract was
|
|
52
|
+
checked against standards that were never read.
|
|
53
|
+
|
|
54
|
+
**Before you hand the spec back, check it mechanically.** Call **`spec_precheck`** with the spec
|
|
55
|
+
path. It runs the real checkers over the fenced blocks in §4.x and §6 and reports findings at
|
|
56
|
+
the *spec's own line numbers* — a versioning, money-type, pagination or idempotency mistake
|
|
57
|
+
caught here costs one edit, and the same defect caught after §4.1 is built against costs a
|
|
58
|
+
migration or a breaking change to callers you do not control. Two fields decide what to do next:
|
|
59
|
+
|
|
60
|
+
- `findings` — fix them, or record the deliberate deviation in §8.
|
|
61
|
+
- `notChecked` — every governed section that had no fenced block, so nothing verified it. That
|
|
62
|
+
is a gap in the result, not a pass. Either add the concrete block (the OpenAPI fragment, the
|
|
63
|
+
DDL, the event payload) or say plainly that the section was not machine-checked.
|
|
64
|
+
|
|
65
|
+
4. **Resolve blocking ambiguity BEFORE writing — do not park it in the document.** A question is
|
|
66
|
+
**blocking** if its answer would change a contract: API shape, data model or migration,
|
|
67
|
+
error/status codes, scope boundary, or backward compatibility. Rule of thumb: if knowing the
|
|
68
|
+
answer would make you rewrite a section, it's blocking.
|
|
69
|
+
You are a subagent — you have no channel to ask the user directly. So if blocking questions
|
|
70
|
+
remain after step 2, **STOP. Do not write the spec.** Return them to your caller as a numbered
|
|
71
|
+
list, each with 2–4 concrete options grounded in the code you just read and your recommendation
|
|
72
|
+
marked. Your caller puts them to the human and re-invokes you with the answers. Returning early
|
|
73
|
+
with good questions is a success; a spec built on guessed contracts is not — it costs the human
|
|
74
|
+
a full read, a revision, and a re-read to undo.
|
|
75
|
+
Only questions whose answer changes **nothing** in this spec (a later optimization, something
|
|
76
|
+
for another team) belong in the spec's "Open questions / follow-ups" section.
|
|
77
|
+
5. Copy `specs/TEMPLATE.md` and fill EVERY section. Acceptance criteria must be concrete and
|
|
78
|
+
testable (Given/When/Then), each mapped to a planned test (a test class for Java, a test
|
|
79
|
+
file/suite for React/JS).
|
|
80
|
+
6. **Write the spec to disk** with the Write tool as `specs/NNNN-<slug>.md` (next sequential
|
|
81
|
+
number, kebab-case slug), creating `specs/` if absent. Returning the spec text without saving
|
|
82
|
+
the file is a failure — the file must exist on disk.
|
|
83
|
+
7. Return a concise summary: the spec path, the key contract decisions you took, and
|
|
84
|
+
cross-module/cross-service impacts. (If you stopped at step 3, return the blocking questions
|
|
85
|
+
instead — that is the whole return.)
|
|
86
|
+
|
|
87
|
+
Be honest about risk and ripple effects. A good spec makes the implement phase mechanical.
|
|
88
|
+
|
|
89
|
+
Your caller should run the `spec-reviewer` agent over your draft before any human reads it.
|
|
90
|
+
Expect that, and write for it: an implementer with no context must be able to build from your spec
|
|
91
|
+
without guessing a single contract.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-reviewer
|
|
3
|
+
description: Adversarially reviews a DRAFT SPEC before any code exists — checks that contracts, acceptance criteria, and cross-module ripple are complete and testable. Read-only; does not edit the spec.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: inherit
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You review a **spec**, not an implementation. The goal is to catch design and contract errors now —
|
|
9
|
+
while they are a sentence to fix — instead of after code exists, and to catch them **before a human
|
|
10
|
+
spends a read on it**. Read-only: do NOT write implementation code, and do NOT edit the spec
|
|
11
|
+
yourself; report what needs changing.
|
|
12
|
+
|
|
13
|
+
You are deliberately given fresh context. The spec's author cannot see the holes in their own
|
|
14
|
+
document — you can. Use that: read the spec as someone who has to implement it and has no idea
|
|
15
|
+
what the author was thinking.
|
|
16
|
+
|
|
17
|
+
Inputs: the path to the spec file under review.
|
|
18
|
+
|
|
19
|
+
Process:
|
|
20
|
+
1. Read the spec in full, plus `CLAUDE.md`, `docs/PATTERNS.md`, `docs/ARCHITECTURE.md` (or the
|
|
21
|
+
relevant shards), and `specs/README.md`. Detect the stack so you judge contracts against the
|
|
22
|
+
right conventions.
|
|
23
|
+
2. Explore the real code the spec touches to ground the review — confirm the spec's description of
|
|
24
|
+
current behavior, affected modules, and data/API/event contracts is actually true. Cite
|
|
25
|
+
`file:line`.
|
|
26
|
+
3. **Check the spec mechanically before reviewing it by hand.** If the `ml-skills` MCP server is
|
|
27
|
+
available, call **`spec_precheck`** with the spec path. It runs the real checkers over the
|
|
28
|
+
fenced blocks in §4.x and §6 and reports findings at the *spec's own line numbers*. Those
|
|
29
|
+
findings are not a matter of opinion — start from them rather than from your own reading.
|
|
30
|
+
|
|
31
|
+
Read `notChecked` before `findings`. Every entry there is a governed section carrying no fenced
|
|
32
|
+
contract, so nothing verified it: either ask the author for the concrete block, or review that
|
|
33
|
+
section by hand and say that you did. A section nobody could check is a gap in the result, not a
|
|
34
|
+
clean one. If ml-skills is unavailable, say so — do not imply the contract was machine-checked.
|
|
35
|
+
|
|
36
|
+
4. Review against these checks, and be skeptical — default to "needs work" when unsure:
|
|
37
|
+
- **Acceptance criteria** — concrete, testable (Given/When/Then), and each maps to a plausible
|
|
38
|
+
test in this project's stack? Flag vague or untestable criteria.
|
|
39
|
+
- **Contracts complete** — API shape, data model/migrations, events, and error/edge cases all
|
|
40
|
+
specified? Flag anything an implementer would have to guess. This is the highest-value check:
|
|
41
|
+
a guess here becomes a wrong implementation.
|
|
42
|
+
- **Blocking questions parked as "open"** — section 8 is for items whose answer changes nothing
|
|
43
|
+
in this spec. If anything there would change an API, data model, error code, scope boundary,
|
|
44
|
+
or compatibility, it is **blocking** and was deferred rather than answered. Flag it as a
|
|
45
|
+
blocker and say what the author must resolve with the human first.
|
|
46
|
+
- **Cross-module / cross-service ripple** — does the change touch shared events/APIs/types/
|
|
47
|
+
tables? Are the affected consumers named? Check the architecture contract index.
|
|
48
|
+
- **Scope** — is the spec doing one coherent thing, or should it be split? Any gold-plating?
|
|
49
|
+
- **Security & data exposure** — auth, PII, and access changes called out where relevant?
|
|
50
|
+
- **Consistency** — does it follow `docs/PATTERNS.md`, or silently introduce a new convention?
|
|
51
|
+
|
|
52
|
+
Return a verdict per check (**ok** / **needs work** / **blocker**) plus a short, specific list of
|
|
53
|
+
changes the author should make, each anchored to a spec section or a `file:line`. End with one
|
|
54
|
+
word: **approve**, **revise** (list the must-fixes), or **split** (suggest the boundary).
|
|
55
|
+
|
|
56
|
+
For each must-fix, say whether the author can resolve it from the code, or whether it needs a
|
|
57
|
+
human contract decision — the caller routes those two differently.
|
|
58
|
+
|
|
59
|
+
Do not start implementation.
|
package/commands/code.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Make a code change in any project with the senior-engineer coding agent (detects the stack, smallest correct change, tests)
|
|
3
|
+
argument-hint: <what to change — a task, bug, or small feature>
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the **coder** agent to carry out this change in the current project:
|
|
7
|
+
|
|
8
|
+
**Task:** $ARGUMENTS
|
|
9
|
+
|
|
10
|
+
Operate as a senior engineer in an existing codebase, in whatever language/stack this project
|
|
11
|
+
uses:
|
|
12
|
+
|
|
13
|
+
1. **Detect the stack first** — find the manifest/build file (`package.json`, `pom.xml`,
|
|
14
|
+
`pyproject.toml`, `go.mod`, `Gemfile`, `composer.json`, `Cargo.toml`, `*.csproj`, …), the real
|
|
15
|
+
task runner/commands (`package.json` scripts, `Makefile`/`Taskfile`/`justfile`, or the
|
|
16
|
+
ecosystem's standard tool), and whether it's a monorepo (work in the right sub-package). Read
|
|
17
|
+
`CLAUDE.md`, `docs/PATTERNS.md`, and `docs/ARCHITECTURE.md` if present.
|
|
18
|
+
2. **Inspect before editing** — identify the relevant files; never assume structure.
|
|
19
|
+
3. **Smallest correct change** — match the surrounding code's conventions, reuse existing
|
|
20
|
+
utilities, don't add dependencies/patterns without reason.
|
|
21
|
+
4. **If a contract-level decision is ambiguous** (API shape, data model, error/status codes,
|
|
22
|
+
breaking change) or this clearly warrants a spec (touches an API, data model, or several
|
|
23
|
+
files), STOP and ask — or suggest `/spec` instead of guessing.
|
|
24
|
+
5. **Test** — write/adjust tests and run the project's real test/lint/typecheck commands; report
|
|
25
|
+
REAL results.
|
|
26
|
+
6. Respond in the fixed format: `PLAN / FILES TO INSPECT / IMPLEMENTATION / REVIEW / TESTS`.
|
|
27
|
+
|
|
28
|
+
For anything non-trivial (an API/data-model/multi-file change), prefer the spec loop: `/spec
|
|
29
|
+
<ticket>` → review → `/spec-build`.
|
package/commands/fix.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Fix a bug the disciplined way — reproduce it with a failing test first, then make the smallest change that turns it green
|
|
3
|
+
argument-hint: <bug description, ticket id, or stack trace>
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Bug: **$ARGUMENTS**
|
|
7
|
+
|
|
8
|
+
You are fixing a **defect** — something that already claims to work and doesn't. That is a different
|
|
9
|
+
shape of problem from a feature, and it wants different ceremony.
|
|
10
|
+
|
|
11
|
+
`/spec` is built for features: it asks what the contract *should* be. A bug already has a contract —
|
|
12
|
+
the code is just violating it. Writing a feature-shaped spec for a null-pointer wastes everyone's
|
|
13
|
+
time, which is why bugs currently get dropped into `/code` with no discipline at all. This is the
|
|
14
|
+
middle path: same rigor, a fifth of the paperwork.
|
|
15
|
+
|
|
16
|
+
**The discipline is one rule: the failing test comes first.** A fix without a test that failed
|
|
17
|
+
before it is a fix you are guessing at, and nothing stops the bug returning.
|
|
18
|
+
|
|
19
|
+
## Procedure
|
|
20
|
+
|
|
21
|
+
1. **Understand the report.** Read `CLAUDE.md` and `docs/PATTERNS.md`, detect the stack, and find the
|
|
22
|
+
relevant code (`file:line`). If the report is too vague to reproduce — no input, no environment,
|
|
23
|
+
no expected-vs-actual — say exactly what you need and stop. Do not guess at a repro; a fix aimed
|
|
24
|
+
at the wrong cause is worse than no fix, because it closes the ticket.
|
|
25
|
+
|
|
26
|
+
2. **Reproduce it with a test that FAILS.** Write it in the project's real framework, at the level
|
|
27
|
+
that actually captures the bug (a unit test if the logic is wrong; an integration or functional
|
|
28
|
+
test if it only appears through the stack). **Run it and show the failure output.** This is the
|
|
29
|
+
gate: if you cannot make a test fail, you have not reproduced the bug, and you must say so rather
|
|
30
|
+
than proceeding to "fix" it.
|
|
31
|
+
|
|
32
|
+
3. **Find the root cause, not the symptom.** State it in one sentence with `file:line` evidence.
|
|
33
|
+
If the honest answer is "the symptom goes away if I add this guard, and I don't know why", say
|
|
34
|
+
that — a suppressed symptom is a worse bug wearing a hat.
|
|
35
|
+
|
|
36
|
+
4. **Make the smallest change that turns the test green.** Match the surrounding conventions. Resist
|
|
37
|
+
refactoring you happen to notice on the way: mention it, don't do it. A bugfix diff that also
|
|
38
|
+
restructures code is one nobody can review.
|
|
39
|
+
|
|
40
|
+
5. **Confirm.** The new test passes; the previously-failing case now works; the surrounding suite is
|
|
41
|
+
still green. Report the real commands and real output — if something fails, say so.
|
|
42
|
+
|
|
43
|
+
6. **Check for siblings.** Nearly every real bug has relatives: the same mistake in a parallel code
|
|
44
|
+
path, the same unguarded input elsewhere. Search for the pattern and report what you find. Fix
|
|
45
|
+
them only if trivial and clearly the same defect; otherwise list them for a decision.
|
|
46
|
+
|
|
47
|
+
## When to stop and escalate to `/spec`
|
|
48
|
+
|
|
49
|
+
Stop and say so if the fix would **change a contract** — an API shape, a status or error code, a
|
|
50
|
+
data model, an event payload, or behavior another service depends on. At that point it isn't a bug
|
|
51
|
+
fix, it's a change of intent, and it needs the contract on paper first. Also escalate if the "bug"
|
|
52
|
+
turns out to be the code behaving as specified and the *spec* being wrong.
|
|
53
|
+
|
|
54
|
+
If the change touches a published contract, run `/repo-impact` before shipping — a fix that corrects
|
|
55
|
+
your service and breaks a consumer is not a fix.
|
|
56
|
+
|
|
57
|
+
## Output
|
|
58
|
+
|
|
59
|
+
- **Root cause** — one sentence, with `file:line`.
|
|
60
|
+
- **The failing test** — its path, and the failure output from before the fix.
|
|
61
|
+
- **The change** — files touched and why, kept minimal.
|
|
62
|
+
- **Verification** — real commands, real results.
|
|
63
|
+
- **Siblings** — same defect elsewhere, fixed or flagged.
|
|
64
|
+
|
|
65
|
+
Then `/code-review` before opening the PR. Only commit when the human asks — and when you do, the
|
|
66
|
+
message names the humans who own the change and nothing else: no `Co-Authored-By:` line for an
|
|
67
|
+
assistant, no "Generated with"/"Made with" line, no model or vendor name, no tool badge or emoji.
|
package/commands/nfr.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Compile non-functional requirements into the two things that enforce them — standing constraints in the knowledge layer, and blocking pipeline gates
|
|
3
|
+
argument-hint: (no args) to check · `apply` to write docs/CONSTRAINTS.md · `gates <path>` to emit the pipeline block · `rules` to draft ml-skills custom rules
|
|
4
|
+
model: haiku
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Route the project's NFRs: **$ARGUMENTS**
|
|
8
|
+
|
|
9
|
+
NFRs are the requirements most likely to be agreed and then lost. They do not
|
|
10
|
+
decompose into user stories — a story breakdown flattens them into prose that
|
|
11
|
+
nothing checks. They decompose into exactly two things: a **standing constraint**
|
|
12
|
+
the author reads while writing every spec, and a **blocking pipeline gate**.
|
|
13
|
+
|
|
14
|
+
## Run it
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/nfr-compile.mjs # check only
|
|
18
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/nfr-compile.mjs --apply # write docs/CONSTRAINTS.md
|
|
19
|
+
node ${CLAUDE_PLUGIN_ROOT}/scripts/nfr-compile.mjs --gates ci/nfr-gates.yml
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Reads `docs/NFRS.md` — a markdown table, so a change to what is in force reviews
|
|
23
|
+
in a pull request like anything else — falling back to `nfrs.json`.
|
|
24
|
+
|
|
25
|
+
## The three things it refuses, and how to explain each
|
|
26
|
+
|
|
27
|
+
**No machine-checkable threshold.** "The API shall be performant" cannot become a
|
|
28
|
+
gate, so it cannot be enforced, so it will be lost. Do not soften this: ask the
|
|
29
|
+
user for the metric, operator and value. If they genuinely cannot name one, the
|
|
30
|
+
honest move is to delete the NFR rather than keep a requirement nothing can fail.
|
|
31
|
+
|
|
32
|
+
**Flattened into an acceptance criterion.** An NFR id appearing inside an AC is
|
|
33
|
+
the exact failure mode — at that point it has stopped being enforced and become a
|
|
34
|
+
sentence. Point at the spec and criterion, and move it back out.
|
|
35
|
+
|
|
36
|
+
**Named by a spec but defined nowhere.** Worse than unrouted: the spec claims a
|
|
37
|
+
constraint that does not exist. Either add it to `docs/NFRS.md` or remove the
|
|
38
|
+
reference.
|
|
39
|
+
|
|
40
|
+
## The third destination: a rule that actually fires
|
|
41
|
+
|
|
42
|
+
A constraint in `docs/CONSTRAINTS.md` is read by whoever writes the next spec. A pipeline gate runs
|
|
43
|
+
at the end. Between those two there is a gap: the code being written *right now*, by a person or an
|
|
44
|
+
agent who has not opened the constraints file. Some NFRs can close that gap, because they are
|
|
45
|
+
structural rather than measured — and those belong in the architecture standards as a rule.
|
|
46
|
+
|
|
47
|
+
The split is worth being precise about, because putting an NFR in the wrong place is how it stops
|
|
48
|
+
being enforced:
|
|
49
|
+
|
|
50
|
+
| NFR shape | Example | Where it goes |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| **Measured at runtime** | p95 latency < 200ms; 99.9% availability | Pipeline gate. Nothing static can see it. |
|
|
53
|
+
| **Structural, visible in source** | every outbound call sets a timeout; no PII in logs; images pinned | An `ml-skills` rule — it fires while the code is being written |
|
|
54
|
+
| **Both** | secrets never committed | A rule *and* a gate. Cheap; do both. |
|
|
55
|
+
|
|
56
|
+
Before drafting anything, ask whether the gate you already have is a gate at all. If the
|
|
57
|
+
`ml-skills` MCP server is available, call **`gate_manifest`**. It returns the complete set of rules
|
|
58
|
+
that can turn this pipeline red *today* — `blocking` — plus everything that only advises, and names
|
|
59
|
+
every standard still unratified and therefore toothless. A `blockingCount` of 0 is the answer to
|
|
60
|
+
"is this NFR enforced or merely written down?", and it is worth knowing before you add a rule to a
|
|
61
|
+
gate that cannot fail. Adding a rule under an unratified standard produces a warning nobody actions,
|
|
62
|
+
not a constraint — ratify it in the same change or the NFR is documentation wearing a rule's clothes.
|
|
63
|
+
|
|
64
|
+
For a structural NFR, draft the rule and put it to the user:
|
|
65
|
+
|
|
66
|
+
```jsonc
|
|
67
|
+
// .mlskills.json
|
|
68
|
+
{ "customRules": [{
|
|
69
|
+
"id": "NFR001", // the NFR's own id, so the trace survives
|
|
70
|
+
"skill": "resilience-patterns", // which standard it belongs under
|
|
71
|
+
"severity": "error",
|
|
72
|
+
"files": ["**/*.ts", "**/*.java"],
|
|
73
|
+
"forbid": "\\bfetch\\s*\\(",
|
|
74
|
+
"near": { "pattern": "timeout|signal|AbortSignal", "lines": 6 },
|
|
75
|
+
"title": "NFR001 — every outbound call sets a timeout",
|
|
76
|
+
"why": "<the NFR's own rationale, verbatim from docs/NFRS.md>",
|
|
77
|
+
"message": "outbound call with no timeout (NFR001)"
|
|
78
|
+
}] }
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Three things to hold to when you do this:
|
|
82
|
+
|
|
83
|
+
- **Keep the NFR's id as the rule id.** That is the whole trace: `docs/NFRS.md` → the rule → the
|
|
84
|
+
finding a developer sees. Renaming it breaks the only link back to why the rule exists.
|
|
85
|
+
- **Draft it, then verify it actually fires.** Write the rule, then run
|
|
86
|
+
`npx @mlmcps/ml-skills check .` against a file you know violates it. A rule that matches nothing
|
|
87
|
+
reports a clean repo, which is worse than having no rule at all — it manufactures false
|
|
88
|
+
confidence in exactly the requirement someone insisted on.
|
|
89
|
+
- **Do not ratify on the user's behalf.** A custom rule on an unratified standard can only warn.
|
|
90
|
+
Say so, and let the human decide whether it is allowed to fail a build — that decision is theirs,
|
|
91
|
+
and taking it for them is how a gate gets disabled the week after it lands.
|
|
92
|
+
|
|
93
|
+
If the standard the rule belongs under does not exist yet, say so rather than forcing it into the
|
|
94
|
+
nearest one — a mis-filed rule is a rule nobody looks for.
|
|
95
|
+
|
|
96
|
+
## After a successful `--apply`
|
|
97
|
+
|
|
98
|
+
Say which constraint ids changed — the script reports exactly that, and reports
|
|
99
|
+
nothing when the write was a no-op. Do not claim an update that did not happen.
|
|
100
|
+
|
|
101
|
+
Mention that the next `/spec` on an affected repo will carry these constraints
|
|
102
|
+
into the new spec automatically, so nobody has to remember they exist. If any of
|
|
103
|
+
them were also compiled into `ml-skills` rules, say which — those fire while the
|
|
104
|
+
code is being written, not just when it is reviewed.
|
|
105
|
+
|
|
106
|
+
## Close
|
|
107
|
+
|
|
108
|
+
If any NFR was refused, the project is not enforcing what it thinks it is. Lead
|
|
109
|
+
with that count, not with the ones that compiled.
|
|
110
|
+
|
|
111
|
+
Then report the routing honestly, per NFR: constraint only, constraint + gate, or
|
|
112
|
+
constraint + gate + rule. An NFR sitting in `docs/CONSTRAINTS.md` with no gate and
|
|
113
|
+
no rule is documented, not enforced, and the difference is the entire point of
|
|
114
|
+
this command.
|
package/commands/pr.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Turn a completed spec plus its diff into a PR title and description, with the acceptance criteria as a review checklist
|
|
3
|
+
argument-hint: <path to spec file, e.g. specs/0001-foo.md> — omit to use the spec matching the current branch
|
|
4
|
+
model: sonnet
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Spec: **$ARGUMENTS**
|
|
8
|
+
|
|
9
|
+
If no spec was given, find the one matching the current branch (the spec whose **Branch** row or
|
|
10
|
+
number/slug matches `git rev-parse --abbrev-ref HEAD`). If that's ambiguous, ask which spec rather
|
|
11
|
+
than guessing.
|
|
12
|
+
|
|
13
|
+
Use the **pr-author** agent to produce the PR title and body from the spec plus the branch diff.
|
|
14
|
+
|
|
15
|
+
Before delegating, check the spec's Status and say so up front if the work isn't verified yet — a
|
|
16
|
+
PR from an `Implemented` spec is fine, but the human should know `/spec-verify` hasn't passed.
|
|
17
|
+
|
|
18
|
+
Relay the agent's output **ready to paste**: the title, then the body (`## Summary`,
|
|
19
|
+
`## Changes`, `## Acceptance criteria` as a checklist mapped to tests, `## Testing` with the real
|
|
20
|
+
commands and real results, `## Risks / follow-ups`), with the spec file linked.
|
|
21
|
+
|
|
22
|
+
Hard rules:
|
|
23
|
+
- **Do not open or push the PR** as part of this command, and do not commit. This produces text.
|
|
24
|
+
- Only if the user explicitly asks to open it: push the branch, then `gh pr create --title ... --body-file <file>`
|
|
25
|
+
using the generated body written to a temp file (never retype it inline).
|
|
26
|
+
- Never tick an acceptance criterion the diff doesn't clearly satisfy, and never state a test result
|
|
27
|
+
you didn't observe. An honest unchecked box is the point of the checklist.
|
|
28
|
+
- **No AI attribution** in the title or body: no `Co-Authored-By:` line for an assistant, no
|
|
29
|
+
"Generated with"/"Made with" line, no model or vendor name, no tool badge or emoji. If the user
|
|
30
|
+
asks you to open the PR, pass the body through unchanged — don't let `gh` or a template append one.
|
|
31
|
+
|
|
32
|
+
Next step: `/spec-advance <spec-file> Archived` once the PR is merged.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Adopt the toolkit into a repo that already has a hand-written CLAUDE.md or docs/ — merges instead of overwriting, and never deletes human prose
|
|
3
|
+
argument-hint: (no args) — run from the root of a repo that already has its own CLAUDE.md/docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are adopting the ml-specs into a repo that **already has a knowledge layer someone wrote by
|
|
7
|
+
hand**. `/repo-init` assumes a blank slate; this doesn't. The difference matters because the fastest
|
|
8
|
+
way to make a team distrust a tool is to have it clobber documentation they wrote.
|
|
9
|
+
|
|
10
|
+
**The rule for this entire command: human prose is never deleted and never silently rewritten.**
|
|
11
|
+
When the existing text and what you'd generate disagree, the human's text stays and you flag the
|
|
12
|
+
disagreement. You are adding structure around their work, not replacing it.
|
|
13
|
+
|
|
14
|
+
The plugin's templates live under `${CLAUDE_PLUGIN_ROOT}/templates/`.
|
|
15
|
+
|
|
16
|
+
## Phase 1 — inventory what's already there
|
|
17
|
+
|
|
18
|
+
1. Read what exists: `CLAUDE.md`, `docs/` (any structure), `specs/`, `AGENTS.md`, `.cursorrules`,
|
|
19
|
+
`.github/copilot-instructions.md`, `CONTRIBUTING.md`. Teams keep agent instructions in all of
|
|
20
|
+
these — find them before assuming there's nothing to preserve.
|
|
21
|
+
|
|
22
|
+
2. **Classify every section** you found into three buckets, and show the user this classification
|
|
23
|
+
*before* writing anything:
|
|
24
|
+
- **Keep verbatim** — project knowledge only a human knew: domain rules, gotchas, history, "we
|
|
25
|
+
tried X and it broke". This is the valuable part and it is not regenerable.
|
|
26
|
+
- **Merge** — something the toolkit also covers (build commands, conventions, a patterns
|
|
27
|
+
section). Their version wins on content; you may restructure around it.
|
|
28
|
+
- **Missing** — toolkit sections with no counterpart (the working agreement, the spec loop, the
|
|
29
|
+
knowledge-layer index, quality gates).
|
|
30
|
+
|
|
31
|
+
3. **Check the existing content against the code**, the same way `/repo-init` learns. Where a
|
|
32
|
+
hand-written claim is now wrong (a command that no longer exists, a pattern the code abandoned),
|
|
33
|
+
**do not correct it silently** — collect it for the report. A stale claim a human wrote is
|
|
34
|
+
still theirs to retire.
|
|
35
|
+
|
|
36
|
+
## Phase 2 — learn what's missing
|
|
37
|
+
|
|
38
|
+
4. Run `/repo-init`'s Phase 1 learning, but **only for what the existing docs don't already cover**.
|
|
39
|
+
Don't re-derive conventions they've already written down — read theirs, verify it, and move on.
|
|
40
|
+
The point is to fill gaps, not to produce a second opinion on everything.
|
|
41
|
+
|
|
42
|
+
## Phase 3 — merge
|
|
43
|
+
|
|
44
|
+
5. **`CLAUDE.md`** — keep their structure and wording. Append only the toolkit sections that are
|
|
45
|
+
missing (from `${CLAUDE_PLUGIN_ROOT}/templates/CLAUDE.fragment.md`), and add the knowledge-layer
|
|
46
|
+
index pointing at whatever `docs/` files actually exist here — including the ones they named
|
|
47
|
+
differently. Do not rename their files to match the templates. If their `CLAUDE.md` is already
|
|
48
|
+
over budget, say so and propose what to move out; don't do it unasked.
|
|
49
|
+
|
|
50
|
+
6. **`docs/PATTERNS.md`** — if they have an equivalent under any name, extend it in their format
|
|
51
|
+
and mark **only what you added** as `(inferred)`. If there's nothing, generate it as `/repo-init`
|
|
52
|
+
would. Never reformat their existing patterns into the template's shape.
|
|
53
|
+
|
|
54
|
+
7. **`docs/ARCHITECTURE.md`** — same. If their structure doc is organised differently (by feature,
|
|
55
|
+
by layer), keep their organisation; add the `Depends on / Used by` edges if absent, since that's
|
|
56
|
+
what the agents actually retrieve on.
|
|
57
|
+
|
|
58
|
+
8. **`specs/`** — scaffold `README.md`, `TEMPLATE.md`, `AGENTS.md` if absent. If they already have a
|
|
59
|
+
spec/RFC/ADR practice, **map onto it instead of replacing it**: keep their directory, their
|
|
60
|
+
numbering, and their template's sections, and add only what the loop needs (acceptance criteria
|
|
61
|
+
that are testable, the §6.1 final-acceptance gate, the Status field `/spec-advance` reads).
|
|
62
|
+
Report the mapping so they can see what changed about their process.
|
|
63
|
+
|
|
64
|
+
9. **Commit attribution** — merge the `attribution` key from
|
|
65
|
+
`${CLAUDE_PLUGIN_ROOT}/templates/settings.json` into `.claude/settings.json`, creating the file
|
|
66
|
+
if absent and leaving every other key untouched. If the repo already sets `attribution`, keep
|
|
67
|
+
their value and report it rather than overwriting — this command never overrides a deliberate
|
|
68
|
+
choice. Committed, it applies to everyone who clones the repo with no per-machine setup.
|
|
69
|
+
|
|
70
|
+
10. **CI + hooks** — offer, don't install: the knowledge-layer gate
|
|
71
|
+
(`${CLAUDE_PLUGIN_ROOT}/templates/ci/`) with `--warn-only` for a repo with existing drift, and
|
|
72
|
+
the opt-in project hooks. Say that the plugin's own hooks (drift warning, secret scan) are
|
|
73
|
+
already active on install and need nothing here.
|
|
74
|
+
|
|
75
|
+
## Phase 4 — report
|
|
76
|
+
|
|
77
|
+
11. Report as three lists, in this order:
|
|
78
|
+
- **Preserved** — their content you kept, by section. Lead with this.
|
|
79
|
+
- **Added** — toolkit sections that were missing.
|
|
80
|
+
- **Conflicts** — where their docs and the code disagree, each with `file:line` evidence and
|
|
81
|
+
**no change made**. These are decisions for them, not for you.
|
|
82
|
+
|
|
83
|
+
Then: what to review first, and that `/repo-doctor` will now keep checking it. Do NOT commit.
|
|
84
|
+
|
|
85
|
+
If the repo has no knowledge layer at all, this is the wrong command — say so and point at
|
|
86
|
+
`/repo-init`. If it has one the toolkit already generated, point at `/repo-refresh`.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Health-check the project's Claude knowledge layer (CLAUDE.md, docs/, specs/) and report drift — read-only, suggests /repo-refresh when needed
|
|
3
|
+
argument-hint: (no args) — run from the repo root
|
|
4
|
+
model: haiku
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are doing a **read-only health check** of this repo's spec-driven-development setup. Do NOT
|
|
8
|
+
edit any files — diagnose and report, then recommend the fix command.
|
|
9
|
+
|
|
10
|
+
The point: the knowledge layer is only worth its tokens if it's *accurate*. A stale doc that
|
|
11
|
+
points at deleted files or contradicts the code is worse than none. Find the drift, don't fix it.
|
|
12
|
+
|
|
13
|
+
Steps:
|
|
14
|
+
|
|
15
|
+
1. **Inventory.** Check which knowledge files exist: `CLAUDE.md`, `docs/PATTERNS.md`,
|
|
16
|
+
`docs/ARCHITECTURE.md` (or sharded `docs/architecture/*.md` + `docs/patterns/*.md`),
|
|
17
|
+
`specs/README.md`, `specs/TEMPLATE.md`. If none exist, report that and recommend `/repo-init`,
|
|
18
|
+
then stop.
|
|
19
|
+
|
|
20
|
+
2. **Broken references.** If `.github/scripts/knowledge-check.mjs` exists, run it — it does this
|
|
21
|
+
check mechanically and faster than you can. Otherwise scan the docs for `file:line` references
|
|
22
|
+
and file paths yourself, flagging any that point at files that no longer exist or whose line
|
|
23
|
+
ranges are now well off (the file shrank past the cited line). These are the highest-signal
|
|
24
|
+
drift markers. If the script is missing, recommend seeding it from the plugin's `templates/ci/`
|
|
25
|
+
so CI catches this instead of waiting for someone to run `/repo-doctor`.
|
|
26
|
+
|
|
27
|
+
3. **Stale commands.** Cross-check the build/test/run/lint commands listed in `CLAUDE.md` against
|
|
28
|
+
the real manifest/build file (`package.json` scripts, `pom.xml`/`build.gradle`, `Makefile`/
|
|
29
|
+
`Taskfile`, `pyproject.toml`, etc.). Flag commands that no longer exist.
|
|
30
|
+
|
|
31
|
+
4. **Budget & shape.** Flag any doc over its ~200-line budget, and whether `CLAUDE.md` is still a
|
|
32
|
+
thin index (links out) rather than having inlined large patterns. For sharded layouts, flag
|
|
33
|
+
router rows pointing at missing shards, or module shards with no router row.
|
|
34
|
+
|
|
35
|
+
5. **`(inferred)` markers.** List patterns still marked `(inferred)` in `docs/PATTERNS.md` — they
|
|
36
|
+
were never confirmed against code and deserve a human glance.
|
|
37
|
+
|
|
38
|
+
6. **Spec hygiene.** In `specs/` (ignore `specs/archive/`), flag:
|
|
39
|
+
- Status `Implemented` with unchecked acceptance criteria.
|
|
40
|
+
- Status `Verified` where a §6 test-plan row names a test file that doesn't exist — the status
|
|
41
|
+
claims evidence the repo doesn't have.
|
|
42
|
+
- Status `Verified` with the branch already merged into the default branch → should be archived
|
|
43
|
+
(`/spec-advance <spec> Archived`).
|
|
44
|
+
- Stuck in `Draft`/`Approved` with no matching branch or code (best-effort; don't block on it).
|
|
45
|
+
- Two specs sharing a number, or a `Status` holding prose rather than one lifecycle word.
|
|
46
|
+
Both are mechanical to repair — point at `scripts/fix-specs.mjs` in the plugin (dry run by
|
|
47
|
+
default) rather than fixing them one at a time here.
|
|
48
|
+
- A blocking contract question parked in section 8 (an answer that would change an API shape,
|
|
49
|
+
data model, error code, scope, or compatibility) — that spec isn't approvable as written.
|
|
50
|
+
|
|
51
|
+
7. **`(inferred)` vs reality spot-check.** Pick 2–3 of the most load-bearing claims in
|
|
52
|
+
`docs/PATTERNS.md` / `docs/ARCHITECTURE.md` and verify them against the code. Report matches and
|
|
53
|
+
mismatches.
|
|
54
|
+
|
|
55
|
+
Report a concise, prioritized list grouped as **Broken (fix now)**, **Stale (likely drift)**, and
|
|
56
|
+
**OK**. End with a one-line recommendation: run `/repo-refresh` if there's real drift, `/repo-init`
|
|
57
|
+
if nothing exists, or "knowledge layer looks healthy" if clean. Do NOT make changes yourself.
|