@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.
- package/MIGRATION.md +1266 -0
- package/README.md +44 -2
- package/assets/claude-md-section.md +85 -0
- package/assets/commands/allow-main.md +33 -0
- package/assets/commands/spec-connect.md +13 -0
- package/assets/commands/spec-live.md +14 -0
- package/assets/commands/spec-remote-review.md +37 -0
- package/assets/commands/spec-skip.md +24 -0
- package/assets/core/SETUP.md +192 -0
- package/assets/core/env.config.json.example +56 -0
- package/assets/core/env.config.md +606 -0
- package/assets/core/gating.config.json.example +4 -0
- package/assets/core/gating.config.md +81 -0
- package/assets/core/jira.config.json.example +18 -0
- package/assets/core/jira.config.md +88 -0
- package/assets/hooks/main-guard.cjs +162 -0
- package/assets/hooks/review-gate.cjs +146 -0
- package/assets/review/page.html +3384 -0
- package/assets/rules/commit-trailers.md +96 -0
- package/assets/rules/negative-checks.md +69 -0
- package/assets/rules/offered-unblocks.md +100 -0
- package/assets/rules/spec-planning.md +702 -0
- package/assets/rules/spec-reports.md +572 -0
- package/assets/skills/no-spec/SKILL.md +249 -0
- package/assets/skills/spec/SKILL.md +714 -0
- package/assets/skills/spec-bug/SKILL.md +585 -0
- package/assets/skills/spec-cancel/SKILL.md +261 -0
- package/assets/skills/spec-complete/SKILL.md +451 -0
- package/assets/skills/spec-diff/SKILL.md +870 -0
- package/assets/skills/spec-hotfix/SKILL.md +607 -0
- package/assets/skills/spec-init/SKILL.md +178 -0
- package/assets/skills/spec-jira-setup/SKILL.md +221 -0
- package/assets/skills/spec-list/SKILL.md +173 -0
- package/assets/skills/spec-next/SKILL.md +678 -0
- package/assets/skills/spec-push/SKILL.md +306 -0
- package/assets/skills/spec-review/SKILL.md +256 -0
- package/assets/skills/spec-reviewed/SKILL.md +284 -0
- package/assets/skills/spec-start/SKILL.md +496 -0
- package/assets/skills/spec-status/SKILL.md +114 -0
- package/assets/skills/spec-sync/SKILL.md +220 -0
- package/assets/skills/spec-to-main/SKILL.md +141 -0
- package/bin/skitterspec-jira.js +68 -0
- package/package.json +40 -4
- package/src/cli.js +5967 -0
- package/src/deprecate.js +138 -0
- package/src/env/bootstrap.js +188 -0
- package/src/env/building.js +143 -0
- package/src/env/classify.js +176 -0
- package/src/env/commitcmd.js +108 -0
- package/src/env/config.js +850 -0
- package/src/env/dev.js +63 -0
- package/src/env/glob.js +34 -0
- package/src/env/hooks.js +226 -0
- package/src/env/hotfix.js +413 -0
- package/src/env/hotfixland.js +302 -0
- package/src/env/integrate.js +167 -0
- package/src/env/live.js +479 -0
- package/src/env/mainguard.js +299 -0
- package/src/env/provision.js +466 -0
- package/src/env/proxy.js +225 -0
- package/src/env/prune.js +119 -0
- package/src/env/registry.js +159 -0
- package/src/env/render.js +17 -0
- package/src/env/resolve.js +716 -0
- package/src/env/review.js +2622 -0
- package/src/env/reviewers/coderabbit.js +228 -0
- package/src/env/reviewers.js +517 -0
- package/src/env/serve.js +1044 -0
- package/src/env/supervise.js +157 -0
- package/src/env/teardown.js +248 -0
- package/src/env/trust.js +87 -0
- package/src/gating.js +155 -0
- package/src/init.js +1150 -0
- package/src/lines-diff.js +114 -0
- package/src/prompts.js +129 -0
- package/src/vendor/jira/adf.js +414 -0
- package/src/vendor/jira/api.js +295 -0
- package/src/vendor/jira/cli-sync.js +1252 -0
- package/src/vendor/jira/commands.js +44 -0
- package/src/vendor/jira/config.js +286 -0
- package/src/vendor/jira/credentials.js +108 -0
- package/src/vendor/jira/dialect.js +45 -0
- package/src/vendor/jira/mcp.js +129 -0
- package/src/vendor/provider-kit/index.js +41 -0
- package/src/vendor/provider-kit/src/adapter.js +23 -0
- package/src/vendor/provider-kit/src/apply.js +207 -0
- package/src/vendor/provider-kit/src/args.js +68 -0
- package/src/vendor/provider-kit/src/assignment.js +277 -0
- package/src/vendor/provider-kit/src/config.js +251 -0
- package/src/vendor/provider-kit/src/credentials.js +404 -0
- package/src/vendor/provider-kit/src/doctor.js +35 -0
- package/src/vendor/provider-kit/src/http.js +63 -0
- package/src/vendor/provider-kit/src/identity.js +93 -0
- package/src/vendor/provider-kit/src/list-assignee.js +71 -0
- package/src/vendor/provider-kit/src/list-rows.js +35 -0
- package/src/vendor/provider-kit/src/md-compare.js +39 -0
- package/src/vendor/provider-kit/src/md-tables.js +94 -0
- package/src/vendor/provider-kit/src/prompt.js +50 -0
- package/src/vendor/provider-kit/src/released.js +219 -0
- package/src/vendor/provider-kit/src/specs.js +248 -0
- package/src/vendor/provider-kit/src/transport.js +22 -0
- package/src/vendor/sync-core/index.js +92 -0
- package/src/vendor/sync-core/src/base.js +81 -0
- package/src/vendor/sync-core/src/compare.js +338 -0
- package/src/vendor/sync-core/src/dialect.js +51 -0
- package/src/vendor/sync-core/src/fields.js +36 -0
- package/src/vendor/sync-core/src/legacy.js +100 -0
- package/src/vendor/sync-core/src/normalize.js +971 -0
- package/src/vendor/sync-core/src/push.js +85 -0
- package/src/vendor/sync-core/src/retarget.js +278 -0
- package/src/vendor/sync-core/src/task-block.js +308 -0
- package/src/vendor/sync-core/src/verify.js +67 -0
- 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.
|