@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.
- package/MIGRATION.md +88 -0
- package/README.md +3 -3
- package/assets/claude-md-section.md +20 -48
- package/assets/core/env.config.json.example +7 -1
- package/assets/core/env.config.md +56 -11
- package/assets/core/gating.config.json.example +4 -0
- package/assets/core/gating.config.md +81 -0
- package/assets/rules/spec-planning.md +53 -13
- package/assets/skills/spec/SKILL.md +44 -16
- package/assets/skills/spec-bug/SKILL.md +30 -25
- package/assets/skills/spec-cancel/SKILL.md +26 -0
- package/assets/skills/spec-complete/SKILL.md +70 -17
- package/assets/skills/spec-hotfix/SKILL.md +38 -17
- package/assets/skills/spec-init/SKILL.md +31 -8
- package/assets/skills/spec-next/SKILL.md +98 -0
- package/assets/skills/spec-review/SKILL.md +24 -11
- package/assets/skills/spec-start/SKILL.md +226 -0
- package/assets/skills/spec-to-main/SKILL.md +21 -19
- package/package.json +1 -1
- package/src/cli.js +405 -15
- package/src/env/classify.js +91 -0
- package/src/env/config.js +39 -1
- package/src/env/integrate.js +61 -1
- package/src/env/live.js +27 -3
- package/src/env/provision.js +196 -5
- package/src/env/resolve.js +1 -0
- package/src/env/teardown.js +41 -3
- package/src/gating.js +155 -0
- package/src/init.js +45 -9
- package/src/prompts.js +41 -4
- package/assets/skills/spec-go/SKILL.md +0 -190
|
@@ -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-
|
|
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-
|
|
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
|
-
-
|
|
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-
|
|
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. **
|
|
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-
|
|
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-
|
|
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
|
-
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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-
|
|
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-
|
|
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.
|
|
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-
|
|
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
|
|
55
|
-
commit, so
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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-
|
|
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
|
|
151
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
67
|
-
6 land:** `integrate` refuses a dirty worktree, so
|
|
68
|
-
skill would block on the very edits it just made.
|
|
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
|
|
77
|
-
(
|
|
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-
|
|
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
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
78
|
-
tag**, where it is absent more often than not. `mv` into a
|
|
79
|
-
renames your spec folder **to** `specs/in-progress`,
|
|
80
|
-
end up one level too high, `00-overview.md` sits
|
|
81
|
-
every later step still appears to work until
|
|
82
|
-
Confirm the result before carrying on — you
|
|
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-
|
|
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
|
|
157
|
-
|
|
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-
|
|
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 **
|
|
26
|
-
`spec-
|
|
27
|
-
`
|
|
28
|
-
|
|
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
|
|
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
|
|
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-
|
|
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
|