@skitterbyte/skitterspec 12.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
@@ -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-
@@ -155,6 +155,20 @@ no live `env.config.json` was found.
155
155
  // refuses it (code-only v1 — use `/spec-connect` for those). Default: none.
156
156
  "live": {
157
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": []
158
172
  }
159
173
  }
160
174
  ```
@@ -165,3 +179,26 @@ no live `env.config.json` was found.
165
179
  - `{repoSlug}` — `{repo}` lower-cased, non-alphanumerics collapsed to `-`
166
180
  (safe for a `COMPOSE_PROJECT_NAME`).
167
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,14 @@ 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.
41
52
 
42
53
  **Live overlay (`/spec-live`) — the light way to test a spec.** `/spec-connect`
43
54
  runs a spec's *own* dev stack and proxies the canonical ports to it (one stack per
@@ -77,16 +88,24 @@ consistent with the codebase:
77
88
  - **Other rules specs must honour:** link the relevant `.claude/rules/*.md`
78
89
  (architecture, code style, testing, database, etc.) rather than restating them.
79
90
 
80
- ## Spec types — Feature vs Bug
91
+ ## Spec types — Feature, Bug, Hotfix
81
92
 
82
- 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:
83
94
 
84
- - **Header field:** `> **Type:** Feature` or `> **Type:** Bug` (authoritative,
85
- greppable: `grep -rl 'Type:.*Bug' specs/`).
86
- - **Filename prefix:** `feat-<name>` for features, `bug-<name>` for bugs
87
- (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).
88
101
 
89
- 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.
90
109
 
91
110
  ## Header fields & State log (audit trail)
92
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,13 +52,45 @@ 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
@@ -93,9 +126,20 @@ directly (the old `/spec-env-down` skill is gone — teardown is folded in here)
93
126
  2. **Stop its host dev servers:** `skitterspec spec-env dev down <name>` (a
94
127
  no-op when none are running / configured).
95
128
  3. **Remove worktree + stack + slot:** run `skitterspec spec-env down <name>`
96
- and execute the commands it prints, in order. Post-integrate the branch is
97
- merged into base, so teardown needs **no `--force`** and deletes the branch
98
- (`git branch -d`) as part of the plan. It still respects the guards (won't
99
- 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").
100
144
 
101
145
  If `env.config.json` is absent, skip this entirely — behave exactly as before.
@@ -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.
@@ -18,7 +18,10 @@ absent, say so and stop.
18
18
  **Code-only.** Live overlay refuses a **stateful** spec — one whose `> **Stack:**`
19
19
  is `worktree + docker`, or whose branch changes migrations (per
20
20
  `env.config.json` → `live.migrations`). Those keep their isolated stack; use
21
- `/spec-connect` for them. The engine enforces this and prints why.
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.
22
25
 
23
26
  ## 1. Identify the target
24
27
 
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: spec-to-main
3
+ description: Land an in-progress spec's branch onto main WITHOUT finishing it — rebase + fast-forward so the work reaches main (to run it in CI / a shared test env), while the worktree stays and the spec stays In Progress. Repeatable — land again as you commit more. Targets a spec by name (arg) or the spec in context. Use when the user says "/spec-to-main", "land this on main but keep going", "I need this on main to run tests before finishing", or "merge to main without completing the spec".
4
+ ---
5
+
6
+ # /spec-to-main — land the branch on main, keep the spec open
7
+
8
+ The **intermediate** landing. `/spec-complete` also lands the branch, but then
9
+ verifies every phase, flips the status to Complete, `git mv`s the spec to
10
+ `complete/`, and tears the environment down. **`/spec-to-main` stops after the
11
+ land**: the worktree stays, the spec stays `In Progress`, and you can land again
12
+ as you add commits.
13
+
14
+ Use it when a later phase can only be done *after* the current work is on `main` —
15
+ e.g. it needs to run in CI, a deploy pipeline, or a shared test environment that
16
+ builds from `main`. Land what you have, run that step, then come back and finish
17
+ the remaining phases with `/spec-go` and eventually `/spec-complete`.
18
+
19
+ It reuses the **same engine** as `/spec-complete`'s landing (`spec-env integrate`
20
+ — rebase + fast-forward), so it produces identical linear history. Because a
21
+ fast-forward leaves `base == branch`, the operation is **idempotent and
22
+ repeatable**: new commits put the branch ahead of base again, and you can run
23
+ `/spec-to-main` as many times as you like.
24
+
25
+ ## 0. Preconditions — when this applies
26
+
27
+ - **Isolation must be on** (`specs/.core/env.config.json` exists **and** the spec
28
+ is on a worktree provisioned by `/spec-go`). If isolation is absent, there is
29
+ nothing to land — the spec is authored directly on `main` already. Say so and
30
+ stop.
31
+ - **Feature / Bug specs only.** A **Hotfix** (`Type: Hotfix`) is built on a
32
+ release *tag* and cannot fast-forward onto `main` — refuse it and point the user
33
+ at `/spec-complete` (it lands a hotfix via tag + cherry-pick). Check the header
34
+ `> **Type:**` before proceeding.
35
+
36
+ ## 1. Identify the target spec
37
+
38
+ - Use the name/path argument if given, else the spec **in context**. If unclear,
39
+ ask which spec.
40
+ - Locate its folder under `specs/in-progress/`. Entry point is `00-overview.md`;
41
+ confirm `> **Status:**` is `In Progress` and `> **Type:**` is `Feature` or
42
+ `Bug`.
43
+
44
+ ## 2. Require a clean worktree
45
+
46
+ The land rebases the branch — it refuses a dirty tree. If the worktree has
47
+ uncommitted changes, offer `/commit` and **stop**; don't auto-commit.
48
+
49
+ **If the spec is live** (you took the running instance with `/spec-live`):
50
+ `integrate` is live-aware — it ends the live session first (releases the branch
51
+ back to base, re-isolates it into its worktree, clears the receipt), then prints
52
+ the landing plan. Commit any live fixes to the branch first; it refuses if the
53
+ primary checkout is dirty, or if a *different* spec holds it (release that one with
54
+ `/spec-live main`).
55
+
56
+ ## 3. Tests must be green before landing
57
+
58
+ Don't push red to `main`. Run the project's typecheck and test commands **in the
59
+ worktree**; the suite must be **green**. For a **Bug** spec, confirm the
60
+ originally-failing test now passes. If anything is red, stop and report — landing
61
+ broken code onto `main` defeats the purpose.
62
+
63
+ (Note this is the *worktree* suite. The whole point of this skill is often to run
64
+ a *further* check that only exists on `main` / in CI — that one runs **after** the
65
+ land, in step 5.)
66
+
67
+ ## 4. Land — rebase + fast-forward
68
+
69
+ Run `skitterspec spec-env integrate <name>` and run the printed commands **in
70
+ order**:
71
+
72
+ - `git -C <worktree> rebase <base>` — replay the branch onto base.
73
+ - `git -C <mainRepoPath> merge --ff-only <branch>` — fast-forward base.
74
+
75
+ On a **rebase conflict** (non-zero exit), run `git -C <worktree> rebase --abort`,
76
+ relay the conflict, and **stop** — leave the resolution to the user; change
77
+ nothing else.
78
+
79
+ On a **no-op** ("already landed on `<base>` — nothing to integrate"), just say so
80
+ and continue — the branch has no commits base doesn't already have.
81
+
82
+ ## 5. Re-test on base, then report
83
+
84
+ - Run the project's test command **from the primary checkout** — base must be
85
+ **green** after the fast-forward.
86
+ - Add a **Changelog** entry to `00-overview.md` recording the intermediate land
87
+ and *why*, e.g.
88
+ `- <YYYY-MM-DD> — Landed intermediate work onto <base> to <run CI / deploy to
89
+ test env / …>; spec stays In Progress.`
90
+ - Do **NOT**: add a State-log row (status doesn't change), flip any phase/status
91
+ to Complete, `git mv` the spec, or tear down the worktree/stack. **The spec
92
+ stays `In Progress` and the worktree stays put.**
93
+ - Report: the base branch, the fast-forward result, and the green base test. It
94
+ **never pushes** — mention the user can `git push` the base branch themselves to
95
+ trigger CI / the shared env.
96
+ - Point the way forward: `/spec-go` to continue the remaining phases (you'll keep
97
+ committing on the same branch and can `/spec-to-main` again), and `/spec-complete`
98
+ when every phase is genuinely done — it will land the final commits, finalise,
99
+ and tear down.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skitterbyte/skitterspec",
3
- "version": "12.0.0",
3
+ "version": "13.0.0",
4
4
  "description": "Spec-driven development for Claude Code — a tracker-free filesystem workflow: lifecycle skills and per-spec isolation. For Linear sync, install @skitterbyte/skitterspec-linear instead.",
5
5
  "keywords": [
6
6
  "claude",