@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 +15 -4
- package/assets/core/env.config.md +39 -2
- package/assets/rules/spec-planning.md +32 -13
- package/assets/skills/spec-cancel/SKILL.md +5 -0
- package/assets/skills/spec-complete/SKILL.md +55 -11
- package/assets/skills/spec-hotfix/SKILL.md +161 -0
- package/assets/skills/spec-live/SKILL.md +4 -1
- package/assets/skills/spec-to-main/SKILL.md +99 -0
- package/package.json +1 -1
- package/src/cli.js +271 -4
- package/src/env/config.js +18 -0
- package/src/env/hotfix.js +133 -0
- package/src/env/live.js +12 -3
- package/src/env/provision.js +5 -1
- package/src/env/prune.js +119 -0
- package/src/env/resolve.js +28 -4
- package/src/env/teardown.js +20 -13
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
|
|
13
|
-
**isolation** — a git worktree per in-progress spec, Docker on demand,
|
|
14
|
-
servers on reserved ports, and `/spec-connect` to test a worktree at your
|
|
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
|
|
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
|
|
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`
|
|
22
|
-
immediately), so
|
|
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.
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
91
|
+
## Spec types — Feature, Bug, Hotfix
|
|
81
92
|
|
|
82
|
-
Every spec is one of
|
|
93
|
+
Every spec is one of three types, recorded **both** in the header and the filename:
|
|
83
94
|
|
|
84
|
-
- **Header field:** `> **Type:** Feature
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
|
25
|
-
the spec now passes — that test is the proof
|
|
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.
|
|
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
|
|
58
|
-
spec has nothing to land, and `/spec-complete` behaves exactly as
|
|
59
|
-
applies, offer to land the finished branch
|
|
60
|
-
|
|
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.
|
|
97
|
-
merged into base, so teardown needs **no `--force`** and deletes
|
|
98
|
-
(`git branch -d`)
|
|
99
|
-
|
|
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.
|
|
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": "
|
|
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",
|