@skitterbyte/skitterspec-jira 0.0.0-stage → 2.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.
Files changed (113) hide show
  1. package/MIGRATION.md +1266 -0
  2. package/README.md +44 -2
  3. package/assets/claude-md-section.md +85 -0
  4. package/assets/commands/allow-main.md +33 -0
  5. package/assets/commands/spec-connect.md +13 -0
  6. package/assets/commands/spec-live.md +14 -0
  7. package/assets/commands/spec-remote-review.md +37 -0
  8. package/assets/commands/spec-skip.md +24 -0
  9. package/assets/core/SETUP.md +192 -0
  10. package/assets/core/env.config.json.example +56 -0
  11. package/assets/core/env.config.md +606 -0
  12. package/assets/core/gating.config.json.example +4 -0
  13. package/assets/core/gating.config.md +81 -0
  14. package/assets/core/jira.config.json.example +18 -0
  15. package/assets/core/jira.config.md +88 -0
  16. package/assets/hooks/main-guard.cjs +162 -0
  17. package/assets/hooks/review-gate.cjs +146 -0
  18. package/assets/review/page.html +3384 -0
  19. package/assets/rules/commit-trailers.md +96 -0
  20. package/assets/rules/negative-checks.md +69 -0
  21. package/assets/rules/offered-unblocks.md +100 -0
  22. package/assets/rules/spec-planning.md +702 -0
  23. package/assets/rules/spec-reports.md +572 -0
  24. package/assets/skills/no-spec/SKILL.md +249 -0
  25. package/assets/skills/spec/SKILL.md +714 -0
  26. package/assets/skills/spec-bug/SKILL.md +585 -0
  27. package/assets/skills/spec-cancel/SKILL.md +261 -0
  28. package/assets/skills/spec-complete/SKILL.md +451 -0
  29. package/assets/skills/spec-diff/SKILL.md +870 -0
  30. package/assets/skills/spec-hotfix/SKILL.md +607 -0
  31. package/assets/skills/spec-init/SKILL.md +178 -0
  32. package/assets/skills/spec-jira-setup/SKILL.md +221 -0
  33. package/assets/skills/spec-list/SKILL.md +173 -0
  34. package/assets/skills/spec-next/SKILL.md +678 -0
  35. package/assets/skills/spec-push/SKILL.md +306 -0
  36. package/assets/skills/spec-review/SKILL.md +256 -0
  37. package/assets/skills/spec-reviewed/SKILL.md +284 -0
  38. package/assets/skills/spec-start/SKILL.md +496 -0
  39. package/assets/skills/spec-status/SKILL.md +114 -0
  40. package/assets/skills/spec-sync/SKILL.md +220 -0
  41. package/assets/skills/spec-to-main/SKILL.md +141 -0
  42. package/bin/skitterspec-jira.js +68 -0
  43. package/package.json +40 -4
  44. package/src/cli.js +5967 -0
  45. package/src/deprecate.js +138 -0
  46. package/src/env/bootstrap.js +188 -0
  47. package/src/env/building.js +143 -0
  48. package/src/env/classify.js +176 -0
  49. package/src/env/commitcmd.js +108 -0
  50. package/src/env/config.js +850 -0
  51. package/src/env/dev.js +63 -0
  52. package/src/env/glob.js +34 -0
  53. package/src/env/hooks.js +226 -0
  54. package/src/env/hotfix.js +413 -0
  55. package/src/env/hotfixland.js +302 -0
  56. package/src/env/integrate.js +167 -0
  57. package/src/env/live.js +479 -0
  58. package/src/env/mainguard.js +299 -0
  59. package/src/env/provision.js +466 -0
  60. package/src/env/proxy.js +225 -0
  61. package/src/env/prune.js +119 -0
  62. package/src/env/registry.js +159 -0
  63. package/src/env/render.js +17 -0
  64. package/src/env/resolve.js +716 -0
  65. package/src/env/review.js +2622 -0
  66. package/src/env/reviewers/coderabbit.js +228 -0
  67. package/src/env/reviewers.js +517 -0
  68. package/src/env/serve.js +1044 -0
  69. package/src/env/supervise.js +157 -0
  70. package/src/env/teardown.js +248 -0
  71. package/src/env/trust.js +87 -0
  72. package/src/gating.js +155 -0
  73. package/src/init.js +1150 -0
  74. package/src/lines-diff.js +114 -0
  75. package/src/prompts.js +129 -0
  76. package/src/vendor/jira/adf.js +414 -0
  77. package/src/vendor/jira/api.js +295 -0
  78. package/src/vendor/jira/cli-sync.js +1252 -0
  79. package/src/vendor/jira/commands.js +44 -0
  80. package/src/vendor/jira/config.js +286 -0
  81. package/src/vendor/jira/credentials.js +108 -0
  82. package/src/vendor/jira/dialect.js +45 -0
  83. package/src/vendor/jira/mcp.js +129 -0
  84. package/src/vendor/provider-kit/index.js +41 -0
  85. package/src/vendor/provider-kit/src/adapter.js +23 -0
  86. package/src/vendor/provider-kit/src/apply.js +207 -0
  87. package/src/vendor/provider-kit/src/args.js +68 -0
  88. package/src/vendor/provider-kit/src/assignment.js +277 -0
  89. package/src/vendor/provider-kit/src/config.js +251 -0
  90. package/src/vendor/provider-kit/src/credentials.js +404 -0
  91. package/src/vendor/provider-kit/src/doctor.js +35 -0
  92. package/src/vendor/provider-kit/src/http.js +63 -0
  93. package/src/vendor/provider-kit/src/identity.js +93 -0
  94. package/src/vendor/provider-kit/src/list-assignee.js +71 -0
  95. package/src/vendor/provider-kit/src/list-rows.js +35 -0
  96. package/src/vendor/provider-kit/src/md-compare.js +39 -0
  97. package/src/vendor/provider-kit/src/md-tables.js +94 -0
  98. package/src/vendor/provider-kit/src/prompt.js +50 -0
  99. package/src/vendor/provider-kit/src/released.js +219 -0
  100. package/src/vendor/provider-kit/src/specs.js +248 -0
  101. package/src/vendor/provider-kit/src/transport.js +22 -0
  102. package/src/vendor/sync-core/index.js +92 -0
  103. package/src/vendor/sync-core/src/base.js +81 -0
  104. package/src/vendor/sync-core/src/compare.js +338 -0
  105. package/src/vendor/sync-core/src/dialect.js +51 -0
  106. package/src/vendor/sync-core/src/fields.js +36 -0
  107. package/src/vendor/sync-core/src/legacy.js +100 -0
  108. package/src/vendor/sync-core/src/normalize.js +971 -0
  109. package/src/vendor/sync-core/src/push.js +85 -0
  110. package/src/vendor/sync-core/src/retarget.js +278 -0
  111. package/src/vendor/sync-core/src/task-block.js +308 -0
  112. package/src/vendor/sync-core/src/verify.js +67 -0
  113. package/src/vendor/sync-core/src/write.js +191 -0
@@ -0,0 +1,496 @@
1
+ ---
2
+ name: spec-start
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
+ ---
5
+
6
+ # /spec-start — put a spec in flight
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
+ One checkout, one spec in flight. This skill is how a spec gets there:
14
+ provision, move it to `in-progress`, refresh the tracker, then hand straight on
15
+ to `/spec-next` for phase 1. Continuing a spec afterwards is `/spec-next`;
16
+ finishing it is `/spec-complete`.
17
+
18
+ ## 1. The gate — what each mode demands of the tree
19
+
20
+ **Check this first, before resolving anything or touching a file.** What the
21
+ gate demands depends on the mode, because the two modes hold work in different
22
+ places — read `mode` from `specs/.core/env.config.json` (default `worktree`).
23
+
24
+ **`worktree` mode — there is no tree gate.** The spec is built in its own
25
+ worktree, so neither another spec being in flight nor its uncommitted files are a
26
+ conflict; both are the parallelism the mode exists for. `git worktree add`
27
+ carries nothing and forks from a commit, and the one thing this run writes into
28
+ the checkout — the spec's own commit, which `spec-env up` plans for you — names
29
+ its paths on both the `add` and the `commit`, so it cannot reach a file that is
30
+ not this spec's. Work belonging to someone else is **reported and left alone**,
31
+ never a refusal. Nothing is switched here and nothing is parked.
32
+
33
+ **`checkout` mode — the workbench must be free**: on the base branch (`main`, or
34
+ the configured `baseBranch`) and clean, since the branch is built right here and
35
+ this mode holds one spec at a time. If it isn't, relay what is in flight and
36
+ stop — name the spec holding the checkout and the two ways out, then end your
37
+ turn:
38
+
39
+ - **`/spec-complete`** — it's finished; land it and free the workbench.
40
+ - **`/spec-cancel`** — it isn't wanted; record why and free the workbench.
41
+
42
+ **Never get past the gate yourself.** Do not stash, do not commit
43
+ **another spec's** work, do not switch branches for them. An uncommitted tree
44
+ and a half-built phase are each a decision someone must make deliberately — and
45
+ the cost of guessing is another spec's work moved without its author asking. A
46
+ refusal costs one command; the alternative can cost an afternoon.
47
+
48
+ **What `spec-env up` does with the tree**, in both modes — relay what it says
49
+ rather than deciding for yourself:
50
+
51
+ | What it found | `worktree` | `checkout` |
52
+ |---------------|-------------|-------------|
53
+ | clean | provisions | provisions |
54
+ | every path is this spec's | commits those paths **first**, then forks | same, then switches |
55
+ | some path is not | commits this spec's, provisions, **reports the rest** | refuses, naming them |
56
+
57
+ That is membership in an exactly-known set — the spec's own folder plus the
58
+ project's `spec.companionPaths` — and **not** a judgement about whether the
59
+ changes look important. It never decides that.
60
+
61
+ **The last row is the only real difference, and it is mechanical.**
62
+ `git switch -c` carries the working tree onto the new branch, so in
63
+ `checkout` mode a colleague's files really would be moved without them asking.
64
+ `git worktree add` carries nothing, so in `worktree` mode the same files are
65
+ simply not this run's business — and refusing over them fired on the commonest
66
+ tree this workflow produces: a second spec authored while the first is still
67
+ uncommitted. When it reports them, say how many and whose in the `Untouched` row
68
+ and **keep the verdict `✅`** — nothing went wrong.
69
+
70
+ When it plans the commit, the paths are printed above the commands, so run them
71
+ as printed; when it refuses, relay the reason and stop.
72
+
73
+ It also refuses a **clean** tree whose spec is not in the commit the worktree
74
+ would fork from — otherwise you get a branch missing the very spec it is for.
75
+
76
+ **A spec that `/spec` already landed is the HEALTHY case of that check.**
77
+ It is not the refusal. `/spec` authors in its own `--docs` worktree and its committing
78
+ verdict fast-forwards the base branch, so by the time `/spec-start` runs the
79
+ spec is already in the commit the worktree forks from and the tree is clean —
80
+ which is exactly what that check is looking for. Do not read "clean tree,
81
+ nothing to commit" as a sign something was skipped: it means the landing worked.
82
+
83
+ **And the worktree may already exist**, because `Commit & Start` keeps it. That
84
+ is a re-attach, not a clash: `spec-env up` plans the attach form rather than a
85
+ second `-b` fork, and its `then, run:` line — `spec-env bootstrap <name>`,
86
+ without `--docs` — is where the `setup` commands `--docs` deliberately skipped
87
+ finally run. So run it — the install belongs to this moment, the first at which
88
+ the tree is used for code — and report a re-attach rather than a fresh
89
+ provision.
90
+
91
+ ## 2. Identify the spec
92
+
93
+ - Use the name/path argument when given.
94
+ - Otherwise use the spec **in context** (the one just created or discussed).
95
+ Unlike `/spec-next`, that fallback is safe here: this skill starts nothing
96
+ without the gate above passing, and a wrong guess is caught by the operator
97
+ before any code is written.
98
+ - Locate it under `specs/` — `specs/backlog/` first, then the other buckets. A
99
+ spec is a `<name>/` folder whose entry point is `00-overview.md`, with one
100
+ file per phase beside it (`01-<slug>.md`, `02-…`). Legacy specs may be a bare
101
+ `<name>.md`, or a `00-overview.md` with inline phases — handle those too.
102
+ - A spec already in `specs/in-progress/` was started before. Its worktree
103
+ probably still exists, so this is a re-attach: say so rather than reporting a
104
+ fresh start, and skip the housekeeping that is already done.
105
+
106
+ ## 2b. Bring the review server up — from here, before anything else
107
+
108
+ **Only when the project has per-spec isolation** (`specs/.core/env.config.json`
109
+ present). Without it there is no review server and this step does not exist —
110
+ skip it in silence rather than explaining an absence.
111
+
112
+ ```
113
+ skitterspec spec-env review serve --host 0.0.0.0
114
+ ```
115
+
116
+ **Here is the point.** Right now this session is standing in the
117
+ **primary checkout**, and in a moment step 3 `cd`s into a worktree and stays
118
+ there. A
119
+ daemon started after that `cd` is started *by the worktree's copy of the code* —
120
+ and when `/spec-complete` removes that worktree, the daemon keeps answering on
121
+ its port and fails on every page it is asked for, for every spec. The engine
122
+ defends against that now, but the cheapest fix is to never create the situation:
123
+ start it while you are still somewhere that outlives the spec.
124
+
125
+ It is also what lets **several specs be reviewed at once**. Reviews all render
126
+ into the primary checkout's `.spec-env/reviews/`, so one server serves every
127
+ provisioned spec — including specs another agent is building in another
128
+ worktree. Starting it here means that one server belongs to the checkout none of
129
+ them can delete.
130
+
131
+ **Say nothing when it is already up.** The usual outcome is adoption — a server
132
+ is running and this changes nothing — and a line per `/spec-start` about a
133
+ daemon nobody asked about is the narration `.claude/rules/spec-reports.md`
134
+ forbids. Speak only if it could not start.
135
+
136
+ **Never fatal, never a gate.** A busy port, no network address, a refused
137
+ spawn — say it in one line and **carry on**; provisioning is not conditional on
138
+ it, and the page falls back to its `file://` URL exactly as it does today.
139
+
140
+ **`--host 0.0.0.0` is the deliberate half.** It binds the server to this
141
+ machine's network addresses so the page opens on a phone, and the engine mints a
142
+ token with that bind as its only guard. On a machine you would rather not expose,
143
+ drop the flag — the server is then reachable from this machine alone and the
144
+ render says so. On **`--plan`** this step does not run at all.
145
+
146
+ ## 3. Build its branch
147
+
148
+ ### `worktree` mode
149
+
150
+ **One path. There is no branching here and none should be added back.**
151
+
152
+ 1. **Provision.** Run `skitterspec spec-env up <name>` — a planner, so run the
153
+ `to provision, run:` commands it prints and confirm they succeeded.
154
+
155
+ 2. **Trust the worktree.** `spec-env up` wrote the printed `trusted:` root into
156
+ `.claude/settings.local.json`, but that file does not hot-reload in this
157
+ session — run **`/add-dir <trusted root>`** before editing into the worktree,
158
+ or the first write prompts. This is not tab machinery: worktrees live outside
159
+ the checkout, and the trust entry is what stops the prompt.
160
+
161
+ 3. **Bootstrap it, and move into it.** The `cd` is in the command itself, and it
162
+ **moves this session** — that is what it is for, not a side effect of it. The
163
+ Bash working directory persists between calls, so from here on this session is
164
+ standing in the worktree, which is what lets a bare `/spec-next` resolve the
165
+ spec on its own:
166
+
167
+ ```
168
+ cd "<worktreePath>" && skitterspec spec-env bootstrap <name>
169
+ ```
170
+
171
+ That is the planner's `then, run:` line, with the `cd` in front. It seeds
172
+ the gitignored files before `setup` itself — a fresh worktree has neither, so
173
+ hooks, typechecks and tests fail until both have happened — and stops at the
174
+ first step that fails, naming it. Relay its step lines; a non-zero exit is a
175
+ failure to report at the moment it happens, not a reason to run the steps by
176
+ hand.
177
+
178
+ **The worktree steps are the engine's to run, never yours.** Seeding the
179
+ gitignored files, the env file, `setup` and the stack all happen inside
180
+ `skitterspec spec-env bootstrap <name>` — one call that names no file. Do not
181
+ reconstruct them as shell: they used to be printed that way, an agent's copy was
182
+ never faithful, and a project's secrets hook refused every rewrite that named a
183
+ `.env` path. `bootstrap --plan` says what it would do, for reading only.
184
+
185
+ **Then confirm the move landed — never assume it.** Ask for a positive signal
186
+ rather than reading silence as success (`.claude/rules/negative-checks.md`
187
+ rule 1): run `skitterspec spec-env resolve` with **no argument** and read the
188
+ `spec:` line it prints.
189
+
190
+ ```
191
+ skitterspec spec-env resolve # must name this spec
192
+ ```
193
+
194
+ Three states, not two. It names this spec → carry on. It names something else,
195
+ or resolves nothing → **the `cd` did not take**. Say so plainly and fall back
196
+ to the stop-here ending in step 6, printing the path so the operator can open
197
+ a session there themselves; do not build a phase from a session whose location
198
+ you could not confirm. A failed `cd` leaves you in the primary checkout on the
199
+ base branch, where a phase's worth of code looks entirely normal at the time.
200
+
201
+ 4. **Housekeep with `git -C <worktreePath>`** — step 4 below, against the
202
+ worktree.
203
+
204
+ **Keep the `-C` prefix**, even though the session is inside the worktree now
205
+ and a bare `git` would usually do the same thing. It is immune to the one
206
+ failure this sequence can have — a `cd` that silently did not take — where a
207
+ bare `git` would instead write the spec's move into the primary checkout on
208
+ the base branch. It costs nothing and removes a whole failure mode, so do not
209
+ tidy it away.
210
+
211
+ 5. **Print the worktree path.** What happens next is step 6 — it is offered
212
+ there, not decided here.
213
+
214
+ **The session moves into the worktree, and nothing opens a window.** Those are
215
+ two different claims and both are load-bearing. The move is real, and the `cd` in
216
+ step 3 is its whole mechanism — no tool call, because an approval prompt is
217
+ unusable on a phone and leaves the session stuck. Nothing is *spawned*: no new
218
+ terminal, no tab, no editor sent anywhere, because that machinery had nothing
219
+ left to do and was removed deliberately.
220
+
221
+ **Do not move the branch into this checkout**, and do not ask the operator to.
222
+ `/spec-live` is for testing a finished-enough spec on the already-running dev
223
+ server; it is not how work gets started.
224
+
225
+ **`/spec-next`'s refusal is unchanged by this.** Its rule 2 — "the worktree you
226
+ are standing in" — is what answers afterwards, and step 3 is what puts the session
227
+ there; nothing about rules 1 to 3 is loosened, and it must stay that way, because
228
+ the refusal exists so the wrong branch is never built. What changed is where the
229
+ session stands, not how weakly the rules read: a bare `/spec-next` typed from
230
+ somewhere that is neither a worktree nor a live checkout still refuses exactly as
231
+ it did. `--worktree <path>` survives untouched beside it — it answers before those
232
+ rules and cannot be reached by guessing.
233
+
234
+ **And the `cd` is a convenience, not the only thing holding this together.**
235
+ `/spec-next`'s **rule 4** asks the engine for the sole provisioned spec, so a
236
+ bare `/spec-next` resolves this spec from anywhere in the repo — after a
237
+ `/clear`, from a new tab, tomorrow morning. That is what makes step 6's
238
+ stop-here ending an honest offer rather than a promise only this session can
239
+ keep. Do not delete rule 4 as redundant with the `cd`: the `cd` is session state,
240
+ and rule 4 is what is left once it is gone.
241
+
242
+ ### `checkout` mode
243
+
244
+ Run `skitterspec spec-env up <name>` and the single `git switch` it prints.
245
+ There is no worktree, no bootstrap and no hand-off — the checkout is already the
246
+ workbench. Its planner enforces the same gate from the engine side, so relay any
247
+ refusal and stop.
248
+
249
+ ## 4. Move the spec into development
250
+
251
+ **Do this before you report anything**, so no path can end with a provisioned
252
+ worktree and a spec still reading `Ready` in `specs/backlog/`. In `worktree` mode
253
+ run it against the worktree with `git -C <worktreePath>`; in `checkout` mode the
254
+ branch is already here.
255
+
256
+ - `git mv "specs/backlog/<name>" "specs/in-progress/<name>"` if it isn't there
257
+ already (`mkdir -p specs/in-progress` first). Use `git mv` to keep history.
258
+ - Set the **Status** header: `> **Status:** In Progress — Phase 1 (started <YYYY-MM-DD>)`.
259
+ - Set **Developer** if it is still `—` (`git config user.name`).
260
+
261
+ Assignment sync is **not yet supported by the Jira provider**: the issue's
262
+ assignee is never read or written, and there is no `/spec-claim`. The
263
+ `> **Developer:**` header is still set by the base skill's own step — that is
264
+ the repo's record and it needs nothing from the tracker. Nothing to run here.
265
+
266
+ - Append a **State log** row: `| <YYYY-MM-DD> | In Progress | in-progress | <git user.name> |`.
267
+
268
+ **Only when `specs/.core/jira.config.json` exists** and the spec's overview
269
+ carries a `jira_identifier`. Either missing → **skip**, in one line
270
+ (`not linked to Jira — /spec-push to mirror it`), and carry on. Nothing else in
271
+ this step changes.
272
+
273
+ **Refresh the mirror now, without asking.** Run `/spec-push`. The spec has just
274
+ moved to `in-progress/` — a real state change, and the tracker is a generated
275
+ mirror of it. (The developer stamped beside it stays a repo-side record:
276
+ assignment sync is not yet supported by the Jira provider.) It costs one engine
277
+ call and no model tokens when Jira credentials are set (see `apply.transport`
278
+ in `jira.config.md`).
279
+
280
+ - **Never mint.** An unlinked spec is skipped, not created. A spec kept
281
+ deliberately local should stay that way — `/spec-push` is how someone opts in.
282
+ - **Never fatal.** If the push fails — offline, no credentials, a Jira error —
283
+ say so and **finish the operation anyway**. The spec is in flight in the repo
284
+ regardless; the mirror is disposable and the next push repairs it. Do not roll
285
+ the provisioning back, and do not stop to ask.
286
+ - **Say what happened** in the skill's report: mirror updated, skipped as
287
+ unlinked, or failed with the reason.
288
+
289
+ ### Why it sits here
290
+
291
+ Pinned **after the `git mv` and before the commit**, and both halves matter:
292
+
293
+ - **After the move**, because the projection reads a spec's workflow status from
294
+ its folder bucket. Push while the folder is still in `backlog/` and the issue
295
+ is set to the status the spec is *leaving*.
296
+ - **Before the commit**, because the push stamps keys into the spec and writes a
297
+ snapshot under `specs/.core/`. The `git add` that follows sweeps both up with
298
+ the status change; push after it instead and those files are left uncommitted —
299
+ which strands a dirty worktree on the hand-off, and makes `spec-env integrate`
300
+ refuse to land the branch.
301
+
302
+ ### Why this is not the refresh `/spec-next` already runs
303
+
304
+ It was once reasoned that a push here would send the same thing twice, one commit
305
+ apart, because `/spec-next` refreshes the moment it starts. That holds only in
306
+ `checkout` mode, where `/spec-next` follows immediately. In `worktree` mode the
307
+ spec is built elsewhere and the refresh can be hours away or never come — and
308
+ until it does, the issue sits in its old status while the repo reads
309
+ `in-progress`.
310
+
311
+ The two pushes are not duplicates either way. This one carries the issue's
312
+ workflow status; the one `/spec-next` runs carries phase 1 starting. Every other
313
+ lifecycle skill mirrors the state change it makes, and this is the seam that
314
+ stops `/spec-start` being the exception.
315
+
316
+ - **Commit it.** One commit, the spec's own — it records the in-progress state on
317
+ the branch, and sweeps up everything above so the worktree is clean when you
318
+ hand it over.
319
+
320
+ **Publishing that branch is yours to do, and nothing here does it for you.**
321
+ Whenever you want the work somewhere other than this machine:
322
+
323
+ ```
324
+ git -C <worktreePath> push -u origin <branch>
325
+ ```
326
+
327
+ Print it if it is useful; never run it. This skill once pushed here, justified as
328
+ recording the state "for everyone" and firing the tracker's automation — and
329
+ neither half survives reading. The automation needs `{identifier}` in
330
+ `branch.pattern` (see `env.config.md`) to put an issue id in the branch name, and
331
+ the shipped default carries none, so the tracker has nothing to match. Nor was it
332
+ an invariant: `/spec-bug` provisions a worktree the same way and has never
333
+ pushed, and `/spec-hotfix` forbids it outright. This was the odd one out.
334
+
335
+ **It also kept a guard from ever firing.** `refuseTeardownIfUnpushed` blocks
336
+ teardown on commits that are unpushed and unlanded — which described no branch at
337
+ all while this skill published every one of them at provisioning. It can fire now,
338
+ and the place it does is `/spec-cancel`, where the work really is about to be
339
+ destroyed: that skill relays the refusal and offers both ways out. Nothing to do
340
+ here beyond knowing it is no longer dead code.
341
+
342
+ A spec ideally arrives `Ready` from `/spec`; a `Draft` works too — sanity-check
343
+ it is well-formed first.
344
+
345
+ - **Report anything left waiting, and claim none of it.** Ask the engine once:
346
+
347
+ ```
348
+ skitterspec spec-env review waiting
349
+ ```
350
+
351
+ A pass listed here arrived when nothing was watching — a wait that never ran,
352
+ a session cleared, a terminal closed overnight — and no watcher can recover
353
+ those, however good. Relay what it prints: the spec, the code, the verdict and
354
+ the age, with `/spec-reviewed <code>` to pick one up and `--drop <code>` to
355
+ disown it.
356
+
357
+ **It is information, not a gate.** It never refuses, nothing here is
358
+ conditional on it, and **you never claim one** — `/spec-diff` §0 stands
359
+ unchanged, and a pass sitting there when you arrived was not sent to you.
360
+ Silent when nothing is waiting, which is the usual case: say nothing rather
361
+ than reporting that there was nothing to report.
362
+
363
+
364
+ ## 4b. Note a missing gating decision (only if configured)
365
+
366
+ **Only when `specs/.core/gating.config.json` exists.** Run
367
+ `skitterspec gating check <name>` and, if it names this spec, mention it **once**
368
+ before phase 1 starts — the cheapest moment to decide is before any code exists.
369
+
370
+ **This check is advisory.** It reports; it never refuses, and nothing below is
371
+ conditional on it. A spec written before the project adopted gating has no header
372
+ and is not broken — turning this into a gate would accuse the very specs the
373
+ feature was designed not to disturb.
374
+
375
+ ## 5. Bring the spec's dev servers up — confirm before heavy steps
376
+
377
+ **Only when the project configures host dev servers** (`env.config.json` → a
378
+ non-empty `dev` array). Show what will start — the commands, the ports, any
379
+ Docker stack — and get a yes; on **`--plan`**, print it and stop. On
380
+ confirmation run `skitterspec spec-env dev up <name>`. With none configured this
381
+ is a clean no-op.
382
+
383
+ To reach the spec at your normal `localhost` URL afterwards, the **user** types
384
+ **`/spec-connect <name>`** (`/spec-connect main` hands the ports back). Never
385
+ invoke it yourself.
386
+
387
+ ## 6. Build phase 1
388
+
389
+ **`checkout` mode — carry straight on into `/spec-next`** in this session: it
390
+ marks phase 1 started, refreshes the mirror again, builds it with tests and
391
+ reports. Do not stop and ask the operator to run it: the branch is here and they
392
+ asked to start the spec.
393
+
394
+ **`worktree` mode — offer it, then do what they say.** Step 3 left this session
395
+ standing in the worktree, so both endings happen right here and neither needs a
396
+ second session opened anywhere. In prose: say the worktree is ready and name its
397
+ path, then ask **"build phase 1 now?"** — recommending that they do, and naming
398
+ both endings so the decline is a real answer rather than a formality.
399
+
400
+ **Never fence that question.** A grey box is read as an artefact to skim rather
401
+ than as something someone is being asked, which is the whole reason
402
+ `.claude/rules/spec-reports.md` bans fencing a message to the reader. This step
403
+ prescribed a fenced block for a long time and an operator read straight past it,
404
+ which is the evidence, not a preference.
405
+
406
+ - **Build it here** — carry on into a bare **`/spec-next`**. Bare is right: the
407
+ session is in the worktree, so its rule 2 resolves this spec with nothing
408
+ passed and nothing guessed.
409
+ - **Stop here** — the operator is left standing in the worktree on a provisioned
410
+ branch, which is a perfectly good place to leave things. Nothing has to be
411
+ reopened or handed anywhere, and `/spec-next` typed an hour later — from this
412
+ session or a fresh one — does exactly what it would have done now.
413
+
414
+ **Ask rather than deciding for them, and mean it.** Provisioning is cheap and
415
+ reversible; a phase build is neither, and one yes should not cover both. A large
416
+ phase is often better started in a session of its own with a whole context budget
417
+ to spend, and only the operator knows which this is. On **`--plan`** this step
418
+ does not run at all — nothing was provisioned to build in.
419
+
420
+ **`--worktree <path>` is still there, and is still not a way around the refusal.**
421
+ It builds a spec the session is *not* standing in, which after step 3 is the
422
+ exception rather than the normal path. Reach for it in exactly two cases: the
423
+ confirm in step 3 reported the `cd` did not take, or you deliberately mean to
424
+ build some other spec's phase from here. A path someone typed is not a path
425
+ anything guessed, which is why it was never a loosening of the refusal and still
426
+ is not.
427
+
428
+ ## 7. Report
429
+
430
+ **When step 6 carried on into `/spec-next`, emit no block here.** That skill ends
431
+ with its own, and its `Branch` and `Spec` fields already carry everything this
432
+ one would say. Two blocks for one run is the noise the contract exists to
433
+ remove — this section is for the run that stops at step 6.
434
+
435
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
436
+ the shape; this section carries only what is specific here.
437
+
438
+ **Verdicts**
439
+
440
+ - `✅` — the branch is provisioned, the spec is `in-progress`, the session is
441
+ standing in the worktree.
442
+ - `⚠️` — provisioned, with something worth knowing (dev servers that did not
443
+ come up, a mirror that did not refresh, a missing gating decision).
444
+ - `❌` — provisioning failed part-way and left something behind. Say what, and
445
+ where.
446
+ - `⏸` — the gate refused: in `checkout` mode a dirty tree or someone else's
447
+ unfinished work, in either mode a spec whose own files are not in the commit
448
+ the worktree would fork from. Nothing changed. Another spec's uncommitted work
449
+ is **not** on this list in `worktree` mode — it is an `Untouched` row on a
450
+ `✅`.
451
+
452
+ **Fields:** `Tracker` · `Branch` · `Spec` · `Worktree` · `Untouched` · `Follow-ups` · `Next`
453
+
454
+ `Worktree` carries the path, because the session is now standing in it and the
455
+ operator's next command depends on knowing that. `Next` is `/spec-next`.
456
+
457
+ `Untouched` appears only when `spec-env up` reported uncommitted work that was
458
+ not this spec's — say how much and whose, and **keep the verdict `✅`**. Nothing
459
+ went wrong: a worktree carries nothing, so that work was never in play.
460
+
461
+ On **`--plan`** nothing was provisioned, so the verdict is `⏸` and `Built`
462
+ carries the plan rather than a claim about the repo.
463
+
464
+ ## Opt-outs
465
+
466
+ - **`--plan`** — print the provisioning and dev-server plan, change nothing.
467
+ - **`--no-worktree`** — skip provisioning and build on the current branch. Warn
468
+ that the work lands wherever you are (usually the base branch); reserve it for
469
+ a trivial change or an explicit request.
470
+
471
+ There is no `--here`. It existed to ask for the branch in the checkout you are
472
+ standing in — and in `checkout` mode that is already what happens, while in
473
+ `worktree` mode `--no-worktree` is the way to say it.
474
+
475
+ ## Why this skill links nothing, but does mirror what it changes
476
+
477
+ This skill creates no spec and mints no issue, so it has **nothing to link** —
478
+ the intake and picker steps belong to `/spec`, `/spec-bug` and `/spec-hotfix`.
479
+
480
+ It does push, though, and that is step 4's seam. The state change it makes — the
481
+ spec moving to `in-progress` with a developer stamped on it — is mirrored by the
482
+ skill that makes it, exactly as `/spec-complete`, `/spec-cancel` and
483
+ `/spec-review` mirror theirs. It was once reasoned that the refresh `/spec-next`
484
+ runs would cover it, so a push here would send the same thing twice one commit
485
+ apart. That only ever held in `checkout` mode, where `/spec-next` follows
486
+ immediately; in `worktree` mode it can be hours away or never come, and the
487
+ issue sits in its old state with nobody assigned meanwhile.
488
+
489
+ The **assignment** seam just above it is still not a push, and does not need to
490
+ be. This is the one moment in the lifecycle where "who is building this" is
491
+ actually decided — the branch is being provisioned for someone, and that someone
492
+ is at the keyboard. It stamps the spec file and stops there, so it costs no
493
+ tracker call and rides out on the push below like every other field. Deferring
494
+ the stamp to `/spec-next` would be worse than untidy: in `worktree` mode the two
495
+ can be separated by hours, and a spec in flight with nobody named on it is
496
+ exactly the gap assignment exists to close.
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: spec-status
3
+ description: Show a spec's one-way sync status against Jira — a read-only report naming what would push, and whether someone edited the issue's description since the last push. Changes nothing. Opt-in — needs specs/.core/jira.config.json. Use when the user says "/spec-status", "is this spec in sync with Jira", "what would push", or "show spec sync status".
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # /spec-status — one-way sync report
8
+
9
+ > Stay silent while this runs — speak only to ask something you cannot answer
10
+ > yourself, or to report a failure at the moment it happens. Read
11
+ > `.claude/rules/spec-reports.md` before reporting; it defines the block this
12
+ > skill ends with.
13
+
14
+ Read-only. Reports two things and writes nothing:
15
+
16
+ 1. **Pending push** — has the spec changed since the last push (is there an issue
17
+ description/state or any phase subtask to create or update)?
18
+ 2. **Description edited** — did someone edit the issue's description on Jira
19
+ since the last push? The next push replaces it, so this is worth reading
20
+ first.
21
+
22
+ **Status is not compared, deliberately.** Skitterspec tells Jira about its
23
+ own transitions and never reads a status back: a card someone moved by hand is
24
+ theirs to have moved, and push resends State only when the spec itself moves.
25
+
26
+ The repo is the source of truth; Jira is a generated mirror, so there is no
27
+ per-field "conflict" — only "what would the next push send" and "did someone
28
+ write over the mirror's text".
29
+
30
+ **Opt-in**: only runs when `specs/.core/jira.config.json` exists. If absent,
31
+ tell the user how to enable Jira sync and stop.
32
+
33
+ ## 1. Identify the target spec
34
+
35
+ Use the argument, else the spec in context; ask if unclear.
36
+
37
+ ## 2. Fetch the Jira issue (optional, for the description check)
38
+
39
+ If the spec has a `jira_identifier`, discover the Jira MCP read tool
40
+ (`getJiraIssue`) and write the issue JSON to a temp file. If Jira isn't
41
+ connected, skip the description check (still report pending-push).
42
+
43
+ **Write the whole issue, including its `description`.** That is the field the
44
+ check reads; without it the check has nothing to look at — and it says nothing
45
+ rather than guessing, so the loss is silent. Keep `url` too: it is what the
46
+ description line points the reader at.
47
+
48
+ **The description itself never enters the conversation.** The engine hashes it
49
+ and compares hashes; what it prints is *that* the text changed, plus where to
50
+ read it. Do not open the temp file, and do not paste the description into your
51
+ report.
52
+
53
+ Optionally fetch the project's status names to a file to validate the
54
+ configured `states` at the same time.
55
+
56
+ ## 3. Run the engine
57
+
58
+ ```
59
+ skitterspec spec-sync status <spec> [--remote <issuefile>] [--workspace-states <statesfile>]
60
+ ```
61
+
62
+ - Reports `push: pending — N to create, M to update` or `up to date`.
63
+ - With `--remote`, adds a `drift:` line when the issue's description was
64
+ edited on Jira since the last push, and nothing otherwise. It never
65
+ reports the issue's state.
66
+ - With `--workspace-states`, fails loudly if a configured status name isn't in
67
+ the project (no workflow transition could ever reach it, so the push would
68
+ refuse at apply time).
69
+
70
+ ## 3b. A key mismatch is a different problem
71
+
72
+ If the spec's `jira_identifier` carries a **different project key** than
73
+ `jira.projectKey` in `specs/.core/jira.config.json` — or the issue read in step
74
+ 2 came back under another key — the issue was moved or the project key changed,
75
+ and the repo's stamps are stale. That is not push drift and `/spec-push` cannot
76
+ fix it: it will fail with `no Jira issue found for <old>-<n>`.
77
+
78
+ The Linear provider ships `retarget` to rewrite stale stamps; the Jira provider
79
+ does not yet. Say so, name the two keys, and stop. Do not attempt the rewrite by
80
+ hand — the identifiers live in frontmatter, snapshot filenames and the keys
81
+ inside those snapshots, and a hand edit misses some.
82
+
83
+ ## 4. Report
84
+
85
+ Relay the engine's output **verbatim, above the block** — it is the answer, and
86
+ the block is the verdict on it. Never write to either side.
87
+
88
+ End with the block defined in `.claude/rules/spec-reports.md`. That file carries
89
+ the shape; this section carries only what is specific here.
90
+
91
+ **Verdicts**
92
+
93
+ - `✅` — in sync; nothing would push.
94
+ - `⚠️` — N objects would push, or the issue's **description** was edited on
95
+ Jira since the last push. Neither is an error, but both are the reason
96
+ someone ran this. **Say which**, since they call for different things: a
97
+ pending push is routine, and an edited description means a person wrote
98
+ something that the next push replaces.
99
+ - `⏸` — no config, or the spec is not linked. Nothing to compare.
100
+
101
+ **Fields:** `Tracker` · `Follow-ups` · `Next`
102
+
103
+ `Tracker` is the answer in one line — what would push, and whether the
104
+ description was edited. `Next` is `/spec-push` when a push is pending, and nothing to
105
+ do when it is not.
106
+
107
+ A **`phases: <mode>`** line names the phase mode that resolved for this spec's
108
+ lifecycle bucket, and appears only when it is not the default `subissue`.
109
+ `mapping.phases` may be a per-bucket map, so this is the only place the mode a
110
+ given spec got is stated. Under **`inline`** the phases live in the spec issue's
111
+ description rather than as subtasks, so "0 to create" is the expected shape
112
+ rather than a sign the phase files failed to parse; under **`deferred`** the
113
+ `N phase(s) deferred` line above it says how many are still waiting on
114
+ `/spec-next`. Relay both lines as printed.