@skitterbyte/skitterspec 16.10.0 → 18.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.
@@ -6,10 +6,10 @@ description: Create a new spec-driven-development spec. Grills the user to a cle
6
6
  # /spec — author a new spec
7
7
 
8
8
  Produce ONE concise spec in `specs/backlog/`. Do not start coding — this skill
9
- plans only. Implementation happens later via `/spec-go`.
9
+ plans only. Implementation happens later via `/spec-start`.
10
10
 
11
11
  Lifecycle (the governing skills) — status in parentheses:
12
- `/spec` (writes **Ready** when fully groomed, else Draft; backlog) → `/spec-go`
12
+ `/spec` (writes **Ready** when fully groomed, else Draft; backlog) → `/spec-start`
13
13
  (In Progress, in-progress; implement phase 1) → `/spec-complete` (Complete) /
14
14
  `/spec-cancel` (Cancelled). See `.claude/rules/spec-planning.md`. (There is no
15
15
  separate grooming command — `/spec` grills to a Ready spec directly.)
@@ -23,7 +23,12 @@ not write the spec until this is resolved.
23
23
 
24
24
  - Break the problem into **distinctive areas** and work them in logical order,
25
25
  resolving dependencies between decisions one at a time.
26
- - Ask **one question at a time**. For each, give your **recommended answer**.
26
+ - **Batch independent questions; sequence dependent ones.** When several
27
+ questions do not affect each other's answers, put them to the user together
28
+ (up to four at once — use the harness's multi-question ask tool where it has
29
+ one) rather than spending a round trip on each. When an answer would change
30
+ what you ask next, ask that one alone and wait for it. Give your
31
+ **recommended answer** either way.
27
32
  - If a question can be answered by **reading the codebase, read it** instead of
28
33
  asking. Verify endpoints/models/files actually exist before relying on them.
29
34
  - Cover, at minimum, the areas that apply:
@@ -42,9 +47,19 @@ not write the spec until this is resolved.
42
47
  this spec touch the DB / stateful services (so its worktree needs a Docker
43
48
  stack), or is a plain worktree enough? Default `worktree`; escalate to
44
49
  `worktree + docker` only when it must. This sets the `> **Stack:**` header
45
- that `/spec-go` acts on (it can be escalated later). Skip when isolation
50
+ that `/spec-start` acts on (it can be escalated later). Skip when isolation
46
51
  isn't enabled — leave the default `worktree`.
47
- 10. **Open questions** anything still undecided.
52
+ 10. **Release gating** *(only when `specs/.core/gating.config.json` exists)* —
53
+ should this ship behind a feature flag, or land live?
54
+ **Offer, don't impose**: the user decides and you raise it, so a spec
55
+ never reaches
56
+ `/spec-complete` with the question unasked. Cite the project's own
57
+ `guidance` path from that config when it names one — skitterspec knows
58
+ nothing about how this project does flags, and must not guess. Record the
59
+ answer **either way**: a flag name, or `none: <one-line reason>`. "No" is a
60
+ decision and belongs in the header; silence is not. Skip entirely when the
61
+ config is absent — that project does not use flags.
62
+ 11. **Open questions** — anything still undecided.
48
63
 
49
64
  Stop grilling when there are no unresolved branches that would change the spec.
50
65
  Briefly play back the agreed understanding before writing.
@@ -95,7 +110,7 @@ the codebase, link rather than duplicate):
95
110
  # <Feature title>
96
111
 
97
112
  > **Type:** Feature
98
- > **Name:** feat-<kebab-name> (the spec folder name — the handle you paste into `/spec-go`)
113
+ > **Name:** feat-<kebab-name> (the spec folder name — the handle you paste into `/spec-start`)
99
114
  > **Status:** Ready — not started
100
115
  > **Author:** <git user.name — `git config user.name`>
101
116
  > **Developer:** —
@@ -103,6 +118,9 @@ the codebase, link rather than duplicate):
103
118
  > **Area:** <comma-separated files/modules this touches>
104
119
  > **Stack:** <worktree — or "worktree + docker" if it touches the DB/stateful
105
120
  > services; only acted on when isolation is enabled — see Phase A item 9>
121
+ > **Gating:** <flag name — or "none: <one-line reason>". Only when release gating
122
+ > is configured; omit the line entirely otherwise. An empty value or a bare
123
+ > "none" is not a valid outcome — see Phase A item 10>
106
124
 
107
125
  ## Problem
108
126
 
@@ -191,7 +209,7 @@ Keep the `00-overview.md` phase index and the phase files in sync: the index row
191
209
  is the one-line summary + status; the phase file is the detail.
192
210
 
193
211
  The **State log** is the audit trail of folder/status transitions — every
194
- lifecycle skill (`/spec-go`, `/spec-complete`, `/spec-cancel`) appends one row
212
+ lifecycle skill (`/spec-start`, `/spec-complete`, `/spec-cancel`) appends one row
195
213
  when it moves the spec. The **Changelog** is for decisions and course-corrections
196
214
  only — keep the two separate.
197
215
 
@@ -206,13 +224,14 @@ Rules for the spec body:
206
224
  phase index.
207
225
  - **Honour project conventions** when writing tasks — reference the relevant
208
226
  `.claude/rules/*.md` rather than re-explaining them.
209
- - **The `## Impact` table is derived from Phase A items 3 (Affected areas) & 5
210
- (Data/API impact)** a structured place to record what those already surface,
211
- not new grilling. It is the scannable substitute for spelling impact out in
212
- prose: name the surfaces (endpoints, schemas, DB tables, domain objects,
213
- routes, business rules) instead of describing them, keep `Detail` terse, and
214
- let it not paragraphs carry the blast radius. It complements the `Area:`
215
- header (files) by naming behavioural surfaces.
227
+ -
228
+ **The `## Impact` table is derived from Phase A items 3 (Affected areas) & 5 (Data/API impact)**
229
+ a structured place to record what those already surface, not new grilling.
230
+ It is the scannable substitute for spelling impact out in prose: name the
231
+ surfaces (endpoints, schemas, DB tables, domain objects, routes, business
232
+ rules) instead of describing them, keep `Detail` terse, and let it not
233
+ paragraphs carry the blast radius. It complements the `Area:` header
234
+ (files) by naming behavioural surfaces.
216
235
  - **Changelog** is mandatory and lives in the spec. Every later decision or
217
236
  course-correction gets a dated one-line entry. Convert relative dates to
218
237
  absolute.
@@ -223,20 +242,29 @@ Rules for the spec body:
223
242
  After writing, tell the user the path and that it's **`Ready`** in `backlog`
224
243
  (grilling in Phase A resolved the open questions). If you deliberately left open
225
244
  questions unresolved, write `Draft` instead and say what still needs deciding.
226
- Either way, the next step is `/spec-go` to start building.
245
+ Either way, the next step is `/spec-start` to start building.
227
246
 
228
247
  ## Phase D — record the isolation stack (only if configured)
229
248
 
230
249
  **Only when `specs/.core/env.config.json` exists** (per-spec isolation is
231
250
  enabled), make sure the `> **Stack:**` header reflects the Phase A item 9
232
251
  decision — `worktree` (default) or `worktree + docker` when it touches the DB /
233
- stateful services. Nothing to provision now: `/spec-go` gives every in-progress
252
+ stateful services. Nothing to provision now: `/spec-start` gives every in-progress
234
253
  spec its own worktree automatically, and brings up Docker only when the Stack
235
254
  says so. Mention the operator can escalate the Stack later (edit the header, or
236
255
  run `skitterspec spec-env up <name>` to add Docker to an existing worktree). If
237
256
  `env.config.json` is absent, isolation is off — leave the default `worktree` and
238
257
  finish as above.
239
258
 
259
+ ## Phase D2 — record the gating decision (only if configured)
260
+
261
+ **Only when `specs/.core/gating.config.json` exists.** Make sure the
262
+ `> **Gating:**` header carries the Phase A item 10 answer — a flag name, or
263
+ `none: <reason>` using the config's `default` wording if it sets one. Nothing is
264
+ provisioned or enforced by this: the header exists so the decision is
265
+ **on the record and reviewable**, and `skitterspec gating check` reports a spec that has
266
+ none. It never blocks. If the config is absent, do not write the line at all.
267
+
240
268
  ## Phase E — link to a ticketing provider (only if one is installed)
241
269
 
242
270
  **Only when a ticketing provider is installed and configured** (it ships the
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spec-bug
3
- description: Investigate a bug, capture it as a Bug-type spec, and drive it red→green. When per-spec isolation is enabled it provisions a worktree first, so the failing test and fix land on the bug's own branch, never on main. ALWAYS starts by reproducing the bug with a failing test, then writes the spec and works the test to green. Creates specs/in-progress/bug-<name>/00-overview.md. Use when the user reports a bug, says "/spec-bug", "investigate this bug", "this is broken — find and fix it", or pastes an error/stack trace.
3
+ description: Investigate a bug, capture it as a Bug-type spec, and drive it red→green. ALWAYS starts by reproducing the bug with a failing test, then writes the spec and works the test to green on the bug's own branch, never on main. Use when the user reports a bug, says "/spec-bug", "investigate this bug", "this is broken — find and fix it", or pastes an error/stack trace.
4
4
  ---
5
5
 
6
6
  # /spec-bug — investigate a bug, prove it with a failing test, fix it
@@ -37,7 +37,7 @@ place), skip this whole section and fix on the current branch — same as when
37
37
  isolation is off. Warn that the fix will land wherever you currently are (usually
38
38
  `main`); reserve it for a trivial one-liner or an explicit request.
39
39
 
40
- A bug fix changes real source, so — exactly like `/spec-go` — it belongs on the
40
+ A bug fix changes real source, so — exactly like `/spec-start` — it belongs on the
41
41
  bug's **own branch**, never directly on `main`. Provision the worktree **now**,
42
42
  before the failing test, so the test, the fix, and the spec all land together and
43
43
  arrive as one reviewable PR.
@@ -51,24 +51,12 @@ provision from — you'll flesh it out in §4:
51
51
  - Run `skitterspec spec-env up bug-<name>` (the `spec-env` CLI engine). It prints
52
52
  the `git worktree add … -b bug/<name>` command (a branch forked from `main`),
53
53
  the worktree path, the opener, and any `in the worktree, run:` bootstrap steps.
54
- - Run the printed `git worktree add`. **The worktree forks from `main`'s last
55
- commit, so your uncommitted stub doesn't travel with it**move it across so
56
- `main` is left pristine. **Create the destination bucket first:**
57
-
58
- ```
59
- mkdir -p <worktreePath>/specs/in-progress
60
- mv specs/in-progress/bug-<name> <worktreePath>/specs/in-progress/
61
- ```
62
-
63
- The `mkdir -p` is not belt-and-braces. Git does not store empty directories,
64
- so `specs/in-progress/` is **absent** from a fresh worktree whenever that
65
- bucket happens to be empty on `main` — the common case, since it empties every
66
- time the last in-progress spec completes. `mv` into a missing destination
67
- renames your spec folder **to** `specs/in-progress`, silently: the spec's files
68
- end up one level too high, `00-overview.md` sits where the bucket should be,
69
- and every later step still appears to work until something cannot find the
70
- spec. Confirm the result before carrying on — you want
71
- `<worktreePath>/specs/in-progress/bug-<name>/00-overview.md`.
54
+ - Run the printed commands in order. The plan **commits the stub first** — the
55
+ worktree forks from `main`'s last commit, so the stub has to be in it — and
56
+ then adds the worktree. Nothing to move afterwards: the spec is already there.
57
+ The commit is planned, not silent; it appears in the printed plan above the
58
+ `git worktree add`, and `spec-env up` refuses outright if anything *other* than
59
+ this spec is uncommitted.
72
60
  - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
73
61
  none of the repo's gitignored files (`.env`, local overrides). Run the printed
74
62
  `in the worktree, run:` steps (file seeding, then `setup`) in order, before
@@ -111,12 +99,14 @@ because work is already underway. Keep it lean:
111
99
  # Bug: <short title>
112
100
 
113
101
  > **Type:** Bug
114
- > **Name:** bug-<kebab-name> (the spec folder name — the handle you paste into `/spec-go`)
102
+ > **Name:** bug-<kebab-name> (the spec folder name — the handle you paste into `/spec-start`)
115
103
  > **Status:** In Progress — fixing (red test added)
116
104
  > **Author:** <git user.name — who reported/captured it>
117
105
  > **Developer:** <git user.name — you, since you're fixing it now>
118
106
  > **Raised:** <YYYY-MM-DD (today)>
119
107
  > **Area:** <files/modules>
108
+ > **Gating:** <flag name — or "none: <one-line reason>". Only when release gating
109
+ > is configured; omit the line entirely otherwise>
120
110
 
121
111
  ## Symptom
122
112
 
@@ -147,8 +137,10 @@ Service, CLI command, Config key, Skill/rule, Business rule — or whatever fits
147
137
  this project (skitterspec itself is a CLI with no HTTP surface). Keep `Detail`
148
138
  terse — names/signatures, not sentences. List **only** surfaces that actually
149
139
  change; the heading is always present, but if nothing external changes write the
150
- single line below instead of an empty table. A bug fix often changes no external
151
- surface — that's fine, use the one-liner.>
140
+ single line below instead of an empty table.>
141
+
142
+ <A bug fix often changes no external surface — that's fine, use the
143
+ one-liner.>
152
144
 
153
145
  | Surface | Change | Detail |
154
146
  |---------|--------|--------|
@@ -176,6 +168,19 @@ fix narrative and decisions — keep them separate.
176
168
 
177
169
 
178
170
 
171
+ ### Release gating (only when configured)
172
+
173
+ **Only when `specs/.core/gating.config.json` exists.** Before writing the spec,
174
+ ask: should this fix ship behind a feature flag, or land live?
175
+ **Offer, don't impose** — cite the project's own `guidance` path when the config
176
+ names one, and
177
+ record the answer either way, as a flag name or `none: <one-line reason>`.
178
+
179
+ A bug fix ships in the next release exactly like a feature, so it gets the same
180
+ question rather than an assumption. A risky rewrite of a broken path is precisely
181
+ where a kill-switch earns its keep; a one-line null check is precisely where
182
+ `none:` is the honest answer. Skip entirely when the config is absent.
183
+
179
184
  ## 5. Drive to GREEN
180
185
 
181
186
  - Implement the **minimal, root-cause** fix. Match surrounding code; honour all
@@ -186,12 +191,12 @@ fix narrative and decisions — keep them separate.
186
191
 
187
192
  If the root cause is large/uncertain and can't be fixed in one pass: keep the red
188
193
  test, split the fix into phase files (`01-<slug>.md` …) with a phase index in
189
- `00-overview.md`, and leave the spec in `in-progress` for `/spec-go` to continue.
194
+ `00-overview.md`, and leave the spec in `in-progress` for `/spec-next` to continue.
190
195
  Say so explicitly — don't fake green.
191
196
 
192
197
  **Then refresh the mirror (only if a provider is installed).** The Fix tasks are
193
198
  ticked, so the repo is now the truth about this fix — and this skill can take a
194
- bug all the way to green without `/spec-go` ever running. Without a provider this
199
+ bug all the way to green without `/spec-next` ever running. Without a provider this
195
200
  is a no-op.
196
201
 
197
202
 
@@ -78,6 +78,32 @@ directly (the old `/spec-env-down` skill is gone — teardown is folded in here)
78
78
  1. If `.spec-env/connected` names this spec, run `skitterspec spec-env connect
79
79
  main` first to free the canonical ports.
80
80
  2. `skitterspec spec-env dev down <name>` — stop its host dev servers.
81
+ **Standing in the worktree? Leave it before you tear it down.** If this
82
+ session's cwd is inside the spec's own worktree, get out **first**, then run the
83
+ teardown commands. How you leave depends on how you got in:
84
+
85
+ - **`/spec-start` moved this session in** — the normal path in `worktree` mode.
86
+ Call **`ExitWorktree`** with `action: "keep"`. It restores the session to the
87
+ directory it started from *and* clears the caches still pointing at the
88
+ worktree, which a bare `cd` does not: after a `cd` the session stays registered
89
+ against the tree and asks you about it again when it ends.
90
+ - **You opened the terminal yourself** — `cd` to the primary checkout, as always.
91
+ `ExitWorktree` is a no-op outside a session it moved, so trying it costs
92
+ nothing, but the `cd` is what relocates you.
93
+
94
+ **Always `keep`, never `remove`.** `ExitWorktree` refuses to remove a worktree
95
+ entered by path in any case, and the `spec-env down` plan below has to stay the
96
+ single thing that deletes — a second deleter is how the teardown guards get
97
+ bypassed.
98
+
99
+ Not because git refuses — it does not. `git worktree remove` **succeeds** on the
100
+ tree you are standing in, and that is the problem: the directory vanishes under
101
+ the shell, `pwd` keeps reporting the path that no longer exists, and every
102
+ command after it dies with `fatal: Unable to read current working directory`.
103
+ The teardown looks fine and everything following it breaks — the report, the
104
+ prune, any check you meant to run. Relocating first costs nothing and is the
105
+ only ordering that survives.
106
+
81
107
  3. `skitterspec spec-env down <name>` — then execute the printed commands to
82
108
  remove the worktree/stack and free the slot. It respects the teardown guards
83
109
  (won't destroy a dirty/unpushed worktree without `--force`).
@@ -25,7 +25,7 @@ Before marking complete, confirm the work is actually finished:
25
25
  originally-failing test named in the spec now passes — that test is the proof
26
26
  the fix works.
27
27
  - If genuinely incomplete work remains, **stop and tell the user** rather than
28
- forcing completion. Offer to finish it (`/spec-go`) or to complete with the
28
+ forcing completion. Offer to finish it (`/spec-next`) or to complete with the
29
29
  remaining items explicitly listed as deferred.
30
30
  - **Check for pre-existing uncommitted changes — before you touch anything.**
31
31
  Run `git status`. Anything already uncommitted is the *user's* work (a
@@ -34,6 +34,23 @@ Before marking complete, confirm the work is actually finished:
34
34
  is its own, and step 4 commits that.
35
35
 
36
36
 
37
+ ### Release gating (only when configured)
38
+
39
+ **Only when `specs/.core/gating.config.json` exists.** Run
40
+ `skitterspec gating check <spec>` and report what it says. This is the last point
41
+ at which the question can still be answered cheaply, which is exactly why it is
42
+ asked here — a spec that reaches `Complete` with no decision recorded is the gap
43
+ the feature exists to close.
44
+
45
+ **Never refuse to complete over it.** Say plainly that no decision was recorded,
46
+ offer to record one now, and finish either way. The work is done; withholding the
47
+ status flip would punish the wrong thing.
48
+
49
+ **This check is advisory.** It reports; it never refuses, and nothing below is
50
+ conditional on it. A spec written before the project adopted gating has no header
51
+ and is not broken — turning this into a gate would accuse the very specs the
52
+ feature was designed not to disturb.
53
+
37
54
  ## 3. Update the spec
38
55
 
39
56
  - Tick all completed tasks in the phase files; flip every finished phase-file
@@ -63,9 +80,10 @@ git add specs/ && git commit -m "chore(spec): complete <name>"
63
80
  ```
64
81
 
65
82
  Step 2 established the tree was otherwise clean, so this commits exactly the
66
- status flip and the move — nothing of yours rides along. **This is what lets step
67
- 6 land:** `integrate` refuses a dirty worktree, so without committing here the
68
- skill would block on the very edits it just made. Do not `git push`.
83
+ status flip and the move — nothing of yours rides along.
84
+ **This is what lets step 6 land:** `integrate` refuses a dirty worktree, so
85
+ without committing here the skill would block on the very edits it just made.
86
+ Do not `git push`.
69
87
 
70
88
  ## 5. Report
71
89
 
@@ -73,8 +91,11 @@ Confirm the move, the commit, the final test result, and list anything deferred.
73
91
 
74
92
  ## 6. Land the branch (opt-in, only if isolated)
75
93
 
76
- **Only when `specs/.core/env.config.json` exists and the spec is on a worktree**
77
- (it was provisioned by `/spec-go` or `/spec-hotfix`). Otherwise skip this entirely
94
+ **Only when `specs/.core/env.config.json` exists and the spec was provisioned**
95
+ (a worktree in `worktree` mode, or its branch in the checkout in `checkout`
96
+ mode — `spec-env integrate` and `down` pick the right plan from `mode`, so the
97
+ commands you run differ but these steps do not)
98
+ (it was provisioned by `/spec-start` or `/spec-hotfix`). Otherwise skip this entirely
78
99
  — a non-isolated spec has nothing to land, and `/spec-complete` behaves exactly as
79
100
  before. When it applies, offer to land the finished branch so the work reaches its
80
101
  destination in one flow. **How it lands depends on the spec type:**
@@ -125,7 +146,7 @@ is finished — e.g. to run a later phase in CI or a shared test env? Use
125
146
  work is actually landable and **aborts loudly** rather than finalize a spec
126
147
  having landed nothing. Two cases, both leaving the live session intact:
127
148
  - *stranded commits* — commits sit on the worktree's **detached HEAD** (e.g. a
128
- pre-fix `/spec-go` committed there instead of on the branch). It prints the
149
+ pre-fix `/spec-next` committed there instead of on the branch). It prints the
129
150
  count, the sha, and a `git -C <worktree> branch <tmp> <sha>` recovery hint —
130
151
  recover those commits onto the branch, then re-run.
131
152
  - *no worktree* — the spec is live but its worktree is gone. Re-isolate it with
@@ -168,6 +189,32 @@ worktree and branch are being kept, and go straight to sub-step 4. Mention
168
189
  canonical ports go back to the primary checkout.
169
190
  2. **Stop its host dev servers:** `skitterspec spec-env dev down <name>` (a
170
191
  no-op when none are running / configured).
192
+ **Standing in the worktree? Leave it before you tear it down.** If this
193
+ session's cwd is inside the spec's own worktree, get out **first**, then run the
194
+ teardown commands. How you leave depends on how you got in:
195
+
196
+ - **`/spec-start` moved this session in** — the normal path in `worktree` mode.
197
+ Call **`ExitWorktree`** with `action: "keep"`. It restores the session to the
198
+ directory it started from *and* clears the caches still pointing at the
199
+ worktree, which a bare `cd` does not: after a `cd` the session stays registered
200
+ against the tree and asks you about it again when it ends.
201
+ - **You opened the terminal yourself** — `cd` to the primary checkout, as always.
202
+ `ExitWorktree` is a no-op outside a session it moved, so trying it costs
203
+ nothing, but the `cd` is what relocates you.
204
+
205
+ **Always `keep`, never `remove`.** `ExitWorktree` refuses to remove a worktree
206
+ entered by path in any case, and the `spec-env down` plan below has to stay the
207
+ single thing that deletes — a second deleter is how the teardown guards get
208
+ bypassed.
209
+
210
+ Not because git refuses — it does not. `git worktree remove` **succeeds** on the
211
+ tree you are standing in, and that is the problem: the directory vanishes under
212
+ the shell, `pwd` keeps reporting the path that no longer exists, and every
213
+ command after it dies with `fatal: Unable to read current working directory`.
214
+ The teardown looks fine and everything following it breaks — the report, the
215
+ prune, any check you meant to run. Relocating first costs nothing and is the
216
+ only ordering that survives.
217
+
171
218
  3. **Remove worktree + stack + slot:** run `skitterspec spec-env down <name>`
172
219
  and execute the commands it prints, in order. After a landing — merged into
173
220
  base for a **feature/bug**, captured by the deploy tag for a **hotfix** —
@@ -177,16 +224,16 @@ worktree and branch are being kept, and go straight to sub-step 4. Mention
177
224
  worktree without `--force`), so if it *does* refuse, relay that and stop
178
225
  rather than reaching for `--force`.
179
226
 
180
- **If the plan prints a `remote branch — confirm with the user first:`
181
- section, ask before running it.** `/spec-go` pushed this branch when it
182
- provisioned, so the remote copy outlives teardown unless someone deletes it.
183
- The planner only ever offers this for a branch that has **landed**, so say so
184
- plainly when you ask — the commits are on the base branch (or captured by the
185
- deploy tag), so deleting the remote branch loses nothing. On a yes, run the
186
- printed `git push <remote> --delete <branch>`; on a no, leave it and say the
187
- remote branch is still there. Never fold it into the `run these:` batch — a
188
- project that wants it unattended sets `teardown.deleteRemoteBranch: "always"`
189
- in `env.config.json`, and then it appears in `run these:` instead of here.
227
+ **If the plan prints a `remote branch — confirm with the user first:` section, ask before running it.**
228
+ `/spec-start` pushed this branch when it provisioned, so the remote copy
229
+ outlives teardown unless someone deletes it. The planner only ever offers
230
+ this for a branch that has **landed**, so say so plainly when you ask — the
231
+ commits are on the base branch (or captured by the deploy tag), so deleting
232
+ the remote branch loses nothing. On a yes, run the printed
233
+ `git push <remote> --delete <branch>`; on a no, leave it and say the remote
234
+ branch is still there. Never fold it into the `run these:` batch — a project
235
+ that wants it unattended sets `teardown.deleteRemoteBranch: "always"` in
236
+ `env.config.json`, and then it appears in `run these:` instead of here.
190
237
  4. **Reap orphaned test-DB volumes:** run `skitterspec spec-env prune`. It lists
191
238
  Docker volumes in the repo namespace that belong to **no live spec** (no
192
239
  worktree) — leftovers from declined/aborted teardowns, manual
@@ -198,6 +245,12 @@ worktree and branch are being kept, and go straight to sub-step 4. Mention
198
245
  finish completing anyway — never block the spec on it. Skip when Docker isn't
199
246
  in use (the command self-reports "no orphaned volumes").
200
247
 
248
+ **Report from where you now are.** After a teardown you relocated for, the
249
+ worktree path in the report is a directory that no longer exists and the landed
250
+ work is on the base branch in the primary checkout — say both, so nobody goes
251
+ looking for a tree that is gone. A session that was a worktree tab has finished
252
+ its job at that point; its shell is the operator's own to close.
253
+
201
254
  **Say what you reclaimed.** With no confirmation step the user never saw this
202
255
  coming, so the final report must name the worktree path removed and the branch
203
256
  deleted (or, under `--keep-env`, that both were kept). A teardown nobody
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spec-hotfix
3
- description: Fix a production bug on the exact released version — fork a worktree from a release tag, drive it red→green like /spec-bug, then land it by tagging a new patch (for CI/CD to deploy) and cherry-picking the fix back onto main. ALWAYS starts from a base tag and works on the hotfix's own branch, never on main. Can start from a tracker issue when a provider is installed (`/spec-hotfix <tag> <ISSUE-REF>`), adopting it as the hotfix's issue. Creates specs/in-progress/hotfix-<name>/00-overview.md. Use when the user says "/spec-hotfix", "hotfix <tag>", "prod is broken on <version>", "patch the released version", or needs a fix shipped against a tagged release rather than main.
3
+ description: Fix a production bug on the exact released version — fork a worktree from a release tag, drive it red→green, then land it by tagging a new patch for CI/CD and cherry-picking the fix onto main. ALWAYS starts from a base tag and works on the hotfix's own branch, never on main. Use when the user says "/spec-hotfix", "hotfix <tag>", "prod is broken on <version>", "patch the released version", or needs a fix shipped against a tagged release rather than main.
4
4
  ---
5
5
 
6
6
  # /spec-hotfix — fix a released version, tag it, cherry-pick back to main
@@ -63,9 +63,12 @@ that header — must exist **before** `spec-env up`:
63
63
  -b hotfix/<slug> <tag>` command (the branch forks from **the tag**, not
64
64
  `main`), the worktree path, the opener, and any `in the worktree, run:`
65
65
  bootstrap steps.
66
- - Run the printed `git worktree add`. **The worktree is checked out at the tag,
67
- so your uncommitted stub doesn't travel with it** move it across so `main`
68
- stays pristine. **Create the destination bucket first:**
66
+ - Run the printed `git worktree add`, then **move the stub across yourself.**
67
+ This is where a hotfix differs from `/spec-bug`, which no longer needs the move:
68
+ that skill's worktree forks from `main`, so committing the stub puts it there,
69
+ while **this worktree is checked out at the tag** — a commit on `main` is not in
70
+ it and never will be. The move is not redundant here; keep it.
71
+ **Create the destination bucket first:**
69
72
 
70
73
  ```
71
74
  mkdir -p <worktreePath>/specs/in-progress
@@ -74,16 +77,15 @@ that header — must exist **before** `spec-env up`:
74
77
 
75
78
  The `mkdir -p` is not belt-and-braces. Git does not store empty directories, so
76
79
  `specs/in-progress/` is **absent** from the worktree whenever nothing was in
77
- progress at that point in history — and here that point is an **old release
78
- tag**, where it is absent more often than not. `mv` into a missing destination
79
- renames your spec folder **to** `specs/in-progress`, silently: the spec's files
80
- end up one level too high, `00-overview.md` sits where the bucket should be, and
81
- every later step still appears to work until something cannot find the spec.
82
- Confirm the result before carrying on — you want
83
- `<worktreePath>/specs/in-progress/hotfix-<name>/00-overview.md`.
84
- - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
80
+ progress at that point in history — and here that point is an
81
+ **old release tag**, where it is absent more often than not. `mv` into a
82
+ missing destination renames your spec folder **to** `specs/in-progress`,
83
+ silently: the spec's files end up one level too high, `00-overview.md` sits
84
+ where the bucket should be, and every later step still appears to work until
85
+ something cannot find the spec. Confirm the result before carrying on — you
86
+ want `<worktreePath>/specs/in-progress/hotfix-<name>/00-overview.md`. - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
85
87
  none of the repo's gitignored files (`.env`, local overrides). Run the printed
86
- `in the worktree, run:` steps (file seeding, then setup) in order, before
88
+ `in the worktree, run:` steps (file seeding, then `setup`) in order, before
87
89
  anything else.
88
90
  - **Trust the worktree for this session.** The engine wrote the printed
89
91
  `trusted:` root into `.claude/settings.local.json`, but it won't hot-reload now
@@ -116,13 +118,15 @@ is usually a single-pass fix, so the `## Fix` block can live directly in
116
118
  # Hotfix: <short title>
117
119
 
118
120
  > **Type:** Hotfix
119
- > **Name:** hotfix-<kebab-name> (the spec folder name — the handle you paste into `/spec-go`)
121
+ > **Name:** hotfix-<kebab-name> (the spec folder name — the handle you paste into `/spec-start`)
120
122
  > **Status:** In Progress — fixing (red test added)
121
123
  > **Author:** <git user.name — who reported/captured it>
122
124
  > **Developer:** <git user.name — you, since you're fixing it now>
123
125
  > **Base version:** <tag prod is running, e.g. v33.16.4>
124
126
  > **Raised:** <YYYY-MM-DD (today)>
125
127
  > **Area:** <files/modules>
128
+ > **Gating:** <pre-filled "none: hotfix — restoring released behaviour"; only
129
+ > when release gating is configured, and overridable — see below>
126
130
 
127
131
  ## Symptom
128
132
 
@@ -153,8 +157,10 @@ Service, CLI command, Config key, Skill/rule, Business rule — or whatever fits
153
157
  this project (skitterspec itself is a CLI with no HTTP surface). Keep `Detail`
154
158
  terse — names/signatures, not sentences. List **only** surfaces that actually
155
159
  change; the heading is always present, but if nothing external changes write the
156
- single line below instead of an empty table. A hotfix should be minimal — often
157
- no external surface changes; that's fine, use the one-liner.>
160
+ single line below instead of an empty table.>
161
+
162
+ <A hotfix should be minimal — often no external surface changes; that's
163
+ fine, use the one-liner.>
158
164
 
159
165
  | Surface | Change | Detail |
160
166
  |---------|--------|--------|
@@ -187,6 +193,21 @@ narrative and decisions).
187
193
 
188
194
 
189
195
 
196
+ ### Release gating (only when configured)
197
+
198
+ **Only when `specs/.core/gating.config.json` exists.** A hotfix is the one spec
199
+ type that does **not** ask the question cold: it writes
200
+ `none: hotfix — restoring released behaviour` and asks only for confirmation.
201
+
202
+ The default differs on purpose. A hotfix restores behaviour a release already
203
+ had, under time pressure, and the fix is captured by a deploy tag rather than
204
+ riding the next release — so a flag has nothing to gate and nothing to roll back
205
+ to. Making someone answer a design question mid-incident buys nothing.
206
+
207
+ It is a **default, not a rule**: say what you are writing and let the user
208
+ override it. If they name a flag, record that instead. Skip entirely when the
209
+ config is absent.
210
+
190
211
  ## 6. Drive to GREEN
191
212
 
192
213
  - Implement the **minimal, root-cause** fix on the branch. Match surrounding code;
@@ -198,7 +219,7 @@ narrative and decisions).
198
219
 
199
220
  **Then refresh the mirror (only if a provider is installed).** The Fix tasks are
200
221
  ticked, so the repo is now the truth about this fix — and this skill can take a
201
- bug all the way to green without `/spec-go` ever running. Without a provider this
222
+ bug all the way to green without `/spec-next` ever running. Without a provider this
202
223
  is a no-op.
203
224
 
204
225
 
@@ -22,10 +22,33 @@ clobber customised content. Finish with a summary of created vs already-present.
22
22
  > **Leave alone**. Non-interactively it only adds what's missing; `--resync` /
23
23
  > `--reset` (reset needs `--yes`) drive the stronger actions.
24
24
 
25
- The system is **eight skills**: `spec` (feature), `spec-bug` (bug), `spec-ready`,
26
- `spec-review`, `spec-go`, `spec-complete`, `spec-cancel`, and this `spec-init`. The lifecycle is
27
- `backlog in-progress → complete / cancelled`, with `.core` holding always-apply
28
- project rules.
25
+ The system is **ten skills**: `spec` (feature), `spec-bug` (bug),
26
+ `spec-hotfix` (a bug fixed on a released tag), `spec-review`, `spec-start`,
27
+ `spec-next`, `spec-to-main`, `spec-complete`, `spec-cancel`, and this
28
+ `spec-init`. The lifecycle is `backlog → in-progress → complete / cancelled`,
29
+ with `.core` holding always-apply project rules.
30
+
31
+ ## 0. Workspace mode (only when adopting isolation)
32
+
33
+ If this project is adopting per-spec isolation, ask which `mode` belongs in
34
+ `specs/.core/env.config.json` — `worktree` (default; a checkout per spec, several
35
+ at once, one terminal session each) or `checkout` (the branch is built in the
36
+ checkout you are already in; one spec at a time, no hand-off). It is a question
37
+ about how the operator works, not about what the repo contains, so ask rather
38
+ than infer it from whether dev servers or Docker are configured.
39
+
40
+ ## 0b. Release gating (optional, and separate)
41
+
42
+ Ask whether specs should record a **release-gating** decision — does this change
43
+ ship behind a feature flag, or land live? Adopting it copies
44
+ `specs/.core/gating.config.json.example` → `gating.config.json` and sets
45
+ `guidance` to wherever this project documents its flags.
46
+
47
+ It is **orthogonal to isolation**: a project can adopt either, both, or neither.
48
+ Skitterspec never learns how the flags work — it asks the question, cites that
49
+ path, and records the answer on each spec. Leave it off and nothing appears:
50
+ no question, no header, no check. Off is a perfectly good answer for a project
51
+ that does not use flags.
29
52
 
30
53
  ## 1. Folders
31
54
 
@@ -54,7 +77,7 @@ project wants everything tracked, remove it. Confirm with
54
77
 
55
78
  ## 3. Verify the skills are installed
56
79
 
57
- Check each of the eight skills resolves — `.claude/skills/<name>/SKILL.md`
80
+ Check each of the ten skills resolves — `.claude/skills/<name>/SKILL.md`
58
81
  (project) or `~/.claude/skills/<name>/` (global). List any missing. This skill
59
82
  scaffolds the project; it does **not** regenerate skill bodies — missing skills
60
83
  must be copied in (e.g. `npx @skitterbyte/skitterspec init`) from a global install
@@ -70,10 +93,10 @@ Ensure it exists. If missing, create it documenting:
70
93
  - the **Author** / **Developer** header fields;
71
94
  - the **State log** audit table (folder/status transitions), kept separate from
72
95
  the **Changelog** (decisions);
73
- - the project's concrete typecheck/test commands, and the rule that **every
74
- phase ends with creating + running tests**.
96
+ - the project's concrete typecheck/test commands, and the rule that
97
+ **every phase ends with creating + running tests**.
75
98
 
76
- Read a sibling spec skill (e.g. `spec`, `spec-go`) for the canonical shapes
99
+ Read a sibling spec skill (e.g. `spec`, `spec-next`) for the canonical shapes
77
100
  rather than inventing them. If the rule already exists, leave it unless stale.
78
101
 
79
102
  ## 5. CLAUDE.md