| name | spec |
| description | Archive an agreed design as a task specification — requirements with stable R-ids, a ratified tests.manifest.json (contract rows, decision rows with enforcement pointers, touch map, spike list), a slimmed mechanics doc for the prose residue, taste decisions drafted into meme, one tandem commit |
| argument-hint | [optional] Path for the spec (e.g., docs/tasks/043-harness-redesign). Omit to auto-create docs/tasks/<NNN>-<slug> |
Ultrathink
Archive Task Specification
Transcribe an already-resolved design into a durable record whose load-bearing parts are DATA. This command does not think — it archives. The debate happened in /brainstorm; here you write down the conclusion, and everything downstream (/build's gates, joins, and lints) consumes what you write mechanically. A row you archive sloppily becomes a gate that enforces the wrong thing.
Drift gate: transcribing must never resolve an intent question the conversation left open. Bounce gaps as a set (Step 4).
The artifact set, by role:
requirements.md — the WHAT, with stable R<n> ids per requirement. The coverage join keys on these ids; renumbering after the plan commit is a breaking change.
tests.manifest.json — the ratified intent rows. This is the file /build's gates enforce; it is user-owned and hook-locked after the tandem commit.
mechanics.md — the prose residue ONLY: mechanism narrative, DDL sketches, choreography, environment context. Anything expressible as a row goes in the manifest, not here. Write it only when qualifying content exists; no resolved-ambiguities closure table — dissolve each resolution into its natural section.
Step 1: Resolve the spec directory
$ARGUMENTS non-empty → use it verbatim (mkdir -p). Otherwise derive a 3–6 word kebab slug from the conversation and run ~/.claude/skills/spec/bin/spec-dir "<slug>" (absolute path; it numbers, creates, and prints <spec-dir> — never hand-roll the numbering).
Step 2: Confirm a resolved design exists
The conversation must contain: an agreed approach, the resolved questions behind it, the invariants with verification methods, acceptance criteria, and — when the design replaces or rewires an existing seam — a behavior inventory with a user verdict per row. /brainstorm's handoff block carries these as candidate manifest rows already; organic debates carry them as prose to be row-ified here. Missing any of it → send the user to /brainstorm; the spec archives a conclusion, it does not manufacture one.
Step 3: Load project context
Read CLAUDE.md (test framework, runner, conventions) and docs/spec.md if present (project-specific template additions; declare non-applicable sections N/A in the preamble, never silently omit). Mechanical lookups only — mark convention-derived values (default).
Step 4: Drift gate — bounce gaps as a set
Classify everything you are about to transcribe:
- Mechanical lookup — fill from Step 3, mark
(default). Not drift.
- Resolved mechanics — settled HOW-detail → manifest rows where row-shaped,
mechanics.md where prose-shaped. Not drift.
- Intent gap — a behavior, scope, expectation value, or verdict the conversation never settled. DRIFT: collect every one and bounce the set to
/brainstorm (or let the user answer inline now). A contract row missing its then values is an intent gap — a row without expectations is a checkbox, not a contract.
Brownfield sweep: a replaced/rewired seam with no behavior inventory, or any inventory row without a preserved/dropped verdict, is an intent gap. Cross-task conflict sweep: ~/.claude/skills/meme/bin/meme search on each requirement's entities; a contradicted prior decision- fact is an intent gap — the user rules on reversals in the debate, not the archive.
Step 5: Write requirements.md
# Task: [name]
[Preamble: provenance ("Archives the design debate of <dates>"); companion pointer with read
gate when mechanics.md exists; N/A declarations for template sections that don't apply.]
## Decisions
[The WHY. Inline markers: `(default)` convention; `(taste)` user judgment, written at
generalizable altitude (drafted to meme in Step 7); evidence-driven choices carry
`(evidence: …)` and stay task-local. Structural decisions with cross-phase blast radius
also become manifest decision rows with an `enforcement` pointer in Step 6.]
- D1: [choice] — because [reasoning] (evidence: [...])
- D2 (taste): [choice] — because [generalizable principle]
## Requirements
[The WHAT, one id per requirement — the coverage join keys on these.]
- R1: [observable requirement]
- R2: [...]
## Invariants
[Assertions with verification methods. Each testable invariant gets a manifest row in
Step 6; a claim no local test reaches names its drill or metric here instead.]
- INV1: [property] — verify: [row id | drill | metric]
`INV<n>` ids are spec-internal indices only — their meaning lives here and is reused with
different meanings across tasks. Production code and tests must state the invariant's
*content*, never the bare id (`(INV3)`): a code comment reads outside this archive, where
`INV3` is meaningless, and provenance-lint blocks bare invariant ids in committed code.
## Behavior Inventory
[Brownfield only. Behavior-as-is read from the CURRENT code during the debate, one verdict
per row. Preserved rows become `tier: characterization` manifest rows; dropped rows cite
the Decisions line dropping them.]
| # | Seam | Observable behavior (as-is) | Verdict |
|---|------|-----------------------------|---------|
## Done When
[Acceptance, each carrying execution class: local-tdd / infra / docs / live-only.
Per the precondition trap: any "X passes" item names a baseline verified during the debate.]
- [ ] [outcome] (local-tdd) — R<n>
## Deferred
[Agreed items outside this task's scope, each with its user-visible consequence while it
waits. /build narrates this at kickoff and re-discloses it at the final gate.]
## Test Plan
### Runner
- Framework and scoped run command (from CLAUDE.md, or resolved in the debate — never invented here)
### Task-level requirements
- [R-ids that compile to no single phase's row — the join checks these at task tier]
Step 6: Write tests.manifest.json
The enforced artifact. Transcribe — never invent — one row per contract scenario the debate ratified:
{ "schema": 1, "task": "<dir basename>",
"rows": [
{ "id": "kebab-scenario-id", "phase": "01", "tier": "contract",
"mode": "assertion-red", "fqn": "com...ClassIT#method",
"drives": "Service.method(Args) -> ReturnShape",
"given": "...", "when": "...", "then": { "field": "expected" },
"requirement": "R1", "status": "ratified" } ],
"decisions": [
{ "id": "D3", "text": "...", "enforcement": "ArchRulesTest#rule | ast-grep:rule-id | review-only" } ],
"touches": { "01": ["path/or/glob", "Class.method"] },
"stubAllow": { "01": ["**/NewInterface.java"] },
"testExceptions": { "01": ["**/seed/*.sql"] },
"taskLevel": ["R9"],
"spikes": [ { "id": "probe-trigger-privilege", "phase": "01", "cmd-sketch": "...", "kills": "the trigger mechanism" } ],
"phases": { "01": { "kind": "local-tdd", "deps": [],
"validation": "backend/gradlew -p backend test --tests 'com...ClassIT'",
"checks": ["backend/gradlew -p backend checkstyleMain test"], "timeboxMin": 20 } } }
Rules: tier ∈ contract | characterization | arch; mode ∈ assertion-red | compile-red | must-stay-green | green-only (green-only is a ratified exemption, declared here, never implied); every drives seam pins an observable boundary, never internals; provisional phase assignments come from the debate's decomposition sketch — /build's planner refines ordering, never membership; a structural decision without an enforcement value and without an explicit review-only flag is an intent gap. Function bodies are never pinned anywhere.
Spike entries exist for every phase whose HOW touches an environment boundary (DB privileges, container config, external APIs) — the feasibility trap made executable.
Step 7: Capture — draft (taste) decisions
Draft each (taste) principle while its debate is in context (~/.claude/skills/meme/bin/meme draft --text "..." — absolute path; drafts are inactive and gitignored). Display the promote/reject verbs per item; run promote only on the user's word (it stages, never commits). Skipped items ride the SessionStart trickle. (default) and (evidence) content never drafts.
Step 8: Tandem commit — consent-gated
Propose exactly one commit: git add <spec-dir> (sweeps requirements, manifest, mechanics) plus any promoted fact files. Show the command and wait for explicit approval; never auto-run. Declined → promoted facts stay staged for the user's own commit; nothing is lost.
Step 9: Summary
List files written; the row count by tier; each intent gap the drift gate bounced (if any); the taste adjudication ledger (promoted relids verbatim as promote printed them, or deferred); the tandem commit's status. Then: /build <spec-dir> runs docs-only in a fresh session — anything it must know is in these files now.