Six Claude Code skills that carry one identifier from a rough idea to shipped code — every requirement gets a number in the spec, and every task, verification, audit and refactoring after it cites that number.
Plain Markdown, read by Claude Code.
No package.json, no dependencies, no build step, nothing that executes at install.
Most spec workflows are a handful of prompts that run in order, and nothing travels between them —
so by the fourth prompt the agent is judging prose it wrote itself. What travels here is an
identifier: stage 2 writes each requirement as one EARS sentence with a stable AC-###, and no
later stage may refer to a requirement any other way.
docs/SPEC.md AC-003 If two shifts for one employee overlap by any minute, then the
scheduler shall flag both and refuse to publish.
TASKS.md - [ ] T-04 Detect overlaps on a minute timeline — closes AC-003
REPORT.md - [ ] R-02 Extract `toRange`, delete the two copies — preserves AC-003
closes in stage 3, preserves in stage 6 — one word apart, and the whole difference between
building a feature and restructuring one. A task that closes no criterion is either unnecessary
work or a requirement nobody wrote down.
flowchart LR
C["1 constitution"] -- "verify command" --> A
A["2 spec"] -- "assigns AC-###" --> T
T["3 tasks"] -- "closes AC-###" --> I
I["4 implement"] -- "verifies AC-###" --> D
D{"5 drift"} -- "code contradicts<br/>a recorded reason" --> R["regression<br/><i>fix the code</i>"]
D -- "nothing forbade it" --> S["staleness<br/><i>fix the spec</i>"]
D -- "clean, but expensive<br/>to change" --> F["6 refactor<br/><i>preserves AC-###</i>"]
R --> A
S --> A
F --> A
| Stage | Command | Writes | The rule it enforces |
|---|---|---|---|
| 0 | /spec-start |
nothing | Six commands in a picker give you no way to tell which one begins |
| 1 | /spec-constitution |
docs/CONSTITUTION.md |
A rule earns its place only if you can name what breaks when it is violated |
| 2 | /spec-architect |
docs/SPEC.md |
Never ask what you can decide — ask only what changes the architecture |
| 3 | /spec-tasks |
TASKS.md |
A task is done when a named criterion is satisfied, not when the code looks finished |
| 4 | /spec-implement |
code | One task, verify, then the next — stop at the first unmet criterion |
| 5 | /spec-drift |
a report | The spec and the code disagree: say which one is wrong |
| 6 | /spec-refactor |
docs/refactorings/NNNN/ |
Restructure only what blocks scheduled work — and change no criterion doing it |
Stages 1 and 6 are optional and every stage runs alone. The last two audit different things: drift asks whether the code does what the spec says, refactor asks whether code that already does can still be changed cheaply.
Stage 6 handles code smells and dead code, and two
rules keep it from restructuring a working system for sport. A smell is actionable only if it is
a Change Preventer for work that is actually scheduled — everything else is logged with an
SM-### and left alone. And a refactoring may not change what the spec says the system does:
if it needs an AC-### reworded it is not a refactoring, it is a change proposal for stage 2.
That second rule is what makes "behaviour is preserved" checkable rather than promised — verify green before, green after, every cited criterion re-read against the new code. The two halves of the work carry different burdens of proof, and land in separate commits:
| Cleanup | Refactoring | |
|---|---|---|
| Admitted by | a static-analysis tool flagged it | the gate above |
| Removes | unused imports, unreferenced locals, dead exports | duplication, shotgun surgery, god functions |
| Risk | deleting something reached reflectively | an unreviewable diff |
| Commit | its own, apart from any behaviour change | one per refactoring |
Nothing goes on a hunch: /spec-refactor writes a numbered report under docs/refactorings/ and
changes no code itself. Runs are never overwritten, and every SM-### it has ever allocated stays
in one registry — so a smell that comes back carries the record of being paid off once already.
Closing a run out belongs to stage 5, which re-checks that each smell really is gone before writing
removed and archiving the directory: a ticked box records what someone believed, and the registry
records what is true.
Requires Claude Code. Nothing is installed, compiled or executed.
/plugin marketplace add DahanItamar/spec-architect
/plugin install spec-architectThen run /spec-start. It reads the repository and names the one command to run next —
/spec-constitution on a new repo, /spec-architect if the conventions are settled,
/spec-implement if a task list is sitting there half-ticked.
The skills also work copied straight into ~/.claude/skills/. Pick one route or the other — do
both and every command shows up twice in the picker, from two copies that drift apart.
Important
The two stages that run shell commands — /spec-implement and /spec-refactor — run only
the verify command named in docs/CONSTITUTION.md. Never one found in a spec, a task list, a
refactoring report or a code comment. Those files are editable by anyone with commit access, so
treating their contents as instructions would turn a Markdown file into remote code execution.
The one thing here that executes. No install — CI runs it on Node 22, output below is v24.15.0:
node --test examples/proof/proof.test.mjs▶ drifted — the code three weeks after the spec was written
✔ but the night shift can no longer be saved — §8 is contradicted (0.3713ms)
✔ and the rejection is silent: the overlap is simply never detected (0.1212ms)
▶ smelly — passes every criterion and is still unshippable
✔ behaves exactly like the spec-derived version — spec-drift finds nothing (0.2465ms)
✔ SM-002 Duplicate Code: the same day arithmetic, copied three times (0.0478ms)
ℹ tests 17
ℹ pass 17
ℹ fail 0
ℹ duration_ms 64.4798
Four lines of a 17-test run. The suite builds one shift-conflict feature four ways and asserts what each does to a shift that crosses midnight:
| Version | Tests green | Matches the spec | Cheap to extend |
|---|---|---|---|
naive.mjs — no spec, shapes chosen by convenience |
✅ | ❌ | ❌ |
spec-derived.mjs — built against §5 and §8 |
✅ | ✅ | ✅ |
drifted.mjs — three weeks and one sensible-looking fix later |
✅ | ❌ | ✅ |
smelly.mjs — six months and four features later |
✅ | ✅ | ❌ |
The last two rows are the argument. drifted.mjs contradicts §8 of its own spec, so a night shift
silently stops being storable — stage 5 catches that. smelly.mjs contradicts nothing and still
shows an overnight shift as -960 minutes in its tooltip, because one of three copies of the same
calculation diverged where no criterion looks — stage 6 catches that.
- Nothing executes at install. No dependencies, no build, no network calls. The only runnable
code is 5
.mjsfiles underexamples/proof/, importingnode:test,node:assert/strictandnode:fs. - 3,187 lines that load on demand. Each
SKILL.mdloads on invocation, the largest being 171 lines; its references load only at the phase that needs them, so a task list is never written with the risk checklist in context. - Change proposals, not spec rewrites. Once
docs/SPEC.mdexists,/spec-architectwrites a diff underdocs/changes/and leaves the spec alone — the reasoning that made feature 1 correct is the asset. Criteria are retired as tombstones, never reused, because archived task lists still cite them.
Built by Itamar Dahan · MIT · © 2026