@skitterbyte/skitterspec 21.0.0 → 22.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +218 -0
- package/README.md +127 -6
- package/assets/claude-md-section.md +42 -18
- package/assets/commands/allow-main.md +33 -0
- package/assets/commands/spec-remote-review.md +22 -0
- package/assets/commands/spec-skip.md +24 -0
- package/assets/core/env.config.json.example +6 -3
- package/assets/core/env.config.md +183 -25
- package/assets/hooks/main-guard.cjs +145 -0
- package/assets/hooks/review-gate.cjs +8 -3
- package/assets/review/page.html +1174 -101
- package/assets/rules/offered-unblocks.md +100 -0
- package/assets/rules/spec-planning.md +195 -14
- package/assets/rules/spec-reports.md +181 -29
- package/assets/skills/no-spec/SKILL.md +219 -0
- package/assets/skills/spec/SKILL.md +248 -21
- package/assets/skills/spec-bug/SKILL.md +34 -24
- package/assets/skills/spec-cancel/SKILL.md +29 -0
- package/assets/skills/spec-complete/SKILL.md +25 -0
- package/assets/skills/spec-diff/SKILL.md +164 -37
- package/assets/skills/spec-hotfix/SKILL.md +22 -19
- package/assets/skills/spec-init/SKILL.md +4 -2
- package/assets/skills/spec-next/SKILL.md +166 -58
- package/assets/skills/spec-review/SKILL.md +87 -0
- package/assets/skills/spec-reviewed/SKILL.md +31 -5
- package/assets/skills/spec-start/SKILL.md +33 -0
- package/package.json +1 -1
- package/src/cli.js +1612 -172
- package/src/env/classify.js +87 -2
- package/src/env/config.js +333 -19
- package/src/env/hooks.js +102 -33
- package/src/env/live.js +124 -1
- package/src/env/mainguard.js +240 -0
- package/src/env/provision.js +106 -10
- package/src/env/registry.js +70 -6
- package/src/env/resolve.js +128 -5
- package/src/env/review.js +854 -29
- package/src/env/reviewers/coderabbit.js +228 -0
- package/src/env/reviewers.js +517 -0
- package/src/env/serve.js +474 -50
- package/src/env/supervise.js +8 -1
- package/src/env/teardown.js +12 -1
- package/src/init.js +185 -24
|
@@ -35,8 +35,8 @@ A verdict sentence, a blank line, then a two-column table:
|
|
|
35
35
|
| **Tracker** | [ABC-88](https://example.invalid/ABC-88) · `feat-foo` · phase 2 moved |
|
|
36
36
|
| **Branch** | `spec/feat-foo` · 3 commits, clean |
|
|
37
37
|
| **Built** | POST /orders handler, orders schema |
|
|
38
|
-
| **Tests** | 128 passed ·
|
|
39
|
-
| **Review** | 7 files, +212 −18 · [
|
|
38
|
+
| **Tests** | 128 passed · dotnet test |
|
|
39
|
+
| **Review** | 7 files, +212 −18 · **local** [http://127.0.0.1:7760/…](http://127.0.0.1:7760/…) · **network** [http://192.168.0.136:7760/…](http://192.168.0.136:7760/…) · **remote** off |
|
|
40
40
|
| **Follow-ups** | none |
|
|
41
41
|
| **Next** | `/spec-next` → phase 3 (Auth) |
|
|
42
42
|
|
|
@@ -87,23 +87,95 @@ the options may be offered after the table.
|
|
|
87
87
|
|
|
88
88
|
## ⏸ Review ready — 7 files, +212 −18
|
|
89
89
|
|
|
90
|
-
**
|
|
90
|
+
- **local** — [http://127.0.0.1:7760/7e9e123e7540/feat-orders](http://127.0.0.1:7760/7e9e123e7540/feat-orders)
|
|
91
|
+
- **network** — [http://192.168.0.136:7760/7e9e123e7540/feat-orders](http://192.168.0.136:7760/7e9e123e7540/feat-orders)
|
|
92
|
+
- **remote** — off · `/spec-remote-review` turns it on
|
|
93
|
+
|
|
94
|
+
live: off — /spec-live to put it live
|
|
95
|
+
|
|
96
|
+
I'm holding here until you send a verdict — the wait covers local and network.
|
|
91
97
|
|
|
92
98
|
`/spec-reviewed` picks it up · `spec-env review skip "<reason>"` moves on
|
|
93
99
|
|
|
94
100
|
---
|
|
95
101
|
|
|
96
|
-
A rule, a heading naming the state and the size, the
|
|
97
|
-
saying the run is stopped
|
|
98
|
-
paragraph explaining it.
|
|
102
|
+
A rule, a heading naming the state and the size, **the stack**, the `live:`
|
|
103
|
+
line, one line saying the run is stopped and which tiers it covers, and the two
|
|
104
|
+
exits. Nothing else, and never a paragraph explaining it.
|
|
105
|
+
|
|
106
|
+
**The `live:` line, and why a rigid contract took a second amendment.** Reading
|
|
107
|
+
a diff is not the only way to judge a change — often the question is whether it
|
|
108
|
+
*works* — and the answer to that lives at the running URL. A reader deciding
|
|
109
|
+
whether to open the page at all wants to know whether it is already running
|
|
110
|
+
somewhere, and finding that out any other way is a trip to a terminal in the
|
|
111
|
+
middle of a review.
|
|
112
|
+
|
|
113
|
+
**Each line names a command a person types**, rather than describing a
|
|
114
|
+
capability. `live: off — the page can put it live` told the reader that a page
|
|
115
|
+
somewhere could do it and left them to find the verb — and the verb is what they
|
|
116
|
+
need when they are in a terminal rather than on the page. So the lines say
|
|
117
|
+
`/spec-live`, `/spec-live main`, `/spec-remote-review`. Making them *clickable*
|
|
118
|
+
was considered and rejected: the only clickable thing markdown has is a URL, and
|
|
119
|
+
a URL that acts when it is **fetched** is one a link previewer or a prefetcher
|
|
120
|
+
fires with nobody involved.
|
|
121
|
+
|
|
122
|
+
It is the engine's line, copied like the stack: `spec-env review` prints it and
|
|
123
|
+
`--json` carries the same answer as `live`, from one function, so the report and
|
|
124
|
+
the command cannot disagree. Four states, and only three of them are a line —
|
|
125
|
+
`on` (with the URL when the project configured one), `off`, `held` (naming the
|
|
126
|
+
spec holding the workbench). The fourth, `unavailable`,
|
|
127
|
+
**prints nothing at all**:
|
|
128
|
+
a project with no isolation and a spec with no worktree both land there,
|
|
129
|
+
and a line about a surface that does not exist is an accusation against a
|
|
130
|
+
healthy repo.
|
|
131
|
+
|
|
132
|
+
**This is the second amendment to this section in two specs**, which is worth
|
|
133
|
+
naming rather than letting pass. The contract earns its rigidity from real
|
|
134
|
+
failures, and two amendments in a row is how a rigid contract quietly becomes a
|
|
135
|
+
negotiable one. Both have carried their reason and both replaced a line rather
|
|
136
|
+
than adding a paragraph.
|
|
137
|
+
**A third should have to argue harder than either did.**
|
|
138
|
+
|
|
139
|
+
**The stack is the engine's, copied rather than composed.** `spec-env review`
|
|
140
|
+
prints one line per tier and `--json` carries the same thing as `tiers`, so take
|
|
141
|
+
it from there in the order it comes — and do not decide which tiers are worth
|
|
142
|
+
mentioning. The whole reason the stack exists is that the engine was being asked
|
|
143
|
+
to guess where the reader was sitting, and it guessed wrong three separate ways
|
|
144
|
+
in one day; a skill re-deciding that in prose is the same guess one layer up.
|
|
145
|
+
|
|
146
|
+
**Three tiers, always all three, in this order.**
|
|
147
|
+
|
|
148
|
+
| Tier | Is | Off when |
|
|
149
|
+
|------|----|----------|
|
|
150
|
+
| `local` | the loopback URL — the machine the run is on | never. With nothing served it is the `file://` page, and says it cannot send a verdict |
|
|
151
|
+
| `network` | the LAN URL — a phone on the same wifi | `review.allowNetwork` is false, or this machine has no network address |
|
|
152
|
+
| `remote` | a published page, for a reader off the network | `review.allowRemote` is false, or nothing has been published |
|
|
153
|
+
|
|
154
|
+
A tier that is off **keeps its line** and names the one command that turns it
|
|
155
|
+
on. Dropping the line is what left a reader who had walked out of the house with
|
|
156
|
+
nothing on screen to tell them a remote page was even possible — they could not
|
|
157
|
+
ask for what they could not see.
|
|
99
158
|
|
|
100
159
|
**Only promise a wait the transport can deliver.** The wait itself is real in
|
|
101
160
|
every case; what varies is what carries it back, not whether the run is
|
|
102
161
|
stopped. Three transports, three true sentences:
|
|
103
162
|
|
|
104
|
-
- **A page the engine SERVES** hands its pass to the local store,
|
|
105
|
-
|
|
163
|
+
- **A page the engine SERVES** hands its pass to the local store, and
|
|
164
|
+
`spec-env review wait` returns when it lands. The run is woken by the press:
|
|
106
165
|
*"I'm holding here until you send a verdict."*
|
|
166
|
+
|
|
167
|
+
**That sentence is only true for as long as the wait is actually running**, so
|
|
168
|
+
the wait is the engine's and never one composed for the occasion. A watcher
|
|
169
|
+
written per run is proven by nothing: one was written
|
|
170
|
+
`until [ -f "$P" ] && [ "$x" \> "$y" ]` — valid bash, a syntax error in zsh,
|
|
171
|
+
a predicate that could never be true — and it spun for five minutes while the
|
|
172
|
+
report underneath it said the run was holding.
|
|
173
|
+
**Silence is what made that expensive**:
|
|
174
|
+
a wait that cannot fire and one patiently working look identical,
|
|
175
|
+
so nothing seemed wrong until the reader asked. Give the wait no timeout
|
|
176
|
+
either; it lasts as long as the session, because a reader who walks away from
|
|
177
|
+
a diff is the normal case and a bounded watch once lost a verdict to a lunch
|
|
178
|
+
break.
|
|
107
179
|
- **A `file://` page** has no server to POST to, so the pass is copied and
|
|
108
180
|
pasted — the reader's next message is what carries it. The run is stopped just
|
|
109
181
|
the same, and says so:
|
|
@@ -112,10 +184,16 @@ stopped. Three transports, three true sentences:
|
|
|
112
184
|
not a lesser one, and it is not an excuse to ask without waiting.
|
|
113
185
|
- **A PUBLISHED page** writes to the artifact's own store, and nothing pushes
|
|
114
186
|
from there into the conversation. That is the one case where a verdict is
|
|
115
|
-
genuinely invisible until someone asks for it, so the
|
|
116
|
-
|
|
187
|
+
genuinely invisible until someone asks for it, so its line in the stack says
|
|
188
|
+
that rather than letting the holding line speak for it:
|
|
189
|
+
|
|
190
|
+
- **remote** — [https://…](https://…) · a verdict here needs `/spec-reviewed`
|
|
117
191
|
|
|
118
|
-
|
|
192
|
+
Where `remote` is the only tier a reader can reach, the holding line says so
|
|
193
|
+
too: *press a verdict, then type `/spec-reviewed` — I cannot see it until you
|
|
194
|
+
do.* Where a served tier is reachable as well, the holding line keeps naming
|
|
195
|
+
the tiers the wait covers, and `remote`'s own caveat sits on `remote`'s line
|
|
196
|
+
where it belongs.
|
|
119
197
|
|
|
120
198
|
**A harness with no file-watch does not get an exemption.** It once read
|
|
121
199
|
"change nothing" — keep the row, keep the question, do not wait — and that
|
|
@@ -123,15 +201,57 @@ escape hatch is what let a whole class of runs go on asking questions nobody was
|
|
|
123
201
|
listening for. Where a watch is unavailable the wait is the turn ending, which
|
|
124
202
|
every harness can do.
|
|
125
203
|
|
|
204
|
+
**A watch that dies is re-armed, silently, on the same window.** A backgrounded
|
|
205
|
+
wait does not always survive a long idle: three sessions lost theirs over one
|
|
206
|
+
lunch break, and two in another were killed at 43 and 30 minutes. So a wait that
|
|
207
|
+
ends **without a verdict** and **was not stopped by the operator** is started
|
|
208
|
+
again on the **same** `--since`. Not a fresh one — a pass that arrived during
|
|
209
|
+
the gap is still inside the original window, and re-arming on a new timestamp
|
|
210
|
+
would strand exactly that pass.
|
|
211
|
+
|
|
212
|
+
**Say nothing when you do it.** Nothing happened and the window is unchanged; a
|
|
213
|
+
line on every death turns a working loop into a stream of non-events.
|
|
214
|
+
|
|
215
|
+
**An operator who stopped it is not a death.** Re-arming over a deliberate stop
|
|
216
|
+
makes the wait unstoppable, which is worse than a wait that stops. Where the two
|
|
217
|
+
cannot be told apart, treat it as deliberate and leave it
|
|
218
|
+
(`.claude/rules/negative-checks.md` rule 4): the cost of being wrong is one
|
|
219
|
+
`/spec-reviewed`, against a loop nobody can break.
|
|
220
|
+
|
|
221
|
+
**It is bounded by the age of the window, not by a count of retries.** Keep
|
|
222
|
+
re-arming while the window is younger than **12 hours**, then stop. A count means
|
|
223
|
+
something different depending on whether deaths come five minutes or forty-five
|
|
224
|
+
apart, and the observed interval already varies that much. Twelve hours
|
|
225
|
+
deliberately does not cover an overnight gap — the pass is never lost, and
|
|
226
|
+
`/spec-reviewed` is the designed recovery — because the alternative is waking
|
|
227
|
+
the session every half hour all night for a review nobody is returning to
|
|
228
|
+
before morning.
|
|
229
|
+
|
|
230
|
+
**Past the bound the banner degrades**, to the sentence this file already
|
|
231
|
+
defines for a transport that cannot push into the conversation:
|
|
232
|
+
|
|
233
|
+
*press a verdict, then type `/spec-reviewed` — I cannot see it until you do.*
|
|
234
|
+
|
|
235
|
+
That is a new **state** for an existing sentence, not a new sentence. The
|
|
236
|
+
holding line is only ever printed while a wait is actually running, which is the
|
|
237
|
+
rule this section has always carried: *only promise a wait the transport can
|
|
238
|
+
deliver.*
|
|
239
|
+
|
|
126
240
|
**The `Continue` ending, and why the banner's exits differ mid-run.** A page
|
|
127
241
|
rendered part-way through a run offers `Continue` — *I have read it, carry on* —
|
|
128
242
|
in place of the committing verdicts, because "commit" is the wrong verb for
|
|
129
|
-
unfinished work. Its banner names the same state and
|
|
243
|
+
unfinished work. Its banner names the same state and the same stack, and
|
|
244
|
+
different exits:
|
|
245
|
+
|
|
246
|
+
…the stack, unchanged…
|
|
130
247
|
|
|
131
|
-
|
|
248
|
+
I'm holding here until you send a verdict — the wait covers local and network.
|
|
132
249
|
|
|
133
250
|
`Continue` carries on · `Request changes` works them now
|
|
134
251
|
|
|
252
|
+
The stack is written out once, above, and referred to everywhere else. Two
|
|
253
|
+
copies of it is how the two come to disagree about which tiers exist.
|
|
254
|
+
|
|
135
255
|
**It is not the `none` verdict that was removed.** `none` recorded itself and
|
|
136
256
|
did nothing, which is the record-and-do-nothing ending this contract exists
|
|
137
257
|
against. `Continue` **resumes the run** — it names an action, which is the bar
|
|
@@ -145,13 +265,40 @@ block. *Waiting* is what any offer does, and it is what this section governs.
|
|
|
145
265
|
that is finished. A mid-run render waits without arming — walking away from it
|
|
146
266
|
costs nothing, which is exactly why `Continue` is safe to offer there.
|
|
147
267
|
|
|
148
|
-
**
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
268
|
+
**One link per reachable store, each labelled.** This amends
|
|
269
|
+
*"exactly one link, never two"*, and the evidence that rule was written on is
|
|
270
|
+
the reason it still reads the way it does. Two links were handed over, the wait
|
|
271
|
+
stood behind only one of them, and a verdict was pressed on the published page
|
|
272
|
+
three times while each one sat unread under a line claiming the run was waiting.
|
|
273
|
+
Two links was not a convenience with a caveat; the caveat existing was the bug.
|
|
274
|
+
|
|
275
|
+
**What that evidence is about is the store, not the count.** A served page hands
|
|
276
|
+
its pass to the local pending store, which `spec-env review wait` watches; a
|
|
277
|
+
published page writes to the artifact's own store, which nothing here can see.
|
|
278
|
+
Two links into two stores asks the reader to know which door the run is standing
|
|
279
|
+
behind, and they cannot.
|
|
280
|
+
|
|
281
|
+
**Local and network are two doors into one room.** The page POSTs with
|
|
282
|
+
`fetch(location.pathname, …)`, so a page opened at `127.0.0.1:7760/…` and one
|
|
283
|
+
opened at `192.168.0.136:7760/…` reach the same server process and the same
|
|
284
|
+
pending store. One wait covers both, and a verdict pressed on either wakes the
|
|
285
|
+
same run. Between those two the objection does not apply — which is why both are
|
|
286
|
+
offered, and why offering them gives nothing up.
|
|
287
|
+
|
|
288
|
+
**So two things are required, and the second is what the old rule lacked.**
|
|
289
|
+
Every link is **labelled** with its tier, and one line says
|
|
290
|
+
**which tiers the wait covers**.
|
|
291
|
+
Two *unlabelled* links stay forbidden exactly as before, because
|
|
292
|
+
the reader still cannot tell them apart.
|
|
293
|
+
|
|
294
|
+
**`remote` keeps the caveat it always had.** It is listed so a reader off the
|
|
295
|
+
network knows the surface exists and what turns it on — never as a door the wait
|
|
296
|
+
is claimed to cover. Where it is on and published, its line says what is true of
|
|
297
|
+
it: *a verdict here needs `/spec-reviewed`*.
|
|
298
|
+
|
|
299
|
+
**Still forbidden**, in the words of the rule this amends: offering two links
|
|
300
|
+
into **different** stores without saying which one the wait is watching. That is
|
|
301
|
+
the failure that cost three unread verdicts, and nothing here touches it.
|
|
155
302
|
|
|
156
303
|
**This is not the old failure returning**, and the difference is the whole
|
|
157
304
|
justification. The offer used to be two quoted lines in the tail of a long
|
|
@@ -247,7 +394,7 @@ behind it — say nothing rather than reporting that there was nothing to report
|
|
|
247
394
|
| `Landed` | A fast-forward, a tag, a cherry-pick. |
|
|
248
395
|
| `Worktree` | A worktree provisioned, entered, or torn down. |
|
|
249
396
|
| `Untouched` | Uncommitted work the run deliberately left alone — whose, and how much. |
|
|
250
|
-
| `Review` | The rendered diff page: files, `+`/`−`, the
|
|
397
|
+
| `Review` | The rendered diff page: files, `+`/`−`, and the stack — the same tiers the banner lists, labelled, run together with `·` because a row is one cell, plus `live` where the engine reported one. **No question** — a row cannot be waited on, so a question in one is unanswerable by construction (see *asking implies waiting*). **Omitted entirely when the run is waiting on a verdict**: the banner after the block carries it instead, and a row saying the same thing beside it splits the reader's attention across two places. |
|
|
251
398
|
| `Follow-ups` | **Always.** `none`, or one line each. |
|
|
252
399
|
| `Next` | **Last.** The single next action for this work — runnable from the state the run leaves behind. |
|
|
253
400
|
|
|
@@ -311,10 +458,10 @@ fenced block **above** the table, where a fence means what a fence should mean:
|
|
|
311
458
|
|
|
312
459
|
| | |
|
|
313
460
|
|---|---|
|
|
314
|
-
| **Why** | 3 assertions fail in `
|
|
461
|
+
| **Why** | 3 assertions fail in `test_orders.py`; nothing committed |
|
|
315
462
|
| **Branch** | `spec/feat-foo` · 2 commits, dirty |
|
|
316
463
|
| **Built** | POST /orders handler, orders schema |
|
|
317
|
-
| **Tests** | 125 passed, 3 failed ·
|
|
464
|
+
| **Tests** | 125 passed, 3 failed · pytest |
|
|
318
465
|
| **Follow-ups** | none |
|
|
319
466
|
| **Next** | fix the failures, then `/spec-next` to finish phase 2 |
|
|
320
467
|
|
|
@@ -341,11 +488,16 @@ finish, so it outlives the session:
|
|
|
341
488
|
canonical port; not in scope here.
|
|
342
489
|
```
|
|
343
490
|
|
|
344
|
-
**
|
|
345
|
-
worktree, and a spec authored there physically
|
|
346
|
-
from the base branch, and cancelled along with its host
|
|
347
|
-
|
|
348
|
-
|
|
491
|
+
**The offer needs no caveat about where.** These skills run inside the spec's own
|
|
492
|
+
worktree, and a follow-up spec authored *there* would physically live on that
|
|
493
|
+
branch — invisible from the base branch, and cancelled along with its host. That
|
|
494
|
+
used to make the offer name the primary checkout as the place to write it.
|
|
495
|
+
It no longer does: `/spec` provisions the **new** spec's own worktree before it
|
|
496
|
+
writes anything and moves the session there, so the follow-up lands on its own
|
|
497
|
+
branch and its own ticket without anyone naming a location. Take the offer and
|
|
498
|
+
let `/spec` handle it. Where isolation is absent there is no worktree to move to,
|
|
499
|
+
and the old caveat applies — `spec-planning.md` and `commit-trailers.md` carry
|
|
500
|
+
the reasoning.
|
|
349
501
|
|
|
350
502
|
## Worked examples
|
|
351
503
|
|
|
@@ -357,7 +509,7 @@ cancelled. So the offer names the primary checkout as the place to write it.
|
|
|
357
509
|
|---|---|
|
|
358
510
|
| **Branch** | `spec/feat-foo` · 4 commits, clean |
|
|
359
511
|
| **Built** | Auth middleware, session table |
|
|
360
|
-
| **Tests** | 140 passed ·
|
|
512
|
+
| **Tests** | 140 passed · go test ./... |
|
|
361
513
|
| **Follow-ups** | Session expiry is read from two places; phase 4 leans on one |
|
|
362
514
|
| **Next** | `/spec-next` → phase 4 (Docs) |
|
|
363
515
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: no-spec
|
|
3
|
+
description: Do a piece of work that genuinely has no spec — a version bump, a lockfile refresh, a rename — on its own branch in its own worktree, reviewed on a page and landed on the verdict. Never on the base branch. Use when the user says "/no-spec", or asks for mechanical work that does not warrant a spec and should not sit on main.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /no-spec — work with no spec, off the base branch
|
|
7
|
+
|
|
8
|
+
> Stay silent while this runs — speak only to ask something you cannot answer
|
|
9
|
+
> yourself, or to report a failure at the moment it happens. Read
|
|
10
|
+
> `.claude/rules/spec-reports.md` before reporting; it defines the block this
|
|
11
|
+
> skill ends with.
|
|
12
|
+
|
|
13
|
+
Some work has no spec and should not have one. Bumping four projects to a new
|
|
14
|
+
version, refreshing a lockfile, a rename across a package: writing a one-phase
|
|
15
|
+
document for it produces a spec nobody reads, and `spec --quick` would have been
|
|
16
|
+
that under a friendlier name.
|
|
17
|
+
|
|
18
|
+
**What it is not is an excuse to work on the base branch.** Two things follow
|
|
19
|
+
from doing it there, and both cost someone else something: the tree is left
|
|
20
|
+
dirty, so every in-flight spec has to replay over it and a release cannot be
|
|
21
|
+
cut; and no page is ever rendered, so the work gets no review at all. This skill
|
|
22
|
+
is the same lane every spec uses — branch, worktree, page, verdict, land —
|
|
23
|
+
with the document left out because there is nothing to put in it.
|
|
24
|
+
|
|
25
|
+
**It writes no spec, moves nothing through the lifecycle, and mints no ticket.**
|
|
26
|
+
There is no bucket, no status, no phase index and no `Refs:` trailer. If you
|
|
27
|
+
find yourself wanting any of those, the work wanted `/spec`.
|
|
28
|
+
|
|
29
|
+
## 1. Name it
|
|
30
|
+
|
|
31
|
+
Take a kebab-case name from the invocation. It becomes the branch
|
|
32
|
+
(`chore/<name>`) and the worktree folder, so it should describe the work:
|
|
33
|
+
`bump-deps`, `rename-widget-props`, `lockfile-refresh`.
|
|
34
|
+
|
|
35
|
+
**Ask if none was given.** Do not invent one — a name nobody chose is a branch
|
|
36
|
+
nobody recognises a week later, and this is the one thing the skill cannot infer
|
|
37
|
+
from the work.
|
|
38
|
+
|
|
39
|
+
**Refuse a name that is already a spec**, which the engine does for you: two
|
|
40
|
+
things answering to one name is how a teardown removes the wrong tree.
|
|
41
|
+
|
|
42
|
+
## 2. Provision
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
skitterspec spec-env nospec <name>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
It records the name as a **specless branch** and prints the plan. Run the
|
|
49
|
+
commands it prints, then move this session into the worktree with a plain `cd`
|
|
50
|
+
— the Bash working directory persists between calls, so from here on the work
|
|
51
|
+
happens on its own branch.
|
|
52
|
+
|
|
53
|
+
**Confirm the move landed** rather than reading silence as success
|
|
54
|
+
(`.claude/rules/negative-checks.md` rule 1): `skitterspec spec-env resolve` with
|
|
55
|
+
no argument must name this branch, and report `no spec` as its bucket. If it
|
|
56
|
+
names something else, stop — say so and do nothing further, because the failure
|
|
57
|
+
this guards against is a session that writes a branch's worth of work into the
|
|
58
|
+
primary checkout while everything looks normal at the time.
|
|
59
|
+
|
|
60
|
+
**The record is not bookkeeping.** It is the only thing that makes a name with
|
|
61
|
+
nothing under `specs/**` resolvable, so without it `review`, `integrate`, `down`
|
|
62
|
+
and a bare `resolve` would all refuse this branch as a spec that does not exist.
|
|
63
|
+
|
|
64
|
+
**Where isolation is not configured** (`specs/.core/env.config.json` absent)
|
|
65
|
+
there is no worktree to make. Say so in one line and stop: this skill exists to
|
|
66
|
+
move work off the base branch, and without isolation there is nowhere to move it
|
|
67
|
+
to. Do not silently do the work in place — that is the outcome it exists to
|
|
68
|
+
prevent.
|
|
69
|
+
|
|
70
|
+
## 3. Do the work
|
|
71
|
+
|
|
72
|
+
Follow the project's rules in `.claude/rules/*.md` and `CLAUDE.md`, exactly as a
|
|
73
|
+
phase would. Tests are part of the work and not after it: extend or add whatever
|
|
74
|
+
covers the change, then run the project's typecheck and test commands. Do not
|
|
75
|
+
proceed to the page until they are green — and if they cannot be made green, say
|
|
76
|
+
so where it happens and report `❌`.
|
|
77
|
+
|
|
78
|
+
**Mechanical does not mean untested.** A version bump that breaks a build is the
|
|
79
|
+
commonest thing in this lane, which is why the gate is the same one a phase has.
|
|
80
|
+
|
|
81
|
+
## 4. Render the page and arm the gate
|
|
82
|
+
|
|
83
|
+
The work is done, the tests are green, and nothing is committed yet:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
skitterspec spec-env review <name> --buttons nospec --run-reviewers
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**This is free.** The engine reads git and splices text into a template; the
|
|
90
|
+
diff never passes through you however large it is.
|
|
91
|
+
|
|
92
|
+
`--buttons nospec` offers `Commit & Land` and `Commit`. It is its own set
|
|
93
|
+
because neither of the usual pairs fits: there is no next phase to continue and
|
|
94
|
+
nothing to put in flight.
|
|
95
|
+
|
|
96
|
+
**Then arm the gate:**
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
skitterspec spec-env review arm <name>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**This skill arms, and `/spec` does not.** That asymmetry is the rule in
|
|
103
|
+
`.claude/rules/spec-reports.md` rather than a choice made here: the gate asserts
|
|
104
|
+
that *finished work* owes an answer, and this is finished work. A written spec
|
|
105
|
+
owes no phase, so authoring arms nothing.
|
|
106
|
+
|
|
107
|
+
**Then offer `/spec-diff`. Do not run it.** The written review costs real tokens
|
|
108
|
+
because writing it means reading the diff, and that spend is the user's call.
|
|
109
|
+
|
|
110
|
+
## 5. Wait for the verdict
|
|
111
|
+
|
|
112
|
+
**The wait is a command. Do not write one.**
|
|
113
|
+
|
|
114
|
+
1. **Note the moment you start waiting**, as an ISO timestamp. That instant is
|
|
115
|
+
the whole scope of what you may claim.
|
|
116
|
+
2. **Run the engine's wait in the background, and end your turn:**
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
skitterspec spec-env review wait <name> --since <the timestamp>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Pass no timeout. A reader who walks away from a diff is the normal case, and
|
|
123
|
+
a bounded watch once lost a verdict to a lunch break.
|
|
124
|
+
3. **On waking, let the engine pick:**
|
|
125
|
+
|
|
126
|
+
**A watch that dies is re-armed on the same window**, silently and bounded by
|
|
127
|
+
the age of that window — `.claude/rules/spec-reports.md` carries the contract,
|
|
128
|
+
including when to stop and what the banner says instead. Do not restate it
|
|
129
|
+
here.
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
skitterspec spec-env review <name> --claim-since <the timestamp> --json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
It claims the one pass that arrived inside the window, acts on nothing when
|
|
136
|
+
none did, and refuses to choose when two did.
|
|
137
|
+
|
|
138
|
+
Relay the engine's **stack** — the `local:`, `network:` and `remote:` lines, all
|
|
139
|
+
three, in that order — never the bare `page:` path.
|
|
140
|
+
`.claude/rules/spec-reports.md` carries the shape and why every tier is named.
|
|
141
|
+
|
|
142
|
+
### Route on the verdict
|
|
143
|
+
|
|
144
|
+
- **`commit-land`** — hand off to `review.commitWith` (`/commit` by default),
|
|
145
|
+
then land it, then tear the worktree down:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
skitterspec spec-env integrate <name>
|
|
149
|
+
skitterspec spec-env down <name>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`integrate` plans a rebase onto the base branch and a `merge --ff-only`; run
|
|
153
|
+
the commands it prints. `down` removes the worktree, deletes the branch and
|
|
154
|
+
**forgets the specless record**, which is what stops a torn-down name going on
|
|
155
|
+
answering to every verb with a path that is no longer there.
|
|
156
|
+
|
|
157
|
+
**If the rebase conflicts, stop.** `git rebase --abort`, leave the commit on
|
|
158
|
+
the branch, tear nothing down, and report `❌` with the conflict — there is a
|
|
159
|
+
standing worktree, which is what separates `❌` from `⏸`.
|
|
160
|
+
|
|
161
|
+
- **`commit`** — the same commit, and **stop there**. The branch stands with the
|
|
162
|
+
work on it, which is the right ending for work that turned out to be bigger
|
|
163
|
+
than one sitting. Say in `Next` that `/spec-to-main` lands it later.
|
|
164
|
+
- **`changes`** — work the notes, record a resolution for each one so the next
|
|
165
|
+
render shows it struck through with what changed, then
|
|
166
|
+
**re-render and wait again**. The reader is still holding a decision.
|
|
167
|
+
- **`discuss`** — report and talk. Claim nothing, change nothing, tear nothing
|
|
168
|
+
down.
|
|
169
|
+
|
|
170
|
+
**Never tear the worktree down on anything but `commit-land`.** It is the only
|
|
171
|
+
verdict that says the work is finished, and the cost of being wrong is somebody
|
|
172
|
+
else's branch removed from disk.
|
|
173
|
+
|
|
174
|
+
## Report
|
|
175
|
+
|
|
176
|
+
End with the block defined in `.claude/rules/spec-reports.md`. That file carries
|
|
177
|
+
the shape; this section carries only what is specific here.
|
|
178
|
+
|
|
179
|
+
**Verdicts**
|
|
180
|
+
|
|
181
|
+
- `✅` — the work is done, the tests are green, and the verdict was acted on.
|
|
182
|
+
- `⚠️` — done and green, with something worth knowing.
|
|
183
|
+
- `❌` — the tests are red, or the land failed part-way. Quote the failure and
|
|
184
|
+
say what is standing.
|
|
185
|
+
- `⏸` — refused before acting: no name given, the name is already a spec, the
|
|
186
|
+
`cd` did not take, or the project has no isolation. Nothing changed.
|
|
187
|
+
|
|
188
|
+
**Fields:** `Branch` · `Built` · `Tests` · `Notes` · `Landed` · `Worktree` ·
|
|
189
|
+
`Review` · `Follow-ups` · `Next`
|
|
190
|
+
|
|
191
|
+
**No `Tracker` and no `Spec`, ever.** There is no ticket and no document, and a
|
|
192
|
+
row saying so would report an absence with nothing behind it — which
|
|
193
|
+
`spec-reports.md` forbids for exactly this reason.
|
|
194
|
+
|
|
195
|
+
`Landed` and `Worktree` appear only once a verdict has been acted on; a run
|
|
196
|
+
waiting on the page has neither, and **omits the `Review` row** in favour of the
|
|
197
|
+
banner, which carries the counts, the stack and the two exits:
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## ⏸ Review ready — <N> files, +<a> −<d>
|
|
202
|
+
|
|
203
|
+
- **local** — <the `local:` URL>
|
|
204
|
+
- **network** — <the `network:` URL, or off with the command that turns it on>
|
|
205
|
+
- **remote** — <the `remote:` URL, or off with the command that turns it on>
|
|
206
|
+
|
|
207
|
+
I'm holding here until you send a verdict — the wait covers local and network.
|
|
208
|
+
|
|
209
|
+
`Commit & Land` finishes it · `Commit` keeps the branch
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
There `Next` names the page rather than a command, because the button is what
|
|
214
|
+
carries the work on.
|
|
215
|
+
|
|
216
|
+
**`Follow-ups` is where a spec gets offered.** This lane is for work with no
|
|
217
|
+
spec, so the thing it most often surfaces is work that *does* want one. Offer to
|
|
218
|
+
`/spec` it on the spot — and `/spec` provisions its own worktree, so there is
|
|
219
|
+
no caveat about where to write it.
|