@skitterbyte/skitterspec 20.0.0 → 22.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.
@@ -154,6 +154,24 @@ Before writing any code for this phase, get the workspace clean:
154
154
  being *"I am moving on"*, which is what keeps this a push rather than a wall —
155
155
  a gate with no exit gets switched off wholesale instead of answered.
156
156
 
157
+ - **Report anything left waiting, and claim none of it.** Ask the engine once:
158
+
159
+ ```
160
+ skitterspec spec-env review waiting
161
+ ```
162
+
163
+ A pass listed here arrived when nothing was watching — a wait that never ran,
164
+ a session cleared, a terminal closed overnight — and no watcher can recover
165
+ those, however good. Relay what it prints: the spec, the code, the verdict and
166
+ the age, with `/spec-reviewed <code>` to pick one up and `--drop <code>` to
167
+ disown it.
168
+
169
+ **It is information, not a gate.** It never refuses, nothing here is
170
+ conditional on it, and **you never claim one** — `/spec-diff` §0 stands
171
+ unchanged, and a pass sitting there when you arrived was not sent to you.
172
+ Silent when nothing is waiting, which is the usual case: say nothing rather
173
+ than reporting that there was nothing to report.
174
+
157
175
  ## 3. Implement the phase
158
176
 
159
177
  Identify the **first unfinished phase** from the `00-overview.md` phase index,
@@ -269,6 +287,12 @@ skitterspec spec-env review <spec>
269
287
  the diff never passes through you, so a 266KB patch costs nothing. Report the
270
288
  path it prints and move on.
271
289
 
290
+ **This render takes the committing button set**, which is the default — so
291
+ `--buttons` is not passed. That is a statement about the work, not about the
292
+ gate: the phase is finished, so `Commit` and `Commit & Continue` are the right
293
+ verbs for it. A render part-way through a run takes `--buttons midrun` and
294
+ offers `Continue` instead; `/spec-diff` owns that case.
295
+
272
296
  **Then arm the gate**, so the phase now owes a verdict:
273
297
 
274
298
  ```
@@ -293,41 +317,72 @@ so one subject lives in one place:
293
317
 
294
318
  ## ⏸ Review ready — <N> files, +<a> −<d>
295
319
 
296
- **[Open the page](<the `open:` URL>)** · I'm holding here until you send a verdict.
320
+ - **local** <the `local:` URL>
321
+ - **network** — <the `network:` URL, or off with the command that turns it on>
322
+ - **remote** — <the `remote:` URL, or off with the command that turns it on>
297
323
 
298
- `/spec-reviewed` picks it up · `spec-env review skip "<reason>"` moves on
324
+ <the `live:` line, exactly as the engine printed it omitted when it printed none>
299
325
 
300
- **One link, and the engine has already chosen it.** Where it served, the
301
- banner carries the served URL and the wait is real. Where it could not serve —
302
- a busy port, a machine with no network address — that is the case publishing
303
- exists for, and then the banner carries the published URL with what is true of
304
- it: *press a verdict, then type `/spec-reviewed`*, because nothing pushes from
305
- the artifact store into this conversation.
326
+ I'm holding here until you send a verdict the wait covers local and network.
306
327
 
307
- **Never offer both.** Publishing while the server is reachable adds a second
308
- door the reader cannot tell apart from the first, and the wait only stands
309
- behind one of themthat was done, and three verdicts were pressed on the
310
- published page while each sat unread under a line saying I was holding. The
311
- published page is for the reader the server cannot reach, and for nobody
312
- else.
328
+ `/spec-reviewed` picks it up · `spec-env review skip "<reason>"` moves on
329
+
330
+ **The stack is the engine's copy it, do not compose it.** `spec-env review`
331
+ printed one line per tier, in that order, and `--json` carries the same thing as
332
+ `tiers`. Relay all three whatever they say, including the ones that are off with
333
+ the command that turns them on: a reader who has left the house cannot ask for a
334
+ remote page they were never shown.
335
+
336
+ **Do not pick one for them.** The engine used to, and the guess failed three
337
+ separate ways in one day. `.claude/rules/spec-reports.md` carries the shape and
338
+ why the *one link, never two* rule now reads
339
+ **one link per reachable store, each labelled** —
340
+ local and network are two doors into one room, so the wait
341
+ covers both. `remote` is a second store, so its own line carries its own caveat:
342
+ *a verdict here needs `/spec-reviewed`*, because nothing pushes from
343
+ the artifact store into this conversation. Never let the holding line promise a
344
+ wait over that tier.
345
+
346
+ **Publishing is still never yours to do.** `remote` reading `off` is the normal
347
+ state, and the fix for it is the command on that line — typed by the operator,
348
+ or pressed on the page, because a published page is one this tooling cannot
349
+ remove and permitting it is not publishing it.
350
+
351
+ **The `live:` line goes with the stack**, and it is the engine's line too —
352
+ copied as printed, and **absent when the engine printed none**. The page can act
353
+ on it: a press puts the spec live or takes it down and hands the reader back the
354
+ same page, which is `/spec-diff` §2b's routing and not this skill's. What
355
+ matters here is that an action **never clears the gate this phase armed** — the
356
+ reader has looked at it running and concluded nothing, so the phase still owes a
357
+ verdict.
313
358
 
314
359
  ---
315
360
 
316
- **Where you are not waiting, it stays the `Review` row** — the counts, the page
317
- link and a question, in one row:
361
+ **Where you are not waiting, it stays the `Review` row** — the counts and the
362
+ page link, and **no question**:
363
+
364
+ | **Review** | <N> files, +<a> −<d> · **local** <URL> · **network** <URL> · **remote** off |
318
365
 
319
- | **Review** | <N> files, +<a> −<d> · [open the page](<the `open:` URL>) want a written review before you commit? |
366
+ At the end of a phase you are always waiting, so this shape belongs to the
367
+ renders that are not this step: a mid-phase `/spec-diff`, a page produced
368
+ alongside other work. A row cannot be waited on, so a question in one is
369
+ unanswerable however findable it is.
320
370
 
321
371
  **Both shapes are addressed to someone, and that is the constraint.** The offer
322
372
  was once a fenced block of engine output: two quoted lines under the test
323
373
  counts, addressed to nobody, with the report then closing on *"commit this
324
374
  first"* — the last instruction the reader got was to move on, so they did. A row
325
- in a labelled table is findable; a question in it is answerable; a banner says
326
- the work has stopped. What must never come back is something unaddressed,
327
- unfindable, or fenced.
375
+ in a labelled table is findable; a banner says the work has stopped. What must
376
+ never come back is something unaddressed, unfindable, or fenced.
377
+
378
+ **The row asks nothing, and that is not a weakening of the above.** A row cannot
379
+ be waited on, so a question in one is unanswerable however findable it is —
380
+ which is the failure `spec-reports.md` records under *asking implies waiting*.
381
+ The row names the page; the banner is what asks, because the banner is the shape
382
+ the run is standing behind.
328
383
 
329
384
  **Never bury it and never split it.** The row sits above the last two rows of
330
- the block, and the page and the question stay in the same row; the banner
385
+ the block, and the page and its counts stay in the same row; the banner
331
386
  replaces the row rather than joining it. Two places naming one page make the reader
332
387
  resolve a distinction before acting on either — which is the same failure
333
388
  whether the two places are adjacent rows or a row and a banner.
@@ -336,16 +391,25 @@ whether the two places are adjacent rows or a row and a banner.
336
391
 
337
392
  The row is findable, but a row cannot make the continuation follow from the
338
393
  reading — and that is the gap the whole gate exists to close.
339
- **Where this harness can watch a file and wake the session on a change, use it.** The pass
340
- arrives at the engine's holding area, the watch fires, and the verdict the
341
- reader pressed is what carries the work on.
394
+
395
+ **The wait is a command. Do not write one.**
342
396
 
343
397
  1. **Note the moment you start waiting**, as an ISO timestamp. That instant is
344
398
  the whole scope of what you may claim.
345
- 2. **Watch the pending store** for the spec
346
- `.spec-env/reviews/<spec>.pending.json` in the primary checkout — and
347
- **end your turn**. Do not poll, and do not hold the turn open: the point is that
348
- the reader has the terminal back while they read.
399
+ 2. **Run the engine's wait in the background, and end your turn:**
400
+
401
+ ```
402
+ skitterspec spec-env review wait <spec> --since <the timestamp>
403
+ ```
404
+
405
+ It returns when a pass arrives inside that window, and
406
+ **it takes no timeout unless you pass one** —
407
+ the wait lasts as long as your session, because a reader who walks away from
408
+ a diff is the normal case rather than the edge one. Do not give it a duration
409
+ of your own.
410
+
411
+ Then **end your turn**. Do not poll it and do not hold the turn open: the
412
+ point is that the reader has the terminal back while they read.
349
413
  3. **On waking, let the engine pick**:
350
414
 
351
415
  ```
@@ -353,11 +417,26 @@ reader pressed is what carries the work on.
353
417
  ```
354
418
 
355
419
  It claims the one pass that arrived inside the window, and acts on nothing
356
- at all when none did (the watch can fire on a write that was not a pass) or
357
- when two did (two sittings, or two people — the operator has the codes).
420
+ at all when none did (the wait can be woken by something that was not a
421
+ pass) or when two did (two sittings, or two people — the operator has the
422
+ codes).
358
423
  4. **Route on the verdict** exactly as `/spec-diff` §2 and §4 describe. Do not
359
424
  restate that routing here.
360
425
 
426
+ **WHY A COMMAND RATHER THAN A LOOP YOU COMPOSE.** This step used to say "watch
427
+ the pending store" and stop, so every run invented its own watcher in shell —
428
+ and three failed in two days, each reaching the operator as *"I pressed the
429
+ button and nothing happened"*. The worst wrote
430
+ `until [ -f "$P" ] && [ "$x" \> "$y" ]`: valid bash, a syntax error in zsh, a
431
+ predicate that could never be true. It spun for five minutes writing to a
432
+ stderr nobody reads.
433
+
434
+ **The bug is not the lesson — the silence is.** A watcher that can never fire
435
+ and one patiently working are indistinguishable from outside, so nothing about
436
+ that run looked wrong until the operator asked. `review wait` says it has
437
+ started, is written once, and is tested against a store that gains a pass
438
+ mid-flight. A predicate composed fresh each time is proven by nothing.
439
+
361
440
  **WHY THIS IS SAFE, AND WHAT IT COSTS.** It was once true that a device
362
441
  reaching your page could not reach your conversation, and that fact was the
363
442
  whole guard: a pass sat in the holding area until a person typed
@@ -371,46 +450,52 @@ is that the page can now act, so the token has become a credential rather than
371
450
  a convenience — and `--claim-since` refusing to choose between two passes is
372
451
  what stops a race becoming a wrong commit.
373
452
 
374
- **Where the harness cannot watch a file, change nothing.** The `Review` row and
375
- `/spec-reviewed` are the whole story, exactly as before. The gate still holds
376
- either way: it is the engine's, not the watch's.
453
+ **Where the harness cannot run something in the background, you still wait**
454
+ the turn ending is the wait. Say the page is rendered and that you are holding
455
+ for the pass, then end your turn; the reader's next message is what carries it,
456
+ and `/spec-diff` picks it up from the paste exactly as it always has. The gate
457
+ holds either way: it is the engine's, not the wait's.
458
+
459
+ This once read *"change nothing"* — keep the row, keep the question, do not
460
+ wait — and that exemption is the hatch a whole class of unanswerable questions
461
+ came through. Every harness can end a turn.
377
462
 
378
463
  **It still does not break a chained run.** `/commit && /spec-next` is typed as
379
464
  one line; by the time this step is reached the chain has finished, so waiting
380
465
  here stops nothing that was still going to happen.
381
466
 
382
- Relay the **`open:`** line the engine prints, not the bare path: a path is not
383
- clickable in any terminal, and a page nobody can open is a page nobody reads.
467
+ Relay the engine's **stack** the `local:`, `network:` and `remote:` lines
468
+ never the bare `page:` path: a path is not clickable in any terminal, and a page
469
+ nobody can open is a page nobody reads.
384
470
 
385
471
  - **Never write the review unasked**, and **never publish**. Publishing leaves
386
472
  something behind that this tooling cannot remove, so it is always something
387
473
  someone asks for. A `file://` link is no use on a phone, and saying so **is**
388
474
  the ask — publishing is the answer to it, and `/spec-diff` §6 owns how.
389
- **Follow the `reader:` line the engine printed do not sniff for it.** It
390
- answers where the person reading this is sitting, and the offer changes with it:
391
-
392
- - **absent** (`unknown`) the `file://` URL, exactly as always. **Do not warn:**
393
- unknown is the ordinary state of a local machine, and a warning there is an
394
- accusation against a healthy session.
395
- - **`local`** the `file://` URL.
396
- - **`remote`** — the engine has already stood its local server up and put a URL
397
- the reader can open on `open:`. So there is **nothing special to say**: relay
398
- that line like any other. Any `also:` lines under it are the other addresses
399
- this machine has, offered because the best-guess one can be wrong — pass them
400
- on rather than editing them out.
401
-
402
- **Never read an environment variable to decide this** not `SSH_CONNECTION`,
403
- not `CLAUDE_CODE_*`, not a tty check. The engine did it, reports it on that line
404
- and in `--json`, and a second implementation here could not be tested and would
405
- drift.
406
-
407
- **Serving is the engine's to do; publishing is never.** A `remote` reader
408
- authorises a local serverone process, ended by one flag, leaving nothing
409
- behind and authorises nothing else. A reader the server CAN reach is not a
410
- reason to publish as well: the page they can already open is the page to name. Publishing leaves a page this tooling
411
- cannot remove, so it stays an ask in every case, always. If the engine could not
412
- serve (a busy port, a machine with no network address) it falls back to the
413
- `file://` URL with its marker, and that is when publishing is worth naming.
475
+ **The `reader:` line no longer decides anything here, and that is the point.**
476
+ It is still printed, and it is still the only place that question is answered —
477
+ but the offer does not change with it, because the stack lists every tier
478
+ whatever it says. Three reader states used to mean three different offers, and
479
+ that branching is exactly what produced a `file://` page on a session detected
480
+ `unknown`, a LAN URL for a phone off the network, and an address that changed
481
+ underneath a reader when detection flipped mid-session.
482
+
483
+ So: **relay all three tier lines, every time.** Any `also:` lines sit under
484
+ `network` the other addresses this machine has, offered because the
485
+ best-guess one can be wrong — so pass them on rather than editing them out.
486
+
487
+ **Never read an environment variable to decide anything about the offer** — not
488
+ `SSH_CONNECTION`, not `CLAUDE_CODE_*`, not a tty check. There is nothing left
489
+ here for a detection to decide, and a second implementation of one could not be
490
+ tested and would drift.
491
+
492
+ **Serving is the engine's to do; publishing is never.** The server is one
493
+ process, ended by one flag, leaving nothing behind, and `review.allowNetwork`
494
+ decides whether it binds wide no detection involved. A reader the server CAN
495
+ reach is not a reason to publish as well: the tiers they can already open are on
496
+ the stack. Publishing leaves a page this tooling cannot remove, so it stays an
497
+ ask in every case, always which is why `remote` shows the command rather than
498
+ a URL until someone types it.
414
499
 
415
500
  - **Never fatal.** A failed render — no worktree, a git error — is one line and
416
501
  the phase is still done. The page is a convenience; the repo is the record.
@@ -102,6 +102,67 @@ resolve it by reading the code, do that instead of asking.
102
102
 
103
103
 
104
104
 
105
+ ## 4b. Hand the refresh back on a page, then wait
106
+
107
+ **Only when the project has per-spec isolation** (`specs/.core/env.config.json`
108
+ present) **and this review actually changed something.** Either missing → skip
109
+ the whole step in silence.
110
+
111
+ A refreshed spec is a rewrite of a document someone is about to work from, so it
112
+ gets read before it is committed — the same ending `/spec` now has:
113
+
114
+ ```
115
+ skitterspec spec-env review <spec> --docs --buttons refresh
116
+ ```
117
+
118
+ `--docs` reads the spec's own documents from the tree you are standing in, so it
119
+ wants no worktree and works for a spec in any bucket. These documents are
120
+ **tracked**, so the diff against `HEAD` is a patch rather than a set of new
121
+ files — which is exactly what the reader wants here: what drifted, and what you
122
+ rewrote.
123
+
124
+ **Render nothing when nothing changed.** `/spec-review` frequently concludes a
125
+ spec is still accurate, and that is a success rather than a gap. A page showing
126
+ an empty diff under a commit button asks for a verdict on nothing, and the
127
+ engine refuses it for the same reason — `nothing to review`. Take that refusal
128
+ as the answer and report the `⏸`/`✅` you already had.
129
+
130
+ **Arm nothing.** No `review arm` here: the gate asserts that a phase which ended
131
+ owes an answer, and a re-validated spec has ended no phase. Walking away leaves
132
+ an uncommitted spec, which is the state this skill has always finished in.
133
+
134
+ ### The three endings
135
+
136
+ `--buttons refresh` offers `Commit`, `Request changes` and `Discuss`.
137
+
138
+ **No start verdict, deliberately.** The spec this skill refreshed may already be
139
+ in progress — that is half of what it is used for — so `Commit & Start` would
140
+ offer to provision a worktree for a spec that already has one.
141
+
142
+ - **`commit`** — hand off to `review.commitWith` (`/commit` by default) with the
143
+ pathspec the render reported on `docs.paths`, then finish. The spec keeps
144
+ whatever status step 4 left it in.
145
+ - **`changes`** — work the notes into the spec, record a resolution for each so
146
+ the next render strikes it through with what changed, re-render, and wait
147
+ again.
148
+ - **`discuss`** — report and talk. Claim nothing, change nothing.
149
+
150
+ ### Then wait for it
151
+
152
+ **The wait is a command. Do not write one.** Note the moment you start waiting
153
+ as an ISO timestamp, run the engine's wait in the background, and end your turn:
154
+
155
+ ```
156
+ skitterspec spec-env review wait <spec> --since <the timestamp>
157
+ ```
158
+
159
+ Pass no timeout. On waking, let the engine pick the pass —
160
+ `skitterspec spec-env review <spec> --docs --claim-since <the timestamp> --json`
161
+ — and route on the verdict above.
162
+
163
+ **Where the page is `file://`** the pass is copied and pasted, so the wait is the
164
+ turn ending and the banner says so. Do not start a watch that cannot fire.
165
+
105
166
  ## 5. Report
106
167
 
107
168
  Do **not** `git commit` unless the user asks.
@@ -122,6 +183,32 @@ the shape; this section carries only what is specific here.
122
183
  API that moved, a task the code already does. `Spec` carries the status the
123
184
  review leaves it in, which is the answer to "can I start this?".
124
185
 
186
+ **Where step 4b rendered a page the run is waiting**, so the block omits the
187
+ `Review` row and ends on the banner from `.claude/rules/spec-reports.md` — the
188
+ tier stack copied from the engine's own lines, never one link chosen for the
189
+ reader:
190
+
191
+ ---
192
+
193
+ ## ⏸ Review ready — &lt;N&gt; files, +&lt;a&gt; −&lt;d&gt;
194
+
195
+ - **local** — &lt;the `local:` URL&gt;
196
+ - **network** — &lt;the `network:` URL, or off with the command that turns it on&gt;
197
+ - **remote** — &lt;the `remote:` URL, or off with the command that turns it on&gt;
198
+
199
+ I'm holding here until you send a verdict — the wait covers local and network.
200
+
201
+ `Commit` commits the refresh · `Request changes` works them now
202
+
203
+ ---
204
+
205
+ `Next` then names the page rather than a command, because the button is what
206
+ carries the work on.
207
+
208
+ Where nothing was rendered — no isolation, or no drift to show — `Next` is
209
+ `/commit, then /spec-start <name>`, since this skill does not commit and
210
+ `/spec-start` refuses a tree holding anything that is not the spec's.
211
+
125
212
  **Drift found and not fixed is a `Follow-up`, not a silence.** A spec this skill
126
213
  declared reviewed is one nobody will re-read; something it noticed and left
127
214
  undone has to leave the session in writing or it did not happen.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spec-reviewed
3
- description: Pick up the review you approved on the page — run it bare to pick up the single waiting pass, paste the six-digit code off the page ("/spec-reviewed 608223") to name one exactly, and be asked which only when two are waiting. Use when the user says "/spec-reviewed", "I approved it", "I've reviewed it", "pick up my review", "I pressed approve", or otherwise says they have finished reviewing a rendered diff.
3
+ description: Pick up the review you approved on the page — run it bare to pick up the single waiting pass, paste the six-digit code off the page ("/spec-reviewed 608223") to name one exactly, or pass the verdict itself ("/spec-reviewed commit") when the page could not send and copied you a command instead. Use when the user says "/spec-reviewed", "I approved it", "I've reviewed it", "pick up my review", "I pressed approve", or otherwise says they have finished reviewing a rendered diff.
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
@@ -70,16 +70,42 @@ Several provisioned and none resolved is a refusal — relay its list and stop,
70
70
  never pick from it. See `.claude/rules/spec-planning.md`; do not restate the
71
71
  rule here.
72
72
 
73
- **Three argument shapes, and they cannot collide.** A **six-digit code**
74
- matches `^\d{6}$`; a **tracker id** carries a letter and a hyphen; a
75
- **spec name** is neither. So the parse needs no flag, and nothing has to be
76
- guessed at from context.
73
+ **Four argument shapes, and they cannot collide.** A **six-digit code**
74
+ matches `^\d{6}$`; a **verdict** is one of a closed list of six words;
75
+ a **tracker id** carries a letter and a hyphen;
76
+ a **spec name** is none of them and always carries a lifecycle prefix
77
+ (`feat-`, `bug-`, `hotfix-`), which no verdict does. So the parse needs no flag,
78
+ and nothing has to be guessed at from context.
77
79
 
78
80
  A **six-digit code** is a pass the operator read off their own page. It says
79
81
  **which pass**, not which spec — so resolve the spec exactly as a bare
80
82
  invocation does, above, and claim the code *there*. Then go to step 4 — a named
81
83
  pass has nothing to disambiguate.
82
84
 
85
+ A **verdict word** — `commit`, `commit-continue`, `commit-start`, `continue`,
86
+ `changes`, `discuss` — is the conclusion itself, arriving without a pass behind
87
+ it. It is
88
+ what a **`file://` page** hands over: that page has no server to POST to and no
89
+ store to write to, so it copies a command instead of sending anything, and this
90
+ is the command. Resolve the spec as a bare invocation does, then send the word
91
+ through the engine:
92
+
93
+ ```
94
+ skitterspec spec-env review <spec> --verdict <word>
95
+ ```
96
+
97
+ It joins the same merge a claimed pass goes through, so the routing in step 4
98
+ is unchanged: a commit over open notes is refused exactly as it would be, the
99
+ outcome log records it, and the gate a phase armed is cleared. Then go to step
100
+ 4 — there is nothing to disambiguate.
101
+
102
+ **A word carries a verdict and nothing else**, and that is a property of the
103
+ transport, not a shortcut. Accepts and comments do not fit on a command line,
104
+ so the page only ever offers the words while the reader has marked nothing —
105
+ the moment they tick an accept or write a note it goes back to handing over the
106
+ blob. If someone tells you they marked things up *and* gives you a word, ask
107
+ for the pass: the word would land a verdict with their notes silently dropped.
108
+
83
109
  A **name** targets that spec instead. A **tracker id** does too, but only
84
110
  through a **provider seam**: the base knows nothing about tracker ids, so
85
111
  resolve one by asking whichever provider is installed for its listing —
@@ -268,6 +268,25 @@ here beyond knowing it is no longer dead code.
268
268
  A spec ideally arrives `Ready` from `/spec`; a `Draft` works too — sanity-check
269
269
  it is well-formed first.
270
270
 
271
+ - **Report anything left waiting, and claim none of it.** Ask the engine once:
272
+
273
+ ```
274
+ skitterspec spec-env review waiting
275
+ ```
276
+
277
+ A pass listed here arrived when nothing was watching — a wait that never ran,
278
+ a session cleared, a terminal closed overnight — and no watcher can recover
279
+ those, however good. Relay what it prints: the spec, the code, the verdict and
280
+ the age, with `/spec-reviewed <code>` to pick one up and `--drop <code>` to
281
+ disown it.
282
+
283
+ **It is information, not a gate.** It never refuses, nothing here is
284
+ conditional on it, and **you never claim one** — `/spec-diff` §0 stands
285
+ unchanged, and a pass sitting there when you arrived was not sent to you.
286
+ Silent when nothing is waiting, which is the usual case: say nothing rather
287
+ than reporting that there was nothing to report.
288
+
289
+
271
290
  ## 4b. Note a missing gating decision (only if configured)
272
291
 
273
292
  **Only when `specs/.core/gating.config.json` exists.** Run
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skitterbyte/skitterspec",
3
- "version": "20.0.0",
3
+ "version": "22.0.0",
4
4
  "description": "Spec-driven development for Claude Code \u2014 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",