@skitterbyte/skitterspec 11.0.0 → 13.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/README.md CHANGED
@@ -9,10 +9,10 @@ Spec-driven development for [Claude Code](https://claude.com/claude-code) — a
9
9
  ```
10
10
 
11
11
  Ships the spec-lifecycle skills (`/spec`, `/spec-go`, `/spec-complete`,
12
- `/spec-cancel`, `/spec-bug`, `/spec-review`, `/spec-init`) plus per-spec
13
- **isolation** — a git worktree per in-progress spec, Docker on demand, host dev
14
- servers on reserved ports, and `/spec-connect` to test a worktree at your normal
15
- `localhost` URL.
12
+ `/spec-cancel`, `/spec-bug`, `/spec-hotfix`, `/spec-review`, `/spec-init`) plus
13
+ per-spec **isolation** — a git worktree per in-progress spec, Docker on demand,
14
+ host dev servers on reserved ports, and `/spec-connect` to test a worktree at your
15
+ normal `localhost` URL.
16
16
 
17
17
  ```sh
18
18
  npx @skitterbyte/skitterspec init
@@ -44,6 +44,17 @@ no external install), so you test at the exact URL you always use.
44
44
  `/spec-connect main` hands the ports back. Exclusive: one spec at a time. See
45
45
  `specs/.core/env.config.md` for the `dev`/`proxy` config.
46
46
 
47
+ ## Production hotfixes — `/spec-hotfix`
48
+
49
+ When prod is on a tagged release, a fix must be built on **that** version, not
50
+ `main`. `/spec-hotfix <tag> <name>` forks a worktree from the tag, then works
51
+ test-first like `/spec-bug`. `/spec-complete` lands it by patch-bumping the tag
52
+ and tagging the branch (your CI/CD deploys the tag — you push it) and
53
+ cherry-picking the fix onto `main`; `--also <tag>` patches extra release lines
54
+ (test/demo). Hotfixes refuse `/spec-live` (their old-tag branch could break the
55
+ running instance) — test them with `/spec-connect`. Tune the `hotfix` block in
56
+ `specs/.core/env.config.md`.
57
+
47
58
  ## v3 — slimmer surface + `/spec-connect`
48
59
 
49
60
  **3.0** folds provisioning into `/spec-go`, teardown into
@@ -34,5 +34,8 @@
34
34
  "guards": {
35
35
  "refuseTeardownIfDirty": true,
36
36
  "refuseTeardownIfUnpushed": true
37
+ },
38
+ "live": {
39
+ "migrations": []
37
40
  }
38
41
  }
@@ -4,8 +4,8 @@ Opt-in config for per-spec isolation (git worktree + optional namespaced Docker
4
4
  stack + host dev servers + a front-door proxy + an optional opener per
5
5
  in-progress spec). Provisioning is folded into `/spec-go`, teardown into
6
6
  `/spec-complete` · `/spec-cancel`, and traffic diversion is `/spec-connect`; the
7
- `skitterspec spec-env <up|down|dev|connect|integrate>` CLI is the engine beneath
8
- them.
7
+ `skitterspec spec-env <up|down|prune|dev|connect|integrate>` CLI is the engine
8
+ beneath them.
9
9
 
10
10
  **Once this file is present, isolation is the default policy:** `/spec-go` gives
11
11
  **every** in-progress spec its own git worktree automatically. Docker is a **per-
@@ -146,6 +146,29 @@ no live `env.config.json` was found.
146
146
  "guards": {
147
147
  "refuseTeardownIfDirty": true,
148
148
  "refuseTeardownIfUnpushed": true
149
+ },
150
+
151
+ // Live overlay (`spec-env live` / `/spec-live`): test a spec on the already-
152
+ // running dev server by checking its branch out in the primary checkout.
153
+ // `migrations` is a list of globs (`**`, `*`, `?`) marking migration files; a
154
+ // branch that changes any of them is treated as STATEFUL and `live take`
155
+ // refuses it (code-only v1 — use `/spec-connect` for those). Default: none.
156
+ "live": {
157
+ "migrations": []
158
+ },
159
+
160
+ // Hotfix landing (`spec-env hotfix land` / `/spec-complete` on a Type: Hotfix
161
+ // spec). A hotfix forks from a release tag and lands by tag + cherry-pick, not
162
+ // fast-forward. `bump` is the version-bump strategy for the new deploy tag (only
163
+ // "patch" today: v33.16.4 -> v33.16.5). `cherryPickMain` also cherry-picks the
164
+ // fix onto the base branch for the next release (default true). `targets` is an
165
+ // optional default list of extra base tags to also patch (test/demo lines);
166
+ // `--also <tag>` adds more at run time. Nothing is ever pushed — you push the
167
+ // deploy tag to trigger CI/CD. Default: patch, main, none.
168
+ "hotfix": {
169
+ "bump": "patch",
170
+ "cherryPickMain": true,
171
+ "targets": []
149
172
  }
150
173
  }
151
174
  ```
@@ -156,3 +179,26 @@ no live `env.config.json` was found.
156
179
  - `{repoSlug}` — `{repo}` lower-cased, non-alphanumerics collapsed to `-`
157
180
  (safe for a `COMPOSE_PROJECT_NAME`).
158
181
  - `{slug}` — the spec slug (folder name minus its `feat-`/`bug-` prefix).
182
+
183
+ ## Pruning orphaned test-DB volumes
184
+
185
+ `spec-env down` drops the finished spec's own Docker volume, but volumes leak
186
+ when that path is skipped — a declined/guard-aborted teardown, a manual
187
+ `git worktree remove`, or `--keep-volumes`. Over many worktrees these orphaned
188
+ DB volumes pile up and eat disk.
189
+
190
+ `skitterspec spec-env prune` reconciles the live volumes in the
191
+ `{repoSlug}_*` namespace against the specs that still have a **worktree** and
192
+ lists the orphans (volumes owned by no live spec) plus the `docker volume rm`
193
+ commands to remove them. It plans only — you run the printed commands — and it
194
+ frees any stale registry slot for a reaped spec.
195
+
196
+ - **Liveness = an existing worktree, not the registry** (the registry is what
197
+ goes stale). A spec with a live worktree — in any bucket, including one checked
198
+ out only on its branch — is always protected.
199
+ - **No backup.** Unlike `spec-env down`, prune does **not** run
200
+ `backupCommand`: an orphan has no running DB to dump. Add `--older-than <days>`
201
+ to only reap volumes older than a cutoff (volumes of unknown age are kept).
202
+ - `/spec-complete` and `/spec-cancel` run prune (confirm-first) as their last
203
+ teardown step, so orphans get swept as specs finish. You can also run it by
204
+ hand at any time to clear an existing backlog.
@@ -1,6 +1,6 @@
1
1
  # Spec Planning
2
2
 
3
- Spec-driven development is driven by seven lifecycle skills (plus `/spec-connect`
3
+ Spec-driven development is driven by nine lifecycle skills (plus `/spec-connect`
4
4
  when isolation is on) — use them rather than hand-rolling specs so the structure
5
5
  and lifecycle stay consistent. Each sets a status on the spec header
6
6
  (`> **Status:** …`):
@@ -9,8 +9,10 @@ and lifecycle stay consistent. Each sets a status on the spec header
9
9
  |-------|---------|--------|--------|
10
10
  | `/spec` | (Feature) Grill to a clear shared understanding, then write a groomed spec | `Ready` (or `Draft`) | `specs/backlog/` |
11
11
  | `/spec-bug` | (Bug) Reproduce with a failing test, capture spec, drive red→green | `In Progress` | `specs/in-progress/` |
12
+ | `/spec-hotfix` | (Hotfix) Fork a worktree from a release tag, red→green, land by tag + cherry-pick | `In Progress` | `specs/in-progress/` |
12
13
  | `/spec-review` | Re-validate a spec against the codebase; refresh stale parts | `—` | (unchanged) |
13
14
  | `/spec-go` | Provision the env, bring dev servers up, implement the next phase | `In Progress` | `specs/in-progress/` |
15
+ | `/spec-to-main` | Land the branch on the base (rebase + ff) **without** finishing — for running the work in CI / a shared env mid-spec; repeatable | `In Progress` (unchanged) | (unchanged) |
14
16
  | `/spec-complete` | Verify all phases done + tests green; land + tear down | `Complete` | `specs/complete/` |
15
17
  | `/spec-cancel` | Record progress, stamp a reason on the header; tear down | `Cancelled` | `specs/cancelled/` |
16
18
  | `/spec-init` | Bootstrap/repair this workflow in a project (idempotent) | — | — |
@@ -18,8 +20,12 @@ and lifecycle stay consistent. Each sets a status on the spec header
18
20
  Status flow: `Ready → In Progress → Complete` (or `Cancelled` from any state).
19
21
  `/spec` grills to a **Ready** spec directly — there is no separate grooming
20
22
  command; it writes `Draft` only when open questions are deliberately left.
21
- `/spec-bug` is test-first and starts straight in `In Progress` (work begins
22
- immediately), so it skips Draft/Ready.
23
+ `/spec-bug` and `/spec-hotfix` are test-first and start straight in `In Progress`
24
+ (work begins immediately), so they skip Draft/Ready. `/spec-to-main` does **not**
25
+ move the spec through the flow at all — it lands the branch on the base branch
26
+ mid-spec (so the work can run in CI / a shared test env) while the spec stays
27
+ `In Progress` in `specs/in-progress/`; it's the intermediate, repeatable half of
28
+ `/spec-complete`'s landing, without the finalise-and-tear-down.
23
29
 
24
30
  **Per-spec isolation (opt-in to adopt, then the default policy).** When a project
25
31
  adopts isolation (`skitterspec init --isolation`, or `specs/.core/env.config.json`
@@ -35,9 +41,28 @@ your canonical `localhost` ports so you can test it at the normal URL
35
41
  move, header edits, the code) happens on the spec's branch in the worktree; `main`
36
42
  changes only when it merges. Teardown is folded into `/spec-complete` ·
37
43
  `/spec-cancel`. Beneath the skills, `skitterspec spec-env
38
- <up|down|dev|connect|integrate>` is the CLI engine. Isolation is **orthogonal to
39
- lifecycle status** and inactive when `env.config.json` is absent — every skill
40
- then behaves as it does today.
44
+ <up|down|prune|dev|connect|integrate|hotfix>` is the CLI engine. Teardown drops
45
+ the finished spec's own test-DB volume; `spec-env prune` additionally reaps
46
+ **orphaned** volumes left by declined/aborted teardowns, so `/spec-complete` and
47
+ `/spec-cancel` also sweep orphans (confirm-first). A **hotfix** is the one
48
+ exception to "fork from `main`": `/spec-hotfix` forks the worktree from a release
49
+ tag and `/spec-complete` lands it via `spec-env hotfix land` (tag + cherry-pick),
50
+ not a fast-forward. Isolation is **orthogonal to lifecycle status** and inactive
51
+ when `env.config.json` is absent — every skill then behaves as it does today.
52
+
53
+ **Live overlay (`/spec-live`) — the light way to test a spec.** `/spec-connect`
54
+ runs a spec's *own* dev stack and proxies the canonical ports to it (one stack per
55
+ spec). **Live overlay** instead reuses the one dev server you already have running:
56
+ `/spec-live <spec>` rebases the branch onto base, frees it from its worktree, and
57
+ checks it out **in the primary checkout**, so your running server hot-reloads the
58
+ feature at the normal URL — no second stack, no proxy. The branch checked out in
59
+ the primary checkout **is** the lock: exactly one spec is live at a time, and
60
+ `/spec-live main` hands the instance back (fixes you make while live commit
61
+ straight onto the branch; `/spec-complete` is live-aware and lands them). Rule of
62
+ thumb: **live overlay is the light default for code-only specs**; it *refuses*
63
+ stateful ones (`Stack: worktree + docker`, or a branch touching migrations) — keep
64
+ `/spec-connect` + a Docker stack for those, and for genuinely parallel testing.
65
+ Beneath it, `skitterspec spec-env live <take|release|abort|status>` is the engine.
41
66
 
42
67
  **Ticketing-provider sync (opt-in, a separate package).** The base is
43
68
  tracker-free: it knows nothing about any specific ticketing system. A
@@ -63,16 +88,24 @@ consistent with the codebase:
63
88
  - **Other rules specs must honour:** link the relevant `.claude/rules/*.md`
64
89
  (architecture, code style, testing, database, etc.) rather than restating them.
65
90
 
66
- ## Spec types — Feature vs Bug
91
+ ## Spec types — Feature, Bug, Hotfix
67
92
 
68
- Every spec is one of two types, recorded **both** in the header and the filename:
93
+ Every spec is one of three types, recorded **both** in the header and the filename:
69
94
 
70
- - **Header field:** `> **Type:** Feature` or `> **Type:** Bug` (authoritative,
71
- greppable: `grep -rl 'Type:.*Bug' specs/`).
72
- - **Filename prefix:** `feat-<name>` for features, `bug-<name>` for bugs
73
- (visible in listings; glob-safe never use `[BUG]`/`[FEATURE]` brackets).
95
+ - **Header field:** `> **Type:** Feature`, `> **Type:** Bug`, or
96
+ `> **Type:** Hotfix` (authoritative, greppable:
97
+ `grep -rl 'Type:.*Hotfix' specs/`).
98
+ - **Filename prefix:** `feat-<name>` for features, `bug-<name>` for bugs,
99
+ `hotfix-<name>` for hotfixes (visible in listings; glob-safe — never use
100
+ `[BUG]`/`[FEATURE]` brackets).
74
101
 
75
- Both types share the same lifecycle folders below type is orthogonal to status.
102
+ A **Hotfix** is a Bug fixed against a **released tag** rather than `main`: it
103
+ carries an extra `> **Base version:** <tag>` header, forks its worktree from that
104
+ tag, and lands by tagging a new patch + cherry-picking onto `main` (never a
105
+ fast-forward merge). `/spec-live` refuses a hotfix — test it with `/spec-connect`.
106
+
107
+ All three types share the same lifecycle folders below — type is orthogonal to
108
+ status.
76
109
 
77
110
  ## Header fields & State log (audit trail)
78
111
 
@@ -64,5 +64,10 @@ directly (the old `/spec-env-down` skill is gone — teardown is folded in here)
64
64
  3. `skitterspec spec-env down <name>` — then execute the printed commands to
65
65
  remove the worktree/stack and free the slot. It respects the teardown guards
66
66
  (won't destroy a dirty/unpushed worktree without `--force`).
67
+ 4. `skitterspec spec-env prune` — reap orphaned test-DB volumes that belong to no
68
+ live spec (leftovers from declined/aborted teardowns or manual worktree
69
+ removal). Show the orphan list and, **only on the user's confirmation**, run
70
+ the printed `docker volume rm` commands. Non-fatal: if it can't run or the user
71
+ declines, report and finish cancelling anyway.
67
72
 
68
73
  If `env.config.json` is absent, skip this entirely — behave exactly as before.
@@ -21,8 +21,9 @@ Before marking complete, confirm the work is actually finished:
21
21
  done in the code — tick it (`- [x]`) if so, or surface it if not.
22
22
  - Run the project's typecheck and test commands. The suite must be **green** to
23
23
  call a spec complete.
24
- - For a **Bug** spec (`Type: Bug`), confirm the originally-failing test named in
25
- the spec now passes — that test is the proof the bug is fixed.
24
+ - For a **Bug** or **Hotfix** spec (`Type: Bug` / `Type: Hotfix`), confirm the
25
+ originally-failing test named in the spec now passes — that test is the proof
26
+ the fix works.
26
27
  - If genuinely incomplete work remains, **stop and tell the user** rather than
27
28
  forcing completion. Offer to finish it (`/spec-go`) or to complete with the
28
29
  remaining items explicitly listed as deferred.
@@ -51,17 +52,55 @@ specs — `git log`/the per-spec State log give the completion order.
51
52
  Confirm the move, the final test result, and list anything deferred. Do **not**
52
53
  `git commit` unless the user asks.
53
54
 
54
- ## 6. Integrate onto the base branch (opt-in, only if isolated)
55
+ ## 6. Land the branch (opt-in, only if isolated)
55
56
 
56
57
  **Only when `specs/.core/env.config.json` exists and the spec is on a worktree**
57
- (it was provisioned by `/spec-go`). Otherwise skip this entirely — a non-isolated
58
- spec has nothing to land, and `/spec-complete` behaves exactly as before. When it
59
- applies, offer to land the finished branch on the base branch so the work reaches
60
- `main` (or your configured `baseBranch`) in one flow:
58
+ (it was provisioned by `/spec-go` or `/spec-hotfix`). Otherwise skip this entirely
59
+ — a non-isolated spec has nothing to land, and `/spec-complete` behaves exactly as
60
+ before. When it applies, offer to land the finished branch so the work reaches its
61
+ destination in one flow. **How it lands depends on the spec type:**
62
+
63
+ ### 6-hotfix. `Type: Hotfix` — tag + cherry-pick (not fast-forward)
64
+
65
+ A hotfix is built on an old release **tag**, so it can't fast-forward onto `main`.
66
+ Use the hotfix landing instead of the integrate steps below:
67
+
68
+ 1. **Require a clean worktree** — the completion edits (status flip, `git mv` to
69
+ `complete/`) must be committed first. If dirty, offer `/commit` and **stop**.
70
+ 2. **Plan + execute.** Run `skitterspec spec-env hotfix land <name>` — add
71
+ `--also <tag>` for each extra release line to patch (test/demo on their own
72
+ versions). Run the printed commands **in order**. It:
73
+ - tags the hotfix branch with the **patch-bumped base tag** (the deploy tag) —
74
+ **created locally; you push it** (`git push origin <tag>`) to trigger CI/CD;
75
+ - for each `--also` target, cherry-picks the fix onto a throwaway worktree at
76
+ that tag and re-tags it;
77
+ - cherry-picks the fix onto `main` for the next release.
78
+ On a **cherry-pick conflict** (non-zero exit), run `git -C <checkout>
79
+ cherry-pick --abort` there, relay the conflict, and **stop** — don't offer
80
+ teardown.
81
+ On a **no-op** ("nothing to land"), say so and continue.
82
+ 3. **Re-test on `main`** after the cherry-pick — it must be **green**.
83
+ 4. **Report** the deploy tag(s) and the `main` cherry-pick. It **never pushes** —
84
+ remind the user to `git push origin <deploy-tag>` to deploy. Then teardown
85
+ (step 7) applies: a tagged hotfix branch tears down with **no `--force`**.
86
+
87
+ ### 6-feature/bug. `Type: Feature` / `Type: Bug` — rebase + fast-forward
88
+
89
+ Land the finished branch on the base branch so the work reaches `main` (or your
90
+ configured `baseBranch`) in one flow. (Need the work on `main` *before* the spec
91
+ is finished — e.g. to run a later phase in CI or a shared test env? Use
92
+ **`/spec-to-main`**: same rebase + fast-forward, but it leaves the spec
93
+ `In Progress` and the worktree standing, and it's repeatable.)
61
94
 
62
95
  1. **Require a clean worktree.** The completion edits (status flip, the
63
96
  `git mv` to `complete/`) must be committed first — integrate refuses a dirty
64
97
  tree. If it's dirty, offer `/commit` and **stop**; don't auto-commit.
98
+ **If the spec is live** (you took the running instance with `/spec-live`):
99
+ `integrate` is live-aware — it ends the live session first (releases the branch
100
+ back to base, re-isolates it into its worktree, clears the receipt), then prints
101
+ the normal landing plan. Commit any live fixes to the branch first; it refuses
102
+ if the primary checkout is dirty, or if a *different* spec holds it (release that
103
+ one with `/spec-live main`). Teardown (step 7) is unchanged.
65
104
  2. **Plan + execute.** Run `skitterspec spec-env integrate <name>` and run the
66
105
  printed commands **in order**:
67
106
  - `git -C <worktree> rebase <base>` — replay the branch onto base.
@@ -87,9 +126,20 @@ directly (the old `/spec-env-down` skill is gone — teardown is folded in here)
87
126
  2. **Stop its host dev servers:** `skitterspec spec-env dev down <name>` (a
88
127
  no-op when none are running / configured).
89
128
  3. **Remove worktree + stack + slot:** run `skitterspec spec-env down <name>`
90
- and execute the commands it prints, in order. Post-integrate the branch is
91
- merged into base, so teardown needs **no `--force`** and deletes the branch
92
- (`git branch -d`) as part of the plan. It still respects the guards (won't
93
- destroy a dirty or unpushed-and-unmerged worktree without `--force`).
129
+ and execute the commands it prints, in order. After a **feature/bug** landing
130
+ the branch is merged into base, so teardown needs **no `--force`** and deletes
131
+ the branch (`git branch -d`). After a **hotfix** landing the branch isn't
132
+ merged (it was tagged + cherry-picked), but its head is captured by the deploy
133
+ tag, so teardown still needs no `--force` and drops the branch with
134
+ `git branch -D` (the tag holds the commits). It still respects the guards (won't
135
+ destroy a dirty, or unpushed-and-unlanded, worktree without `--force`).
136
+ 4. **Reap orphaned test-DB volumes:** run `skitterspec spec-env prune`. It lists
137
+ Docker volumes in the repo namespace that belong to **no live spec** (no
138
+ worktree) — leftovers from declined/aborted teardowns, manual
139
+ `git worktree remove`, or `--keep-volumes`. Show the user the orphan list and,
140
+ **only on their confirmation**, execute the printed `docker volume rm`
141
+ commands. Non-fatal: if prune can't run (Docker down) or the user declines,
142
+ report it and finish completing anyway — never block the spec on it. Skip when
143
+ Docker isn't in use (the command self-reports "no orphaned volumes").
94
144
 
95
145
  If `env.config.json` is absent, skip this entirely — behave exactly as before.
@@ -15,6 +15,12 @@ This skill is **opt-in**: it needs `specs/.core/env.config.json` with a `dev`
15
15
  block (host dev servers + their `frontPort`s). If isolation or `dev` is absent,
16
16
  say so and stop.
17
17
 
18
+ **Lighter alternative for a code-only spec:** `/spec-live` reuses the dev server
19
+ you already have running (it branch-switches the primary checkout) instead of
20
+ starting a second stack — no proxy, one process. Prefer it for code-only specs;
21
+ use `/spec-connect` when a spec has its own Docker stack, or to run several stacks
22
+ in parallel.
23
+
18
24
  ## 1. Identify the target
19
25
 
20
26
  - Use the spec named as an argument. The literal `main` means **disconnect**
@@ -98,7 +98,9 @@ runnable — its UI/API on the spec's reserved port block, isolated from `main`.
98
98
  - **Diverting your browser is a separate step.** To test the spec at your normal
99
99
  `localhost` URL, run **`/spec-connect <name>`** (exclusive — it exposes this
100
100
  spec on the canonical ports; `/spec-connect main` hands them back). `/spec-go`
101
- never seizes the canonical ports on its own.
101
+ never seizes the canonical ports on its own. For a **code-only** spec, the
102
+ lighter **`/spec-live <name>`** reuses your already-running dev server (a
103
+ branch-switch, no second stack) — `/spec-live main` hands it back.
102
104
 
103
105
  ## 3. Pre-flight — commit prior work
104
106
 
@@ -0,0 +1,161 @@
1
+ ---
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. 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.
4
+ ---
5
+
6
+ # /spec-hotfix — fix a released version, tag it, cherry-pick back to main
7
+
8
+ This is the **hotfix** counterpart to `/spec-bug`. Same test-first discipline
9
+ (reproduce as a **failing test (RED)**, then drive to **GREEN**), but the base is
10
+ a **release tag**, not `main`: prod is running a tagged version, so the fix must
11
+ be built on **that** commit line, shipped as a **new patch tag** (your CI/CD
12
+ deploys tags), and only then cherry-picked onto `main` for the next release.
13
+
14
+ Spec type convention (see `.claude/rules/spec-planning.md`):
15
+ - Hotfix specs are named `hotfix-<kebab-name>`; every header carries
16
+ `> **Type:** Hotfix` and `> **Base version:** <tag>`.
17
+ - Branch is `hotfix/<slug>`, forked from the base tag.
18
+
19
+ **Isolation is required.** A hotfix forks a worktree from a tag and lands by
20
+ tag + cherry-pick — it needs the isolation engine (`specs/.core/env.config.json`).
21
+ If isolation is absent, say so and stop; there is no in-place path.
22
+
23
+ ## 1. Establish the base version (the tag)
24
+
25
+ - Take the release tag from the argument — `/spec-hotfix <tag> <name>` (e.g.
26
+ `/spec-hotfix v33.16.4 login-crash`). If it's missing, **ask which version prod
27
+ is running** — don't guess.
28
+ - **Verify the tag exists** before anything else:
29
+ `git rev-parse --verify <tag>^{commit}`. If it doesn't resolve, stop and ask.
30
+
31
+ ## 2. Reproduce & isolate (light investigation)
32
+
33
+ Hotfixes are concrete — confirm, don't over-grill. Establish:
34
+
35
+ - **Repro:** exact steps / input that triggers it on the released version.
36
+ - **Expected vs actual:** what *should* happen vs what does.
37
+ - **Root cause:** read the code **at the base tag** and trace it to `file:line`.
38
+ The fix belongs on the tag's line, so reason about that code, not `main`'s.
39
+
40
+ ## 3. Seed the stub, then provision the worktree from the tag
41
+
42
+ The engine forks the worktree from the spec's `Base version`, so the stub — with
43
+ that header — must exist **before** `spec-env up`:
44
+
45
+ - From the base branch (`main`), create
46
+ `specs/in-progress/hotfix-<name>/00-overview.md` with the header block
47
+ (including `> **Type:** Hotfix` and `> **Base version:** <tag>`) and the
48
+ `## Symptom` you established. It starts in `in-progress` — work begins now.
49
+ - Run `skitterspec spec-env up hotfix-<name>`. It prints a `git worktree add …
50
+ -b hotfix/<slug> <tag>` command (the branch forks from **the tag**, not
51
+ `main`), the worktree path, the opener, and any `in the worktree, run:`
52
+ bootstrap steps.
53
+ - Run the printed `git worktree add`. **The worktree is checked out at the tag,
54
+ so your uncommitted stub doesn't travel with it** — move it across so `main`
55
+ stays pristine:
56
+ `mv specs/in-progress/hotfix-<name> <worktreePath>/specs/in-progress/`.
57
+ - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
58
+ none of the repo's gitignored files (`.env`, local overrides). Run the printed
59
+ `in the worktree, run:` steps (file seeding, then setup) in order, before
60
+ anything else.
61
+ - **Trust the worktree for this session.** The engine wrote the printed
62
+ `trusted:` root into `.claude/settings.local.json`, but it won't hot-reload now
63
+ — run `/add-dir <trusted root>` before editing into the worktree, or the first
64
+ edits will prompt.
65
+ - **Do everything below in the worktree**, on the `hotfix/<slug>` branch — the red
66
+ test, the fix, and the rest of the spec. Act with absolute paths /
67
+ `git -C <worktreePath>`, or open a fresh session rooted there. `main` changes
68
+ only at `/spec-complete` (via cherry-pick, not merge).
69
+
70
+ ## 4. Write the failing test FIRST (RED) — mandatory
71
+
72
+ Encode the **correct** (expected) behaviour as a test, then run it and confirm it
73
+ **fails for the right reason**, on the hotfix branch:
74
+
75
+ - Put it where the suite already covers that area. Reuse existing test helpers /
76
+ factories; follow the project's test rules (see `.claude/rules/`). Never
77
+ hardcode dates — compute them relative to now.
78
+ - Run it with the project's test command. Quote the red output. A test that
79
+ passes before the fix proves nothing — keep refining until it genuinely
80
+ captures the bug on this version.
81
+
82
+ ## 5. Write the Hotfix spec
83
+
84
+ Flesh out `00-overview.md` in the worktree (you seeded the stub in §3). A hotfix
85
+ is usually a single-pass fix, so the `## Fix` block can live directly in
86
+ `00-overview.md`. Keep it lean:
87
+
88
+ ```markdown
89
+ # Hotfix: <short title>
90
+
91
+ > **Type:** Hotfix
92
+ > **Status:** In Progress — fixing (red test added)
93
+ > **Author:** <git user.name — who reported/captured it>
94
+ > **Developer:** <git user.name — you, since you're fixing it now>
95
+ > **Base version:** <tag prod is running, e.g. v33.16.4>
96
+ > **Raised:** <YYYY-MM-DD (today)>
97
+ > **Area:** <files/modules>
98
+
99
+ ## Symptom
100
+
101
+ <observed wrong behaviour on the released version + repro steps; paste any error>
102
+
103
+ ## Root cause
104
+
105
+ <the actual cause, at `file:line` on the base tag. One paragraph — be specific.>
106
+
107
+ ## Failing test (red)
108
+
109
+ <test name + path; what it asserts. How to run it. Paste the red failure line.>
110
+
111
+ ## Fix
112
+
113
+ - [ ] <the minimal change that addresses the root cause, not the symptom>
114
+ - [ ] Failing test now passes (GREEN); run the project's typecheck and test
115
+ commands — confirm no regressions.
116
+ - [ ] <any follow-up hardening, or "None">
117
+
118
+ ## Landing
119
+
120
+ - [ ] Deploy tag (patch bump of the base version) created at `/spec-complete`
121
+ and pushed **by you** to trigger CI/CD.
122
+ - [ ] Fix cherry-picked onto `main` (and any `--also` release lines).
123
+
124
+ ## State log
125
+
126
+ | Date | Status | Folder | By |
127
+ |------|--------|--------|----|
128
+ | <YYYY-MM-DD> | In Progress | in-progress | <developer> |
129
+
130
+ ## Changelog
131
+
132
+ - <YYYY-MM-DD> — Hotfix reproduced on <tag>; failing test added (red).
133
+ ```
134
+
135
+ Keep the **State log** (state transitions) separate from the **Changelog** (fix
136
+ narrative and decisions).
137
+
138
+ ## 6. Drive to GREEN
139
+
140
+ - Implement the **minimal, root-cause** fix on the branch. Match surrounding code;
141
+ honour all project rules (see `.claude/rules/`).
142
+ - Re-run the failing test → it must pass. Then run the project's typecheck and
143
+ test commands to confirm no regressions. Quote results.
144
+ - Commit the fix to the `hotfix/<slug>` branch (this commit is what gets tagged
145
+ and cherry-picked). Tick the Fix tasks; add a Changelog line.
146
+
147
+ ## 7. Report
148
+
149
+ Summarise: the base tag, root cause, the failing→passing test, the fix, and the
150
+ full test result. The spec stays in `in-progress`.
151
+
152
+ - **`/spec-live` is refused for a hotfix** — its branch is built on an old tag, so
153
+ hot-reloading it onto the running dev server could break the shared instance.
154
+ To test it, use `/spec-connect` (its own isolated stack).
155
+ - Suggest **`/spec-complete`** to land it: it patch-bumps the base tag, tags the
156
+ hotfix branch **locally** (you push it to deploy), and cherry-picks the fix onto
157
+ `main`. Add `--also <tag>` at completion to also patch other release lines
158
+ (test/demo on their own versions).
159
+
160
+ Do **not** `git push` or `git tag`-and-push unless the user asks — deploying to
161
+ prod is theirs to trigger.
@@ -13,6 +13,14 @@ clobber customised content. Finish with a summary of created vs already-present.
13
13
  > all of the below mechanically. This skill is the manual/repair path and is
14
14
  > useful when the package isn't available or you only need to fix part of the
15
15
  > setup.
16
+ >
17
+ > **Re-running on an already-set-up repo is safe.** `init` detects the existing
18
+ > setup (via the committed `specs/.core/.skitterspec-manifest.json` of installed
19
+ > file hashes) and, interactively, offers three paths — **Resync** (update managed
20
+ > skills/rules to the latest but keep files you've edited), **Start again** (reset
21
+ > the managed scaffolding fresh — never your specs or config, with a confirm), or
22
+ > **Leave alone**. Non-interactively it only adds what's missing; `--resync` /
23
+ > `--reset` (reset needs `--yes`) drive the stronger actions.
16
24
 
17
25
  The system is **eight skills**: `spec` (feature), `spec-bug` (bug), `spec-ready`,
18
26
  `spec-review`, `spec-go`, `spec-complete`, `spec-cancel`, and this `spec-init`. The lifecycle is
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: spec-live
3
+ description: Test a spec on your already-running dev server by checking its branch out in the primary checkout — no second stack, no proxy. `spec-live <spec>` takes the running instance for that spec; `spec-live main` releases it. Runs `skitterspec spec-env live`. Opt-in — needs specs/.core/env.config.json. Code-only specs; stateful (Docker/migration) specs use /spec-connect. Use when the user says "/spec-live", "go live with <spec>", "take the instance for <spec>", or "test <spec> on the running server".
4
+ ---
5
+
6
+ # /spec-live — put one spec live on the running instance
7
+
8
+ Instead of running a second dev stack for a spec (that's `/spec-connect`), **reuse
9
+ the one instance you already have**: rebase the spec's branch onto base, hand it
10
+ from its worktree to the **primary checkout**, and let your running dev server
11
+ hot-reload it. You test at your normal URL, with one process. The branch that's
12
+ checked out in the primary checkout **is** the lock — exactly one spec is live at
13
+ a time, and `/spec-live main` hands the instance back.
14
+
15
+ This skill is **opt-in**: it needs `specs/.core/env.config.json`. If isolation is
16
+ absent, say so and stop.
17
+
18
+ **Code-only.** Live overlay refuses a **stateful** spec — one whose `> **Stack:**`
19
+ is `worktree + docker`, or whose branch changes migrations (per
20
+ `env.config.json` → `live.migrations`). Those keep their isolated stack; use
21
+ `/spec-connect` for them. It also **always refuses a `Type: Hotfix` spec** — its
22
+ branch is built on an old release tag, so hot-reloading it onto the running dev
23
+ server could break the shared instance; test a hotfix with `/spec-connect`. The
24
+ engine enforces all of this and prints why.
25
+
26
+ ## 1. Identify the target
27
+
28
+ - Use the spec named as an argument. The literal `main` means **release** (hand
29
+ the instance back to base). Else use the spec **currently in context**; if
30
+ unclear, ask.
31
+
32
+ ## 2. Make sure a dev server is running
33
+
34
+ `live take` **verifies** a dev server is up on your canonical ports and switches
35
+ the branch under it — it does **not** start one. If nothing is listening it
36
+ refuses; start your dev server first (however you normally run it, or
37
+ `skitterspec spec-env dev up <spec>`). (Projects with no `dev` servers configured
38
+ have nothing to hot-reload — the switch still happens, with a warning.)
39
+
40
+ ## 3. Take (or release)
41
+
42
+ ```
43
+ skitterspec spec-env live take <spec> # rebase → detach worktree → checkout in primary
44
+ skitterspec spec-env live release # hand the instance back to base, re-isolate the branch
45
+ skitterspec spec-env live abort # crash recovery (see below)
46
+ skitterspec spec-env live status # who's live (branch in the primary checkout + receipt)
47
+ ```
48
+
49
+ **Take** rebases the branch onto base, frees it from its worktree
50
+ (`switch --detach`), checks it out in the primary checkout, then writes a receipt
51
+ (`.spec-env/live.json`). Relay its output. **If it reports the rebase hit
52
+ conflicts**, it left everything untouched — rebase the branch in its worktree,
53
+ resolve, then retry. **If it says a spec already holds the instance**, release it
54
+ first. If it warns dependencies changed, restart your dev server after the switch.
55
+
56
+ **Release** (`/spec-live main`) is the graceful exit of an unfinished session:
57
+ `skitterspec spec-env live release` reads the live spec from the receipt, checks
58
+ base back out in the primary checkout, re-attaches the branch to its worktree, and
59
+ clears the receipt. Commit any fixes to the branch first — it refuses on a dirty
60
+ tree rather than discard them. (To *finish* a live spec instead of releasing it,
61
+ use `/spec-complete`, which is live-aware.)
62
+
63
+ **Abort** is crash recovery, for when a session died mid-take and left the primary
64
+ checkout on a feature branch: `skitterspec spec-env live abort` restores base from
65
+ the receipt and re-isolates. It refuses if the primary checkout has uncommitted
66
+ changes (it won't discard them) — commit or stash first.
67
+
68
+ ## 4. Report
69
+
70
+ Echo which spec is now live on the primary checkout (and any warning), that it was
71
+ released / recovered, or — for `status` — which branch the primary checkout is on
72
+ and whether the instance is free. Fixes you make while live commit straight onto
73
+ the spec's branch.