@skitterbyte/skitterspec-linear 11.0.0 → 12.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.
@@ -153,9 +153,12 @@ that header — must exist **before** `spec-env up`:
153
153
  -b hotfix/<slug> <tag>` command (the branch forks from **the tag**, not
154
154
  `main`), the worktree path, the opener, and any `in the worktree, run:`
155
155
  bootstrap steps.
156
- - Run the printed `git worktree add`. **The worktree is checked out at the tag,
157
- so your uncommitted stub doesn't travel with it** move it across so `main`
158
- stays pristine. **Create the destination bucket first:**
156
+ - Run the printed `git worktree add`, then **move the stub across yourself.**
157
+ This is where a hotfix differs from `/spec-bug`, which no longer needs the move:
158
+ that skill's worktree forks from `main`, so committing the stub puts it there,
159
+ while **this worktree is checked out at the tag** — a commit on `main` is not in
160
+ it and never will be. The move is not redundant here; keep it.
161
+ **Create the destination bucket first:**
159
162
 
160
163
  ```
161
164
  mkdir -p <worktreePath>/specs/in-progress
@@ -164,14 +167,13 @@ that header — must exist **before** `spec-env up`:
164
167
 
165
168
  The `mkdir -p` is not belt-and-braces. Git does not store empty directories, so
166
169
  `specs/in-progress/` is **absent** from the worktree whenever nothing was in
167
- progress at that point in history — and here that point is an **old release
168
- tag**, where it is absent more often than not. `mv` into a missing destination
169
- renames your spec folder **to** `specs/in-progress`, silently: the spec's files
170
- end up one level too high, `00-overview.md` sits where the bucket should be, and
171
- every later step still appears to work until something cannot find the spec.
172
- Confirm the result before carrying on — you want
173
- `<worktreePath>/specs/in-progress/hotfix-<name>/00-overview.md`.
174
- - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
170
+ progress at that point in history — and here that point is an
171
+ **old release tag**, where it is absent more often than not. `mv` into a
172
+ missing destination renames your spec folder **to** `specs/in-progress`,
173
+ silently: the spec's files end up one level too high, `00-overview.md` sits
174
+ where the bucket should be, and every later step still appears to work until
175
+ something cannot find the spec. Confirm the result before carrying on — you
176
+ want `<worktreePath>/specs/in-progress/hotfix-<name>/00-overview.md`. - **Bootstrap the worktree.** A fresh worktree has no installed dependencies and
175
177
  none of the repo's gitignored files (`.env`, local overrides). Run the printed
176
178
  `in the worktree, run:` steps (file seeding, then `setup`) in order, before
177
179
  anything else.
@@ -213,6 +215,8 @@ is usually a single-pass fix, so the `## Fix` block can live directly in
213
215
  > **Base version:** <tag prod is running, e.g. v33.16.4>
214
216
  > **Raised:** <YYYY-MM-DD (today)>
215
217
  > **Area:** <files/modules>
218
+ > **Gating:** <pre-filled "none: hotfix — restoring released behaviour"; only
219
+ > when release gating is configured, and overridable — see below>
216
220
 
217
221
  ## Symptom
218
222
 
@@ -357,6 +361,21 @@ say so in one line — *"project picker unavailable"* — and carry on with
357
361
  If `linear.projectId` is set but that Project is archived or missing, relay
358
362
  Linear's error and stop rather than silently minting an unparented issue.
359
363
 
364
+ ### Release gating (only when configured)
365
+
366
+ **Only when `specs/.core/gating.config.json` exists.** A hotfix is the one spec
367
+ type that does **not** ask the question cold: it writes
368
+ `none: hotfix — restoring released behaviour` and asks only for confirmation.
369
+
370
+ The default differs on purpose. A hotfix restores behaviour a release already
371
+ had, under time pressure, and the fix is captured by a deploy tag rather than
372
+ riding the next release — so a flag has nothing to gate and nothing to roll back
373
+ to. Making someone answer a design question mid-incident buys nothing.
374
+
375
+ It is a **default, not a rule**: say what you are writing and let the user
376
+ override it. If they name a flag, record that instead. Skip entirely when the
377
+ config is absent.
378
+
360
379
  ## 6. Drive to GREEN
361
380
 
362
381
  - Implement the **minimal, root-cause** fix on the branch. Match surrounding code;
@@ -37,6 +37,19 @@ checkout you are already in; one spec at a time, no hand-off). It is a question
37
37
  about how the operator works, not about what the repo contains, so ask rather
38
38
  than infer it from whether dev servers or Docker are configured.
39
39
 
40
+ ## 0b. Release gating (optional, and separate)
41
+
42
+ Ask whether specs should record a **release-gating** decision — does this change
43
+ ship behind a feature flag, or land live? Adopting it copies
44
+ `specs/.core/gating.config.json.example` → `gating.config.json` and sets
45
+ `guidance` to wherever this project documents its flags.
46
+
47
+ It is **orthogonal to isolation**: a project can adopt either, both, or neither.
48
+ Skitterspec never learns how the flags work — it asks the question, cites that
49
+ path, and records the answer on each spec. Leave it off and nothing appears:
50
+ no question, no header, no check. Off is a perfectly good answer for a project
51
+ that does not use flags.
52
+
40
53
  ## 1. Folders
41
54
 
42
55
  Create any that are missing; drop a `.gitkeep` into ones that would otherwise be
@@ -80,8 +93,8 @@ Ensure it exists. If missing, create it documenting:
80
93
  - the **Author** / **Developer** header fields;
81
94
  - the **State log** audit table (folder/status transitions), kept separate from
82
95
  the **Changelog** (decisions);
83
- - the project's concrete typecheck/test commands, and the rule that **every
84
- phase ends with creating + running tests**.
96
+ - the project's concrete typecheck/test commands, and the rule that
97
+ **every phase ends with creating + running tests**.
85
98
 
86
99
  Read a sibling spec skill (e.g. `spec`, `spec-next`) for the canonical shapes
87
100
  rather than inventing them. If the rule already exists, leave it unless stale.
@@ -198,6 +198,31 @@ project's own, so ask rather than guess.
198
198
  the workspace — that report is the evidence the setup is right, so don't
199
199
  paraphrase it into "done".
200
200
 
201
+ ## 8b. Let `/spec-start` commit the snapshot with its spec
202
+
203
+ **Only when `specs/.core/env.config.json` exists** (per-spec isolation is on). If
204
+ it is absent, skip this — there is nothing to configure.
205
+
206
+ `/spec-start` commits an uncommitted spec for you, but only the paths it can
207
+ prove belong to that spec. Its own folder always does; this repo's per-spec
208
+ Linear snapshot (`sync.baseDir`, `specs/.core/linear-base/<ID>.base.json`) does
209
+ not, because the base engine is deliberately tracker-free and cannot know that
210
+ path exists. Declare it once, in `env.config.json`:
211
+
212
+ ```json
213
+ "spec": {
214
+ "companionPaths": ["specs/.core/linear-base/{identifier}.base.json"]
215
+ }
216
+ ```
217
+
218
+ `{identifier}` resolves through `branch.identifierField`, so **set that too** if
219
+ it is still empty — `"linear_identifier"` is the field `/spec` stamps. Without
220
+ it the pattern expands to nothing and the snapshot is treated as another spec's
221
+ file: `/spec-start` then refuses the tree instead of committing it, which is the
222
+ safe failure but a needless one.
223
+
224
+ Leave both alone if the user has already set them.
225
+
201
226
  ## 9. Report and hand off
202
227
 
203
228
  **Finish by checking, not by describing.** First write down what the MCP server
@@ -254,12 +279,12 @@ more detail if you need it. If the key is missing, tell the user to run this
254
279
  skitterspec spec-sync credentials set
255
280
  ```
256
281
 
257
- **Do not ask the user to paste an API key into this conversation, and do not
258
- offer to store one for them.** A key pasted into a chat enters the transcript,
259
- is sent to the model, and may be logged — moving where a key is stored is
260
- pointless if it travels through the conversation to get there. Your job is to
261
- confirm the setup is ready and name the command; the value is theirs alone. The
262
- key is optional: without one, pushes go over MCP.
282
+ **Do not ask the user to paste an API key into this conversation, and do not offer to store one for them.**
283
+ A key pasted into a chat enters the transcript, is sent to the model, and may
284
+ be logged — moving where a key is stored is pointless if it travels through the
285
+ conversation to get there. Your job is to confirm the setup is ready and name
286
+ the command; the value is theirs alone. The key is optional: without one,
287
+ pushes go over MCP.
263
288
 
264
289
  Mention what setup did **not** configure, so the defaults aren't mistaken for
265
290
  decisions: phase mapping (`mapping.phases` — sub-issue per phase by default) and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spec-next
3
- description: Build the next unfinished phase of the spec currently in flight on this checkout — pre-flight, implement with tests, record progress and refresh the tracker. Refuses when no spec is in flight rather than guessing one. Use when the user says "/spec-next", "build the next phase", "continue the spec", or "carry on with this spec".
3
+ description: Build the next unfinished phase of the spec in flight for this session — pre-flight, implement with tests, record progress and refresh the tracker. Refuses when no spec is in flight rather than guessing one, and never builds a spec it is not standing in. Use when the user says "/spec-next", "build the next phase", "continue the spec", or "carry on with this spec".
4
4
  ---
5
5
 
6
6
  # /spec-next — build the next phase of the spec in flight
@@ -26,7 +26,7 @@ Resolve **in this order**, and stop at the first that answers:
26
26
  branch the checkout is on names the spec.
27
27
 
28
28
  **If none answers, refuse and stop:**
29
- `no spec in flight — run /spec-start <name> to put one on this checkout`.
29
+ `no spec in flight — run /spec-start <name> to start one`.
30
30
 
31
31
  **Never fall back to the spec "in context".** A spec discussed in conversation
32
32
  is not a spec in flight, and this skill writes real code: building the wrong
@@ -5,16 +5,15 @@ description: Push a spec up to its linked Linear issue (repo → Linear, one-way
5
5
 
6
6
  # /spec-push — send a spec up to Linear (one-way)
7
7
 
8
- Repo → Linear. The repo is the **source of truth**; Linear is a **generated
9
- mirror**. A spec is a Linear **issue**; each phase is a **sub-issue** (a child
10
- issue), and the phase file is mirrored into that sub-issue's description as
11
- written — its prose, its sections, and its tasks as a read-only checklist, never
12
- as issues of their own. Only the phase's h1 and `> **Status:**` line are left
13
- out, because both are pushed as fields of their own (the sub-issue's title and
14
- state). This skill
15
- computes what changed since the last push and applies it — it never reads Linear
16
- content back or merges. A person editing the mirror in Linear will see it
17
- overwritten on the next push.
8
+ Repo → Linear. The repo is the **source of truth**; Linear is a
9
+ **generated mirror**. A spec is a Linear **issue**; each phase is a
10
+ **sub-issue** (a child issue), and the phase file is mirrored into that
11
+ sub-issue's description as written — its prose, its sections, and its tasks as
12
+ a read-only checklist, never as issues of their own. Only the phase's h1 and
13
+ `> **Status:**` line are left out, because both are pushed as fields of their
14
+ own (the sub-issue's title and state). This skill computes what changed since
15
+ the last push and applies it — it never reads Linear content back or merges. A
16
+ person editing the mirror in Linear will see it overwritten on the next push.
18
17
 
19
18
  **Opt-in**: only runs when `specs/.core/linear.config.json` exists. If absent,
20
19
  tell the user how to enable Linear sync and stop.
@@ -190,10 +189,10 @@ skitterspec spec-sync verify <spec> --stored <file>
190
189
 
191
190
  It compares against what the engine sent, ignoring the reformatting Linear
192
191
  legitimately applies (renumbered ordered lists, `-`→`*`, collapsed table
193
- separators, checkbox case, whitespace) and reporting only lost or altered **word
194
- characters**. Relay any divergence — it prints both sides around the first
195
- difference. It exits 0 either way: the repo is unaffected and still correct, so
196
- this is a warning, not a failure.
192
+ separators, checkbox case, whitespace) and reporting only lost or altered
193
+ **word characters**. Relay any divergence — it prints both sides around the
194
+ first difference. It exits 0 either way: the repo is unaffected and still
195
+ correct, so this is a warning, not a failure.
197
196
 
198
197
  This is **not a pull**. Nothing read here is merged, stamped, or written
199
198
  anywhere; the repo remains the only source of truth. Do it before step 5 so a
@@ -44,6 +44,19 @@ trust the spec's own wording — verify:
44
44
  - **Backward compatibility.** Re-confirm the planned API/schema changes are still
45
45
  additive/safe given the current code (see the project's compatibility rules).
46
46
 
47
+ ### Release gating (only when configured)
48
+
49
+ **Only when `specs/.core/gating.config.json` exists.** Run
50
+ `skitterspec gating check <spec>`. A spec it names has no recorded gating
51
+ decision — or a bare `none` that records nothing — and that is
52
+ **drift like any other**: the question was never asked, or its answer was lost. Grill for it in
53
+ step 3 and write the header in step 4, exactly as you would a stale file path.
54
+
55
+ **This check is advisory.** It reports; it never refuses, and nothing below is
56
+ conditional on it. A spec written before the project adopted gating has no header
57
+ and is not broken — turning this into a gate would accuse the very specs the
58
+ feature was designed not to disturb.
59
+
47
60
  ## 3. Grill only where a decision is needed
48
61
 
49
62
  Where the drift forces a choice (the old approach no longer fits, a referenced
@@ -54,12 +67,12 @@ resolve it by reading the code, do that instead of asking.
54
67
 
55
68
  ## 4. Update the spec
56
69
 
57
- - Rewrite stale **Decisions** / **Solution overview** and refresh the **Impact
58
- map** in `00-overview.md`, and stale **tasks** in the phase files, so they
59
- match the current code and the resolved questions. Add/remove tasks within a phase file; add a new phase by
60
- creating a `0N-<slug>.md` file **and** a matching overview index row, or drop a
61
- dead phase by removing both. Keep the index and files in sync; **preserve
62
- completed `[x]` history**.
70
+ - Rewrite stale **Decisions** / **Solution overview** and refresh the
71
+ **Impact map** in `00-overview.md`, and stale **tasks** in the phase files,
72
+ so they match the current code and the resolved questions. Add/remove tasks
73
+ within a phase file; add a new phase by creating a `0N-<slug>.md` file
74
+ **and** a matching overview index row, or drop a dead phase by removing both.
75
+ Keep the index and files in sync; **preserve completed `[x]` history**.
63
76
  - **A phase's status is the `⬜`/`🔄`/`✅` on its H1** — `# Phase 2 — <goal> 🔄`.
64
77
  It is mirrored in that file's `> **Status:**` line and in the matching
65
78
  `00-overview.md` phase-index row, but the **heading is the authoritative one**:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spec-start
3
- description: Put a spec in flight on this checkout — provision its branch, move it to in-progress, refresh the tracker, then build phase 1. Refuses unless the checkout is on the base branch with nothing already in flight, so it never parks or swaps someone's unfinished work. Use when the user says "/spec-start", "start this spec", or "begin implementing <spec>".
3
+ description: Put a spec in flight — provision its branch, move it to in-progress, refresh the tracker, then build phase 1. Commits the spec itself when that is all that is uncommitted, and refuses to touch anyone else's unfinished work. Use when the user says "/spec-start", "start this spec", or "begin implementing <spec>".
4
4
  ---
5
5
 
6
6
  # /spec-start — put a spec in flight
@@ -12,30 +12,49 @@ finishing it is `/spec-complete`.
12
12
 
13
13
  ## 1. The gate — refuse unless the workbench is free
14
14
 
15
- **Check this first, before resolving anything or touching a file.** In
16
- `worktree` mode run `skitterspec spec-env live status`; in `checkout` mode read
17
- the current branch. The workbench must be:
15
+ **Check this first, before resolving anything or touching a file.** What the
16
+ gate demands depends on the mode, because the two modes hold work in different
17
+ places read `mode` from `specs/.core/env.config.json` (default `worktree`).
18
18
 
19
- - **on the base branch** (`main`, or the configured `baseBranch`), and
20
- - **clean** no uncommitted changes.
19
+ **`worktree` mode the tree must be clean, and that is all.** The spec is built
20
+ in its own worktree, so another spec being in flight is not a conflict; it is the
21
+ parallelism the mode exists for. The only requirement is that this checkout has
22
+ no uncommitted work — *except* the spec you are starting, which `spec-env up`
23
+ commits for you (see below). Nothing is switched here and nothing is parked.
21
24
 
22
- **If it isn't, relay what is in flight and stop.** Name the spec holding the
23
- checkout and the three ways out, then end your turn:
25
+ **`checkout` mode the workbench must be free**: on the base branch (`main`, or
26
+ the configured `baseBranch`) and clean, since the branch is built right here and
27
+ this mode holds one spec at a time. If it isn't, relay what is in flight and
28
+ stop — name the spec holding the checkout and the two ways out, then end your
29
+ turn:
24
30
 
25
31
  - **`/spec-complete`** — it's finished; land it and free the workbench.
26
32
  - **`/spec-cancel`** — it isn't wanted; record why and free the workbench.
27
- - **`/spec-live main`** *(worktree mode)* — park it: the branch goes back to its
28
- worktree and stays exactly as it is, ready to resume later.
29
33
 
30
- **Never get past the gate yourself.** Do not stash, do not commit on the
31
- operator's behalf, do not `/spec-live main` for them, do not switch branches. An
32
- uncommitted tree, a half-built phase and a rebase are each a decision someone
33
- must make deliberately — and the cost of guessing is another spec's work moved
34
- without its author asking. A refusal costs one command; the alternative can cost
35
- an afternoon.
34
+ **Never get past the gate yourself.** Do not stash, do not commit
35
+ **another spec's** work, do not switch branches for them. An uncommitted tree
36
+ and a half-built phase are each a decision someone must make deliberately — and
37
+ the cost of guessing is another spec's work moved without its author asking. A
38
+ refusal costs one command; the alternative can cost an afternoon.
36
39
 
37
- A dirty tree is refused *with the same words whatever the cause*: the gate does
38
- not try to judge whether the changes look important.
40
+ **The one exception is the spec you are starting.** `spec-env up` classifies the
41
+ uncommitted tree against the target spec and answers one of three ways — relay
42
+ what it says rather than deciding for yourself:
43
+
44
+ | What it found | What it does |
45
+ |---------------|--------------|
46
+ | clean | provisions, as always |
47
+ | every path belongs to this spec | plans `git add` + `git commit` **first**, then the fork |
48
+ | any path does not | refuses, naming the paths that disqualified it |
49
+
50
+ That is membership in an exactly-known set — the spec's own folder plus the
51
+ project's `spec.companionPaths` — and **not** a judgement about whether the
52
+ changes look important. The gate still never decides that. When it plans the
53
+ commit, the paths are printed above the commands, so run them as printed; when it
54
+ refuses, relay the reason and stop.
55
+
56
+ It also refuses a **clean** tree whose spec is not in the commit the worktree
57
+ would fork from — otherwise you get a branch missing the very spec it is for.
39
58
 
40
59
  ## 2. Identify the spec
41
60
 
@@ -48,51 +67,88 @@ not try to judge whether the changes look important.
48
67
  spec is a `<name>/` folder whose entry point is `00-overview.md`, with one
49
68
  file per phase beside it (`01-<slug>.md`, `02-…`). Legacy specs may be a bare
50
69
  `<name>.md`, or a `00-overview.md` with inline phases — handle those too.
51
- - A spec already in `specs/in-progress/` was started before. If its branch is
52
- parked in a worktree, this skill brings it back into flight; say so rather
53
- than reporting a fresh start.
54
-
55
- ## 3. Put its branch in this checkout
70
+ - A spec already in `specs/in-progress/` was started before. Its worktree
71
+ probably still exists, so this is a re-attach: say so rather than reporting a
72
+ fresh start, and skip the housekeeping that is already done.
56
73
 
57
- **Read `mode` from `specs/.core/env.config.json`** (default `worktree`).
74
+ ## 3. Build its branch
58
75
 
59
76
  ### `worktree` mode
60
77
 
61
78
  1. **Provision.** Run `skitterspec spec-env up <name>` — a planner, so run the
62
- `to provision, run:` commands it prints and confirm they succeeded. Then run
63
- its **`then, in the worktree, run:`** steps in order (file seeding, then
64
- `setup`): a fresh worktree has no dependencies and none of the repo's
65
- gitignored files, so hooks, typechecks and tests fail until they are there.
66
- 2. **Bring the branch here.** Tell the user to type **`/spec-live <name>`** it
67
- rebases the branch, frees it from the worktree and checks it out in this
68
- checkout, which is what makes this session the workbench. It is a user-only
69
- command, so you cannot run it: print it, end your turn, and pick up at step 4
70
- when they re-run `/spec-start`.
71
- **Already here?** If the live check in step 1 showed this spec live, or the
72
- branch is already checked out, the move is done carry straight on.
73
- 3. **A spec the live overlay refuses** a hotfix, a stateful spec
74
- (`Stack: worktree + docker`), or a branch touching migrations — **parks
75
- instead.** Do the housekeeping in step 4 with `git -C <worktreePath>`, run
76
- `open.command` if configured, print the worktree path, and say to run
77
- `/spec-next` from a session there. Relay the engine's refusal reason as it
78
- printed it; those guards protect a shared dev instance and are not yours to
79
- weaken.
80
- **Trust the worktree first.** `spec-env up` wrote the printed `trusted:` root
81
- into `.claude/settings.local.json`, but that file will not hot-reload in this
82
- session — run `/add-dir <trusted root>` before editing into the worktree, or
83
- the first write prompts.
79
+ `to provision, run:` commands it prints and confirm they succeeded, **except**
80
+ the `open.command` line, which belongs to the hand-off in 3 below.
81
+
82
+ 2. **Enter the worktree — this session, no new window.** The spec is built in its
83
+ worktree; that is what the mode is for, and it is why `main` stays free and
84
+ several specs run at once. So put *this* session there rather than opening
85
+ another one: call **`EnterWorktree`** with the worktree path.
86
+
87
+ **Do it immediately after `git worktree add`, before bootstrap and before the step 4 housekeeping.**
88
+ Once the session is the worktree, `setup` runs in place and the housekeeping
89
+ is plain `git` the `cd` and the `git -C <worktreePath>` prefix both
90
+ disappear. **Never `cd` into the worktree first:** `EnterWorktree` refuses a
91
+ path that is already the working directory
92
+ (`is the current working directory`), so a bootstrap `cd` does not merely
93
+ make the call redundant, it makes it fail.
94
+
95
+ Then run the planner's **`then, in the worktree, run:`** steps in order (file
96
+ seeding, then `setup`) — a fresh worktree has no dependencies and none of the
97
+ repo's gitignored files, so hooks, typechecks and tests fail until they are
98
+ there. Do the step 4 housekeeping, then say to run **`/spec-next`**, here.
99
+
100
+ **Do not move the branch into this checkout**, and do not ask the operator to.
101
+ Entering the worktree is the opposite of moving the branch out of it — the
102
+ branch never leaves. `/spec-live` is for testing a finished-enough spec on the
103
+ already-running dev server; it is not the way work gets started, and reaching
104
+ for it here is what used to split a start across two invocations.
105
+
106
+ 3. **When you cannot enter, hand off as before.** Two cases, and
107
+ **decide from cwd before calling**, not by calling and catching — an error
108
+ surfaced mid-skill reads as a bug, and both conditions are knowable in
109
+ advance:
110
+
111
+ - **This session's cwd is already inside a worktree.** `EnterWorktree` only
112
+ allows a worktree→worktree switch when the target lives under
113
+ `.claude/worktrees/`, and a project's worktree root usually does not
114
+ (`../{repo}-wt` is the shipped shape). Do not "fix" this by relocating the
115
+ root: starting a spec from the base branch is the documented path anyway.
116
+ - **`EnterWorktree` is unavailable** — a harness without it. There is no CLI
117
+ counterpart to fall back on, so the skill degrades rather than fails.
118
+
119
+ On either, do exactly what this skill did before: bootstrap with
120
+ `cd "<worktreePath>"`, housekeep with `git -C <worktreePath>`, run
121
+ `open.command` if one is configured, print the worktree path, and say to run
122
+ **`/spec-next`** from a session in it.
123
+ **Trust the worktree first** on this path: `spec-env up` wrote the printed
124
+ `trusted:` root into `.claude/settings.local.json`, but that file will not
125
+ hot-reload in this session — run `/add-dir <trusted root>` before editing into
126
+ the worktree, or the first write prompts. (Entering the worktree makes both
127
+ moot: the writes are then in-cwd.)
128
+
129
+ `EnterWorktree` is gated on being told to work in a worktree by the user or by
130
+ project instructions. A lifecycle skill directing it **is** project
131
+ instruction, so the call is in contract here.
132
+
133
+ **`/spec-next` is unchanged by this.** Its rule 2 — "the worktree you are
134
+ standing in" — is what answers once the session has actually moved; nothing about
135
+ its resolution is loosened, and it must not be. The refusal exists so the wrong
136
+ branch is never built.
84
137
 
85
138
  ### `checkout` mode
86
139
 
87
140
  Run `skitterspec spec-env up <name>` and the single `git switch` it prints.
88
- There is no worktree, no bootstrap, no live step — the checkout is already the
141
+ There is no worktree, no bootstrap and no hand-off — the checkout is already the
89
142
  workbench. Its planner enforces the same gate from the engine side, so relay any
90
143
  refusal and stop.
91
144
 
92
145
  ## 4. Move the spec into development
93
146
 
94
- On the branch, in this checkout (or via `git -C <worktreePath>` for a parked
95
- spec):
147
+ **Do this before you report anything**, so no path can end with a provisioned
148
+ worktree and a spec still reading `Ready` in `specs/backlog/`. Having entered the
149
+ worktree (step 3.2) this is plain `git` — you are standing in it. On the hand-off
150
+ path (step 3.3) run it against the worktree with `git -C <worktreePath>` instead;
151
+ in `checkout` mode the branch is already here.
96
152
 
97
153
  - `git mv "specs/backlog/<name>" "specs/in-progress/<name>"` if it isn't there
98
154
  already (`mkdir -p specs/in-progress` first). Use `git mv` to keep history.
@@ -107,6 +163,17 @@ spec):
107
163
  A spec ideally arrives `Ready` from `/spec`; a `Draft` works too — sanity-check
108
164
  it is well-formed first.
109
165
 
166
+ ## 4b. Note a missing gating decision (only if configured)
167
+
168
+ **Only when `specs/.core/gating.config.json` exists.** Run
169
+ `skitterspec gating check <name>` and, if it names this spec, mention it **once**
170
+ before phase 1 starts — the cheapest moment to decide is before any code exists.
171
+
172
+ **This check is advisory.** It reports; it never refuses, and nothing below is
173
+ conditional on it. A spec written before the project adopted gating has no header
174
+ and is not broken — turning this into a gate would accuse the very specs the
175
+ feature was designed not to disturb.
176
+
110
177
  ## 5. Bring the spec's dev servers up — confirm before heavy steps
111
178
 
112
179
  **Only when the project configures host dev servers** (`env.config.json` → a
@@ -121,10 +188,23 @@ invoke it yourself.
121
188
 
122
189
  ## 6. Build phase 1
123
190
 
124
- **Carry straight on into `/spec-next`** in this session: it marks phase 1
125
- started, refreshes the mirror again, builds it with tests and reports. Do not
126
- stop and ask the operator to run it the workbench is set up and they asked to
127
- start the spec.
191
+ **`checkout` mode — carry straight on into `/spec-next`** in this session: it
192
+ marks phase 1 started, refreshes the mirror again, builds it with tests and
193
+ reports. Do not stop and ask the operator to run it: the branch is here and they
194
+ asked to start the spec.
195
+
196
+ **`worktree` mode — the spec is built in its worktree**, and step 3.2 put this
197
+ session there, so end by saying the worktree path is now the session's and to run
198
+ **`/spec-next`** here. On the hand-off path (step 3.3) the session did not move:
199
+ say so plainly, print the path, and tell them to run `/spec-next` from a session
200
+ in it.
201
+
202
+ `/spec-next` resolves the spec it is *standing in* — the live spec of the
203
+ checkout, the worktree its cwd is inside, or the branch in `checkout` mode — and
204
+ a name argument narrows a re-run rather than selecting a spec elsewhere. That
205
+ refusal is deliberate: building the wrong spec's phase writes commits on a branch
206
+ nobody asked for. **Do not work around it**, and do not offer to build the phase
207
+ from here.
128
208
 
129
209
  ## Opt-outs
130
210
 
@@ -142,10 +142,10 @@ pnpm exec skitterspec-linear spec-sync released [<range>] [--json]
142
142
  ```
143
143
 
144
144
  `ref` prints the ticket for the branch you are on, so a commit can carry
145
- `Refs: <KEY-N>` — see `.claude/rules/commit-trailers.md`. **Off a spec branch, or
146
- on a spec that is not linked, it prints nothing and exits non-zero.** That is the
147
- correct answer, not an error to work around: do not invent a ref, and never write
148
- `Refs: none`.
145
+ `Refs: <KEY-N>` — see `.claude/rules/commit-trailers.md`.
146
+ **Off a spec branch, or on a spec that is not linked, it prints nothing and exits non-zero.**
147
+ That is the correct answer, not an error to work around: do not invent a ref,
148
+ and never write `Refs: none`.
149
149
 
150
150
  `released` reports the tickets in a commit range — by default since the most
151
151
  recent tag, and it always prints the range it chose so a wrong default is
@@ -170,9 +170,9 @@ the report saying which commits it set aside.
170
170
  pnpm exec skitterspec-linear spec-sync retarget [--yes]
171
171
  ```
172
172
 
173
- Renaming a Linear team rewrites the key in every issue identifier, and **nothing
174
- in the repo moves**: the frontmatter stamps, the config `teamKey`, and the
175
- snapshot filenames and their sub-issue keys all keep the old prefix, so
173
+ Renaming a Linear team rewrites the key in every issue identifier, and
174
+ **nothing in the repo moves**: the frontmatter stamps, the config `teamKey`,
175
+ and the snapshot filenames and their sub-issue keys all keep the old prefix, so
176
176
  `/spec-push` starts failing with `no Linear issue found for SKI-7`.
177
177
 
178
178
  `retarget` detects the rename (the team id survives it; the key does not) and
@@ -8,9 +8,9 @@ disable-model-invocation: true
8
8
 
9
9
  The **intermediate** landing. `/spec-complete` also lands the branch, but then
10
10
  verifies every phase, flips the status to Complete, `git mv`s the spec to
11
- `complete/`, and tears the environment down. **`/spec-to-main` stops after the
12
- land**: the worktree stays, the spec stays `In Progress`, and you can land again
13
- as you add commits.
11
+ `complete/`, and tears the environment down.
12
+ **`/spec-to-main` stops after the land**: the worktree stays, the spec stays
13
+ `In Progress`, and you can land again as you add commits.
14
14
 
15
15
  Use it when a later phase can only be done *after* the current work is on `main` —
16
16
  e.g. it needs to run in CI, a deploy pipeline, or a shared test environment that
@@ -19,9 +19,9 @@ the remaining phases with `/spec-next` and eventually `/spec-complete`.
19
19
 
20
20
  It reuses the **same engine** as `/spec-complete`'s landing (`spec-env integrate`
21
21
  — rebase + fast-forward), so it produces identical linear history. Because a
22
- fast-forward leaves `base == branch`, the operation is **idempotent and
23
- repeatable**: new commits put the branch ahead of base again, and you can run
24
- `/spec-to-main` as many times as you like.
22
+ fast-forward leaves `base == branch`, the operation is
23
+ **idempotent and repeatable**: new commits put the branch ahead of base again,
24
+ and you can run `/spec-to-main` as many times as you like.
25
25
 
26
26
  ## 0. Preconditions — when this applies
27
27
 
@@ -58,10 +58,10 @@ primary checkout is dirty, or if a *different* spec holds it (release that one w
58
58
 
59
59
  ## 3. Tests must be green before landing
60
60
 
61
- Don't push red to `main`. Run the project's typecheck and test commands **in the
62
- worktree**; the suite must be **green**. For a **Bug** spec, confirm the
63
- originally-failing test now passes. If anything is red, stop and report — landing
64
- broken code onto `main` defeats the purpose.
61
+ Don't push red to `main`. Run the project's typecheck and test commands
62
+ **in the worktree**; the suite must be **green**. For a **Bug** spec, confirm
63
+ the originally-failing test now passes. If anything is red, stop and report —
64
+ landing broken code onto `main` defeats the purpose.
65
65
 
66
66
  (Note this is the *worktree* suite. The whole point of this skill is often to run
67
67
  a *further* check that only exists on `main` / in CI — that one runs **after** the
@@ -69,8 +69,8 @@ land, in step 5.)
69
69
 
70
70
  ## 4. Land — rebase + fast-forward
71
71
 
72
- Run `skitterspec spec-env integrate <name>` and run the printed commands **in
73
- order**:
72
+ Run `skitterspec spec-env integrate <name>` and run the printed commands
73
+ **in order**:
74
74
 
75
75
  - `git -C <worktree> rebase <base>` — replay the branch onto base.
76
76
  - `git -C <mainRepoPath> merge --ff-only <branch>` — fast-forward base.
@@ -91,8 +91,8 @@ and continue — the branch has no commits base doesn't already have.
91
91
  `- <YYYY-MM-DD> — Landed intermediate work onto <base> to <run CI / deploy to
92
92
  test env / …>; spec stays In Progress.`
93
93
  - Do **NOT**: add a State-log row (status doesn't change), flip any phase/status
94
- to Complete, `git mv` the spec, or tear down the worktree/stack. **The spec
95
- stays `In Progress` and the worktree stays put.**
94
+ to Complete, `git mv` the spec, or tear down the worktree/stack.
95
+ **The spec stays `In Progress` and the worktree stays put.**
96
96
  - Report: the base branch, the fast-forward result, and the green base test. It
97
97
  **never pushes** — mention the user can `git push` the base branch themselves to
98
98
  trigger CI / the shared env.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skitterbyte/skitterspec-linear",
3
- "version": "11.0.0",
3
+ "version": "12.0.0",
4
4
  "description": "Spec-driven development for Claude Code, with one-way Linear sync — a superset of @skitterbyte/skitterspec: the base filesystem workflow plus /spec-status · /spec-push and the spec-sync CLI. The repo is canonical; Linear is a generated mirror. Install this OR the base, not both.",
5
5
  "keywords": [
6
6
  "claude",