@skitterbyte/skitterspec-linear 10.7.0 → 11.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 +36 -0
- package/README.md +3 -3
- package/assets/claude-md-section.md +13 -51
- package/assets/commands/spec-live.md +2 -2
- package/assets/core/SETUP.md +1 -1
- package/assets/core/env.config.json.example +4 -1
- package/assets/core/env.config.md +26 -6
- package/assets/core/linear.config.json.example +2 -1
- package/assets/core/linear.config.md +46 -4
- package/assets/rules/spec-planning.md +30 -10
- package/assets/skills/spec/SKILL.md +15 -10
- package/assets/skills/spec-bug/SKILL.md +43 -9
- package/assets/skills/spec-cancel/SKILL.md +12 -0
- package/assets/skills/spec-complete/SKILL.md +26 -5
- package/assets/skills/spec-hotfix/SKILL.md +42 -8
- package/assets/skills/spec-init/SKILL.md +16 -6
- package/assets/skills/spec-linear-setup/SKILL.md +1 -1
- package/assets/skills/spec-next/SKILL.md +141 -0
- package/assets/skills/spec-push/SKILL.md +2 -2
- package/assets/skills/spec-review/SKILL.md +5 -5
- package/assets/skills/spec-start/SKILL.md +146 -0
- package/assets/skills/spec-status/SKILL.md +2 -2
- package/assets/skills/spec-sync/SKILL.md +9 -1
- package/assets/skills/spec-to-main/SKILL.md +7 -5
- package/package.json +1 -1
- package/src/cli.js +234 -20
- package/src/env/config.js +24 -1
- package/src/env/integrate.js +61 -1
- package/src/env/live.js +27 -3
- package/src/env/provision.js +58 -1
- package/src/env/teardown.js +41 -3
- package/src/init.js +21 -12
- package/src/prompts.js +31 -3
- package/src/vendor/linear/cli-sync.js +55 -4
- package/src/vendor/linear/config.js +70 -3
- package/src/vendor/linear/released.js +65 -5
- package/assets/skills/spec-go/SKILL.md +0 -233
package/MIGRATION.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Migration guide
|
|
2
2
|
|
|
3
|
+
## `@skitterbyte/skitterspec` v16 → v17 (`/spec-go` splits in two)
|
|
4
|
+
|
|
5
|
+
### Breaking change
|
|
6
|
+
|
|
7
|
+
**`/spec-go` is removed.** It did two jobs — set an environment up, and build a
|
|
8
|
+
phase — and the seam between them is where the worktree hand-off hurt: you ran
|
|
9
|
+
the same command twice, once to provision and once, from another session, to
|
|
10
|
+
build. They are now two commands with one job each:
|
|
11
|
+
|
|
12
|
+
| Removed | Use instead |
|
|
13
|
+
|---------|-------------|
|
|
14
|
+
| `/spec-go <name>` (first run — start a spec) | **`/spec-start <name>`** — puts the spec in flight on this checkout, moves it to `in-progress`, then builds phase 1. |
|
|
15
|
+
| `/spec-go` (later runs — build the next phase) | **`/spec-next`** — builds the next phase of whichever spec is in flight. Re-run it per phase. |
|
|
16
|
+
| `/spec-go --here` | **Nothing — `/spec-start` *is* here.** It puts the branch in the checkout you are in, which is what the flag was reaching for. |
|
|
17
|
+
|
|
18
|
+
**One checkout holds one spec in flight.** `/spec-start` refuses while another
|
|
19
|
+
spec holds your checkout, naming it and the three ways to free the workbench
|
|
20
|
+
(`/spec-complete`, `/spec-cancel`, or `/spec-live main` to park it). It will not
|
|
21
|
+
stash, commit or switch on your behalf — moving unfinished work is a decision,
|
|
22
|
+
not a side effect.
|
|
23
|
+
|
|
24
|
+
**`/spec-next` refuses when nothing is in flight** rather than guessing a spec
|
|
25
|
+
from the conversation. It writes real code; a wrong guess produces commits on a
|
|
26
|
+
branch nobody asked for.
|
|
27
|
+
|
|
28
|
+
### What to do
|
|
29
|
+
|
|
30
|
+
1. **Upgrade** — `npx @skitterbyte/skitterspec update` removes the retired
|
|
31
|
+
`/spec-go` skill and installs the two replacements. A `/spec-go` you edited
|
|
32
|
+
yourself is kept with a warning rather than deleted; remove it by hand.
|
|
33
|
+
2. **Retrain the muscle memory** — `/spec-start <name>` to begin, `/spec-next` to
|
|
34
|
+
carry on, unchanged `/spec-complete` to finish.
|
|
35
|
+
3. **Providers**: the `spec-go-start` seam is now **`spec-next-start`**. A
|
|
36
|
+
provider distribution must rename its fragment file to match, or the build
|
|
37
|
+
fails on an orphaned seam.
|
|
38
|
+
|
|
3
39
|
## `@skitterbyte/skitterspec-linear` v9 → v10 (`push` validates your issue states)
|
|
4
40
|
|
|
5
41
|
**`spec-sync push` now refuses to run until the configured `states` names have
|
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ them. Your `specs/` content and live `.core` config are never touched.
|
|
|
72
72
|
|
|
73
73
|
## What the superset adds
|
|
74
74
|
|
|
75
|
-
On top of the base skills (`/spec`, `/spec-
|
|
75
|
+
On top of the base skills (`/spec`, `/spec-start`, `/spec-next`, isolation, …):
|
|
76
76
|
|
|
77
77
|
- **`/spec-status`** — read-only drift report: what the next push would create /
|
|
78
78
|
update, any workflow-state drift, and any phase whose status signals disagree
|
|
@@ -108,7 +108,7 @@ On top of the base skills (`/spec`, `/spec-go`, isolation, …):
|
|
|
108
108
|
Linear steps filled in, so the mirror keeps up without anyone remembering to
|
|
109
109
|
push: `/spec`, `/spec-bug` and `/spec-hotfix` link the spec they create (asking
|
|
110
110
|
which **Project** it belongs to, and minting a sub-issue per phase);
|
|
111
|
-
`/spec-
|
|
111
|
+
`/spec-next` refreshes it as work starts; `/spec-complete`, `/spec-cancel` and
|
|
112
112
|
`/spec-review` refresh it after they change it. All three creating skills can
|
|
113
113
|
also start **from** an existing issue — `/spec SKI-123`,
|
|
114
114
|
`/spec-hotfix v33.16.4 SKI-123`, or `--from-issue` to browse the ones your web
|
|
@@ -155,7 +155,7 @@ whole repo *or* one per lifecycle bucket:
|
|
|
155
155
|
so agents can be assigned one each.
|
|
156
156
|
- `"deferred"` — unlinked phases wait until the work starts. A spec sitting in
|
|
157
157
|
`specs/backlog/` mirrors as **the issue alone**, keeping its phase list in the
|
|
158
|
-
description; the sub-issues arrive with the push that follows `/spec-
|
|
158
|
+
description; the sub-issues arrive with the push that follows `/spec-start`. Worth
|
|
159
159
|
it when adopting sync on a backlog of dozens of specs, where the default
|
|
160
160
|
front-loads hundreds of calls for work nobody has started.
|
|
161
161
|
- `"inline"` — phases become **sections of the spec issue's own description**,
|
|
@@ -1,53 +1,15 @@
|
|
|
1
1
|
## Spec workflow
|
|
2
2
|
|
|
3
|
-
Spec-driven development runs through the lifecycle **skills**
|
|
4
|
-
structure and lifecycle stay consistent
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
| `/spec-hotfix` | (Hotfix) Fork a worktree from a release tag, red→green, land by tag | `In Progress` | `specs/in-progress/` |
|
|
17
|
-
| `/spec-to-main` | Land the branch on the base mid-spec, without finishing | (unchanged) | (unchanged) |
|
|
18
|
-
| `/spec-init` | Bootstrap/repair this workflow in a project (idempotent) | — | — |
|
|
19
|
-
|
|
20
|
-
**Skills vs commands.** The table is skills — Claude reads them and exercises
|
|
21
|
-
judgment. `/spec-connect` and `/spec-live` are **slash commands** instead: each
|
|
22
|
-
pre-executes one `spec-env` verb and relays it, so only you can run them. A skill
|
|
23
|
-
that wants one will tell you to type it.
|
|
24
|
-
|
|
25
|
-
Every spec has a **type** (`> **Type:** Feature\|Bug`) and a filename prefix
|
|
26
|
-
(`feat-<name>` / `bug-<name>`) — never `[BUG]` brackets (glob hazard). Specs use
|
|
27
|
-
markdown checkboxes (`- [ ]`) for task tracking and are the single source of
|
|
28
|
-
truth for progress. Every spec is a folder: `00-overview.md` is the dashboard
|
|
29
|
-
(problem, decisions, solution, **phase index**, logs) and **each phase is its own
|
|
30
|
-
file** (`01-<slug>.md`, `02-…`) holding that phase's tasks — never a bare file,
|
|
31
|
-
never phases lumped into the overview. **Every phase ends with creating and
|
|
32
|
-
running tests**; decisions go in the spec's Changelog, state transitions in its
|
|
33
|
-
State log.
|
|
34
|
-
|
|
35
|
-
> Tailor the per-phase test commands and project conventions referenced by the
|
|
36
|
-
> spec skills to this project's stack (see `.claude/rules/spec-planning.md`).
|
|
37
|
-
|
|
38
|
-
**Per-spec isolation (adopt once, then default):** with isolation adopted
|
|
39
|
-
(`skitterspec init --isolation`, or `specs/.core/env.config.json` present),
|
|
40
|
-
**`/spec-go`** gives every in-progress spec its own git worktree automatically —
|
|
41
|
-
parallel specs, no stashing, `main` left free — and brings up the project's host
|
|
42
|
-
**dev servers** (`env.config` → `dev`) on the spec's ports. The **`/spec-connect <name>`** command then exposes that spec on your canonical
|
|
43
|
-
`localhost` ports so you can test it at the normal URL (`/spec-connect main`
|
|
44
|
-
hands them back); for a code-only spec, **`/spec-live <name>`** reuses the dev
|
|
45
|
-
server you already have running instead. Docker is a
|
|
46
|
-
**per-spec escalation**: `/spec` sets `> **Stack:** worktree` (default) or
|
|
47
|
-
`worktree + docker` when the spec touches the DB / stateful services, and only
|
|
48
|
-
the latter gets a namespaced stack. Teardown is folded into **`/spec-complete`** ·
|
|
49
|
-
**`/spec-cancel`**; beneath the skills, `skitterspec spec-env` is the CLI engine — `up`, `down`,
|
|
50
|
-
`prune`, `dev`, `connect`, `integrate`, `hotfix`, `live`, `status` and `resolve`.
|
|
51
|
-
Most are planners the skills run; omit the spec name and it uses the worktree you
|
|
52
|
-
are standing in. Independent of lifecycle
|
|
53
|
-
status; inactive when `env.config.json` is absent.
|
|
3
|
+
Spec-driven development runs through the lifecycle **skills** — use them so
|
|
4
|
+
structure and lifecycle stay consistent. The everyday loop is
|
|
5
|
+
**`spec → start → next → commit → complete`**, with `/spec-connect` when you want to test
|
|
6
|
+
the spec in a browser.
|
|
7
|
+
|
|
8
|
+
**Skills vs commands.** The lifecycle skills are read by Claude, which exercises
|
|
9
|
+
judgment. `/spec-connect` and `/spec-live` are **slash commands** instead — each
|
|
10
|
+
pre-executes one `spec-env` verb and relays it, so only you can run them; a
|
|
11
|
+
skill that wants one will tell you to type it.
|
|
12
|
+
|
|
13
|
+
The skill table, the spec type/folder conventions and the per-spec isolation
|
|
14
|
+
model all live in **`.claude/rules/spec-planning.md`**, the canonical reference
|
|
15
|
+
every spec skill points at. Tailor its per-phase test commands to this stack.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Put one spec live on the already-running dev server
|
|
3
|
-
argument-hint: "[
|
|
2
|
+
description: Put one spec live on the already-running dev server — `<spec>` takes it, a bare `take` takes the spec you are on, `main` hands the instance back
|
|
3
|
+
argument-hint: "[<spec> | main | take | release | abort | status]"
|
|
4
4
|
allowed-tools: Bash({{exec}} skitterspec spec-env live:*)
|
|
5
5
|
disable-model-invocation: true
|
|
6
6
|
---
|
package/assets/core/SETUP.md
CHANGED
|
@@ -168,7 +168,7 @@ field:
|
|
|
168
168
|
|
|
169
169
|
Everything else (state names, field ownership) has sensible defaults — see
|
|
170
170
|
`linear.config.md` to customise. The moment this file exists, the Linear steps in
|
|
171
|
-
`/spec` and `/spec-
|
|
171
|
+
`/spec` and `/spec-start` and the three sync skills switch on.
|
|
172
172
|
|
|
173
173
|
> Editing by hand skips the state-name check described above. If you go this
|
|
174
174
|
> route and your workspace renamed any state, `/spec-push` catches it at your
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Opt-in config for per-spec isolation (git worktree + optional namespaced Docker
|
|
4
4
|
stack + host dev servers + a front-door proxy + an optional opener per
|
|
5
|
-
in-progress spec). Provisioning is folded into `/spec-
|
|
5
|
+
in-progress spec). Provisioning is folded into `/spec-start`, teardown into
|
|
6
6
|
`/spec-complete` · `/spec-cancel`, and traffic diversion is `/spec-connect`; the
|
|
7
7
|
`skitterspec spec-env <up|down|prune|dev|connect|integrate>` CLI is the engine
|
|
8
8
|
beneath them.
|
|
9
9
|
|
|
10
|
-
**Once this file is present, isolation is the default policy:** `/spec-
|
|
10
|
+
**Once this file is present, isolation is the default policy:** `/spec-start` gives
|
|
11
11
|
**every** in-progress spec its own git worktree automatically. Docker is a **per-
|
|
12
12
|
spec escalation** — a spec brings up a stack only when its `> **Stack:**` header
|
|
13
13
|
is `worktree + docker` (set at `/spec` when it touches the DB / stateful
|
|
@@ -28,6 +28,22 @@ no live `env.config.json` was found.
|
|
|
28
28
|
```jsonc
|
|
29
29
|
{
|
|
30
30
|
// Where sibling worktrees are created and how their dirs are named.
|
|
31
|
+
// Where a spec's branch gets built.
|
|
32
|
+
//
|
|
33
|
+
// "worktree" (default) — every spec gets its own git worktree. Several
|
|
34
|
+
// specs run side by side and `main` stays free, at the cost of
|
|
35
|
+
// one terminal session per spec (`/spec-start` sets it up for you).
|
|
36
|
+
// "checkout" — the branch is built in the primary checkout instead. One
|
|
37
|
+
// spec at a time, but no second session and no hand-off: the
|
|
38
|
+
// terminal you are already in follows the work.
|
|
39
|
+
//
|
|
40
|
+
// Pick it for how you work, not for what this repo contains — a project with
|
|
41
|
+
// no dev servers may still want several specs in flight. An unrecognised
|
|
42
|
+
// value falls back to "worktree" rather than erroring.
|
|
43
|
+
//
|
|
44
|
+
// Not to be confused with `seedFiles.mode`, which is "symlink" | "copy".
|
|
45
|
+
"mode": "worktree",
|
|
46
|
+
|
|
31
47
|
"worktree": {
|
|
32
48
|
"root": "../{repo}-wt", // dir that holds all spec worktrees; sibling of
|
|
33
49
|
// the primary checkout, never nested inside it.
|
|
@@ -108,9 +124,13 @@ no live `env.config.json` was found.
|
|
|
108
124
|
"host": "127.0.0.1" // bind host for the canonical ports
|
|
109
125
|
},
|
|
110
126
|
|
|
111
|
-
// Optional, editor/terminal-agnostic opener
|
|
112
|
-
//
|
|
113
|
-
//
|
|
127
|
+
// Optional, editor/terminal-agnostic opener. `/spec-start` RUNS it when it hands
|
|
128
|
+
// you into a new worktree — after provisioning and bootstrap, so the session
|
|
129
|
+
// opens onto a tree that is ready to work in. The template is expanded with
|
|
130
|
+
// {worktreePath}, {slug}, {branch}, {projectName}, {portOffset}.
|
|
131
|
+
// Empty = nothing is opened (the path is just printed), which is how you turn
|
|
132
|
+
// the auto-open off. A non-interactive run skips it either way — an opened
|
|
133
|
+
// window nobody is sitting at helps no one.
|
|
114
134
|
// Examples: "code {worktreePath}", "tmux new-window -c {worktreePath}",
|
|
115
135
|
// or a "warp://..." deeplink for Warp users.
|
|
116
136
|
"open": {
|
|
@@ -148,7 +168,7 @@ no live `env.config.json` was found.
|
|
|
148
168
|
"refuseTeardownIfUnpushed": true
|
|
149
169
|
},
|
|
150
170
|
|
|
151
|
-
// What teardown cleans up beyond this machine. `/spec-
|
|
171
|
+
// What teardown cleans up beyond this machine. `/spec-start` pushes the spec
|
|
152
172
|
// branch when it provisions, so without this a completed spec leaves a merged
|
|
153
173
|
// branch on the remote forever. `deleteRemoteBranch`:
|
|
154
174
|
// "prompt" (default) — plan `git push <remote> --delete <branch>` in its own
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# `linear.config.json` — Linear one-way sync config
|
|
2
2
|
|
|
3
3
|
Opt-in config for the Linear sync (`/spec-status`, `/spec-push`, and the
|
|
4
|
-
Linear-aware paths of `/spec` and `/spec-
|
|
4
|
+
Linear-aware paths of `/spec` and `/spec-start`). Sync is **one-way**: the repo is
|
|
5
5
|
the source of truth and the Linear **issue** is a **generated mirror**. A spec is
|
|
6
6
|
a Linear issue and each phase a sub-issue; a phase's tasks ride along inside
|
|
7
7
|
that sub-issue's description as a read-only checklist. Content is
|
|
@@ -11,7 +11,7 @@ is a read-only drift report. The `sync.fieldOwnership` map now just selects the
|
|
|
11
11
|
projection field set (every field is repo-owned and pushed).
|
|
12
12
|
|
|
13
13
|
**Every Linear step is gated on this file.** While `specs/.core/linear.config.json`
|
|
14
|
-
is absent the feature is simply unused — `/spec`, `/spec-
|
|
14
|
+
is absent the feature is simply unused — `/spec`, `/spec-start`, and the CLI's
|
|
15
15
|
`spec-sync` subcommands behave exactly as they do today (local-only). Adopt it by
|
|
16
16
|
copying `linear.config.json.example` → `linear.config.json` here and filling in
|
|
17
17
|
your team ID (and an optional grouping project).
|
|
@@ -88,8 +88,12 @@ absence). A `sync.fieldOwnership` value outside `both|pull|push` is a hard error
|
|
|
88
88
|
// The project's OWN deployment ladder — where a ticket goes AFTER its spec is
|
|
89
89
|
// complete. Empty (the default) means no ladder is declared and every
|
|
90
90
|
// stage-aware path is unused. See "The deployment ladder" below.
|
|
91
|
+
//
|
|
92
|
+
// `ignorePaths` is what `released`/`stage` treat as BOOKKEEPING rather than
|
|
93
|
+
// shipped work — see "Bookkeeping commits" below. `[]` opts out.
|
|
91
94
|
"release": {
|
|
92
|
-
"stages": []
|
|
95
|
+
"stages": [],
|
|
96
|
+
"ignorePaths": ["specs/"]
|
|
93
97
|
},
|
|
94
98
|
|
|
95
99
|
// Git branch name derived for a linked spec. Tokens: {type}, {slug},
|
|
@@ -168,6 +172,44 @@ Run `skitterspec spec-sync states` to see the whole configured vocabulary — th
|
|
|
168
172
|
bucket map and the ladder — against what the workspace actually has.
|
|
169
173
|
|
|
170
174
|
|
|
175
|
+
## Bookkeeping commits (`release.ignorePaths`)
|
|
176
|
+
|
|
177
|
+
`spec-sync released` and `spec-sync stage` answer "what did this release
|
|
178
|
+
contain?" from the `Refs:` trailers in the range. Left alone, that over-answers:
|
|
179
|
+
a spec's `chore(spec): complete <name>` commit carries the **same ref** as the
|
|
180
|
+
code it describes, but lands **after** the tag that shipped that code — so the
|
|
181
|
+
ticket turns up in two consecutive release ranges, once for its code and once
|
|
182
|
+
for its paperwork. Downstream, a deployment ladder then drags an issue that had
|
|
183
|
+
already reached the top back down a rung.
|
|
184
|
+
|
|
185
|
+
`release.ignorePaths` names the repo-relative prefixes that are paperwork:
|
|
186
|
+
|
|
187
|
+
```jsonc
|
|
188
|
+
"release": {
|
|
189
|
+
"ignorePaths": ["specs/"]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
- **Paths, not subjects.** `chore(spec):` is a convention a mislabelled commit
|
|
194
|
+
escapes; what a commit changed is a fact. A commit touching an ignored path
|
|
195
|
+
**and** a source file still counts — it shipped code.
|
|
196
|
+
- **Prefixes, not globs.** `specs` and `specs/` both mean the directory, and a
|
|
197
|
+
prefix matches only on a path boundary, so `specs/` never swallows
|
|
198
|
+
`specs-archive/`. Name a single file to ignore just that file.
|
|
199
|
+
- **Only a commit whose paths are ALL ignored is dropped**, and only when git
|
|
200
|
+
actually listed paths for it. A merge commit (for which git lists none) counts,
|
|
201
|
+
as does every commit if the path read fails — a lookup that saw nothing knows
|
|
202
|
+
nothing, and dropping a ticket nobody notices is worse than the double-count
|
|
203
|
+
this is fixing.
|
|
204
|
+
- **Every drop is disclosed.** The report says `N commit(s) ignored as
|
|
205
|
+
bookkeeping`, and `--json` carries `ignored` / `ignoredCommits`.
|
|
206
|
+
- **`[]` is the opt-out**; a blank entry is a hard error, since `""` is a prefix
|
|
207
|
+
of every path and would silently empty the release.
|
|
208
|
+
|
|
209
|
+
Default: `["specs/"]`. A project that keeps its paperwork elsewhere names its own
|
|
210
|
+
directories instead.
|
|
211
|
+
|
|
212
|
+
|
|
171
213
|
## Spec → Issue, phases → sub-issues
|
|
172
214
|
|
|
173
215
|
Push maps the spec's structure to Linear's, keyed by id so it updates rather than
|
|
@@ -323,7 +365,7 @@ default for anyone who never sets one.
|
|
|
323
365
|
`save_issue` calls to mirror, N being its phase count.
|
|
324
366
|
- `"deferred"` — only once the work starts. A spec sitting in `specs/backlog/`
|
|
325
367
|
mirrors as **the issue alone**; its sub-issues are created by the push that
|
|
326
|
-
follows `/spec-
|
|
368
|
+
follows `/spec-start`.
|
|
327
369
|
- `"inline"` — never. Each phase becomes a **section of the spec issue's own
|
|
328
370
|
description**, with its full task list, and the `## Phases` index stays as the
|
|
329
371
|
table of contents. One issue per spec, however many phases it has.
|
|
@@ -11,7 +11,8 @@ and lifecycle stay consistent. Each sets a status on the spec header
|
|
|
11
11
|
| `/spec-bug` | (Bug) Reproduce with a failing test, capture spec, drive red→green | `In Progress` | `specs/in-progress/` |
|
|
12
12
|
| `/spec-hotfix` | (Hotfix) Fork a worktree from a release tag, red→green, land by tag + cherry-pick | `In Progress` | `specs/in-progress/` |
|
|
13
13
|
| `/spec-review` | Re-validate a spec against the codebase; refresh stale parts | `—` | (unchanged) |
|
|
14
|
-
| `/spec-
|
|
14
|
+
| `/spec-start` | Put a spec in flight on this checkout, then build phase 1 | `In Progress` | `specs/in-progress/` |
|
|
15
|
+
| `/spec-next` | Build the next phase of the spec in flight (re-run per phase) | `In Progress` (unchanged) | (unchanged) |
|
|
15
16
|
| `/spec-to-main` | Land the branch on the base (rebase + ff) **without** finishing — for running the work in CI / a shared env mid-spec; repeatable | `In Progress` (unchanged) | (unchanged) |
|
|
16
17
|
| `/spec-complete` | Verify all phases done + tests green; land + tear down | `Complete` | `specs/complete/` |
|
|
17
18
|
| `/spec-cancel` | Record progress, stamp a reason on the header; tear down | `Cancelled` | `specs/cancelled/` |
|
|
@@ -29,7 +30,7 @@ it.
|
|
|
29
30
|
real judgment (green tests before a land; an MCP fetch and a team-key check; ten
|
|
30
31
|
subcommands) — but they are marked user-only too, since nobody reaches them
|
|
31
32
|
except by typing them. Everything else in the table above stays model-invocable,
|
|
32
|
-
which is what lets `/spec-
|
|
33
|
+
which is what lets `/spec-next` hand off to `/spec-push` as work progresses.
|
|
33
34
|
|
|
34
35
|
Status flow: `Ready → In Progress → Complete` (or `Cancelled` from any state).
|
|
35
36
|
`/spec` grills to a **Ready** spec directly — there is no separate grooming
|
|
@@ -41,21 +42,33 @@ mid-spec (so the work can run in CI / a shared test env) while the spec stays
|
|
|
41
42
|
`In Progress` in `specs/in-progress/`; it's the intermediate, repeatable half of
|
|
42
43
|
`/spec-complete`'s landing, without the finalise-and-tear-down.
|
|
43
44
|
|
|
45
|
+
**Two workspace modes.** `specs/.core/env.config.json` → `mode` decides where a
|
|
46
|
+
spec's branch is built. **`worktree`** (the default) gives each spec its own
|
|
47
|
+
checkout — several specs at once and `main` left free, at the cost of one
|
|
48
|
+
terminal session per spec, which `/spec-start` sets up for you. **`checkout`** builds
|
|
49
|
+
the branch in the primary checkout instead: one spec at a time, but no second
|
|
50
|
+
session and no hand-off, so the terminal you are already in follows the work.
|
|
51
|
+
Pick it for how you work rather than for what the project contains — a repo with
|
|
52
|
+
no dev servers may still want several specs in flight. In `checkout` mode
|
|
53
|
+
`/spec-connect` and `/spec-live` do not apply and say so: both exist to reach
|
|
54
|
+
work that lives elsewhere, which is the gap that mode removes.
|
|
55
|
+
|
|
44
56
|
**Per-spec isolation (opt-in to adopt, then the default policy).** When a project
|
|
45
57
|
adopts isolation (`skitterspec init --isolation`, or `specs/.core/env.config.json`
|
|
46
|
-
present), `/spec-
|
|
58
|
+
present), `/spec-start` gives **every** in-progress spec its own git worktree
|
|
47
59
|
automatically — several specs run side by side without stashing or clashing, and
|
|
48
60
|
`main` stays free. Docker is a **per-spec escalation**: `/spec` records
|
|
49
61
|
`> **Stack:** worktree` (default) or `worktree + docker` when the spec touches the
|
|
50
|
-
DB / stateful services, and `/spec-
|
|
51
|
-
latter. `/spec-
|
|
62
|
+
DB / stateful services, and `/spec-start` brings up a namespaced stack only for the
|
|
63
|
+
latter. `/spec-start` also starts the project's host **dev servers** (`env.config`
|
|
52
64
|
→ `dev`) on the spec's ports; **`/spec-connect <name>`** then exposes that spec on
|
|
53
65
|
your canonical `localhost` ports so you can test it at the normal URL
|
|
54
66
|
(`/spec-connect main` hands them back). All housekeeping (the backlog→in-progress
|
|
55
67
|
move, header edits, the code) happens on the spec's branch in the worktree; `main`
|
|
56
68
|
changes only when it merges. Teardown is folded into `/spec-complete` ·
|
|
57
69
|
`/spec-cancel`. Beneath the skills, `skitterspec spec-env
|
|
58
|
-
<up|down|prune|dev|connect|integrate|hotfix>` is the CLI
|
|
70
|
+
<up|down|prune|dev|connect|integrate|hotfix|live|status|resolve>` is the CLI
|
|
71
|
+
engine (omit the spec name and it uses the worktree you are standing in). Teardown drops
|
|
59
72
|
the finished spec's own test-DB volume; `spec-env prune` additionally reaps
|
|
60
73
|
**orphaned** volumes left by declined/aborted teardowns, so `/spec-complete` and
|
|
61
74
|
`/spec-cancel` also sweep orphans (confirm-first). A **hotfix** is the one
|
|
@@ -82,6 +95,13 @@ Beneath it, `skitterspec spec-env live <take|release|abort|status>` is the engin
|
|
|
82
95
|
tracker-free: it knows nothing about any specific ticketing system. A
|
|
83
96
|
ticketing provider is installed as its own distribution that plugs into named
|
|
84
97
|
**seams** in the shared skills and fulfils a skill-name + CLI contract.
|
|
98
|
+
|
|
99
|
+
Part of that contract is the **binary name**: the shipped `/spec-connect` and
|
|
100
|
+
`/spec-live` commands invoke `skitterspec`, so a superset that replaces the base
|
|
101
|
+
must expose that name too, alongside whatever it calls itself — one entry point
|
|
102
|
+
under two names. A distribution shipping only its own name leaves those commands
|
|
103
|
+
failing with `command not found`, which reads as a broken install rather than a
|
|
104
|
+
missing alias.
|
|
85
105
|
Sync is **one-way**: the repo is the source of truth and the tracker is a
|
|
86
106
|
**generated mirror**. It ships `/spec-push` (repo→tracker; computes a create/update plan
|
|
87
107
|
against a committed last-pushed snapshot and applies it) and `/spec-status`
|
|
@@ -91,7 +111,7 @@ the tracker is never read back or merged.
|
|
|
91
111
|
|
|
92
112
|
**Every skill that moves a spec through the lifecycle carries a seam**, so the
|
|
93
113
|
mirror keeps up without anyone remembering to push: `/spec`, `/spec-bug` and
|
|
94
|
-
`/spec-hotfix` link the spec they create; `/spec-
|
|
114
|
+
`/spec-hotfix` link the spec they create; `/spec-next` refreshes it as work starts;
|
|
95
115
|
`/spec-complete`, `/spec-cancel` and `/spec-review` refresh it after they change
|
|
96
116
|
it. `/spec-to-main` and `/spec-live` carry none — they change no status.
|
|
97
117
|
With no provider installed the seams are empty and every skill behaves as a plain
|
|
@@ -134,11 +154,11 @@ status.
|
|
|
134
154
|
Every spec header carries:
|
|
135
155
|
|
|
136
156
|
- `> **Name:**` — the spec's folder name (`feat-`/`bug-`/`hotfix-<kebab-name>`).
|
|
137
|
-
It's the handle you pass to `/spec-
|
|
157
|
+
It's the handle you pass to `/spec-start` and the other lifecycle skills, surfaced
|
|
138
158
|
in the header so it's copy-pasteable without digging for the folder name.
|
|
139
159
|
- `> **Author:**` — who created the spec (set at `/spec` / `/spec-bug`, defaults
|
|
140
160
|
to `git config user.name`).
|
|
141
|
-
- `> **Developer:**` — who implements it (`—` until `/spec-
|
|
161
|
+
- `> **Developer:**` — who implements it (`—` until `/spec-start` starts work, then
|
|
142
162
|
set to `git config user.name`; `/spec-bug` sets it immediately).
|
|
143
163
|
|
|
144
164
|
Every spec also has a **State log** table — the audit trail of folder/status
|
|
@@ -174,7 +194,7 @@ When asked for a plan, implementation strategy, or feature breakdown:
|
|
|
174
194
|
|
|
175
195
|
```
|
|
176
196
|
specs/backlog/ Ready (or Draft) specs (/spec)
|
|
177
|
-
specs/in-progress/ under active implementation (/spec-
|
|
197
|
+
specs/in-progress/ under active implementation (/spec-start, /spec-bug)
|
|
178
198
|
specs/complete/ finished (/spec-complete)
|
|
179
199
|
specs/cancelled/ abandoned, with a reason on the header (/spec-cancel)
|
|
180
200
|
specs/.core/ project rules — ALWAYS APPLY, never moved
|
|
@@ -6,10 +6,10 @@ description: Create a new spec-driven-development spec. Grills the user to a cle
|
|
|
6
6
|
# /spec — author a new spec
|
|
7
7
|
|
|
8
8
|
Produce ONE concise spec in `specs/backlog/`. Do not start coding — this skill
|
|
9
|
-
plans only. Implementation happens later via `/spec-
|
|
9
|
+
plans only. Implementation happens later via `/spec-start`.
|
|
10
10
|
|
|
11
11
|
Lifecycle (the governing skills) — status in parentheses:
|
|
12
|
-
`/spec` (writes **Ready** when fully groomed, else Draft; backlog) → `/spec-
|
|
12
|
+
`/spec` (writes **Ready** when fully groomed, else Draft; backlog) → `/spec-start`
|
|
13
13
|
(In Progress, in-progress; implement phase 1) → `/spec-complete` (Complete) /
|
|
14
14
|
`/spec-cancel` (Cancelled). See `.claude/rules/spec-planning.md`. (There is no
|
|
15
15
|
separate grooming command — `/spec` grills to a Ready spec directly.)
|
|
@@ -91,7 +91,7 @@ it happens differs (`/spec` writes the spec in Phase B, `/spec-bug` in its step
|
|
|
91
91
|
|
|
92
92
|
- **Stamp `linear_identifier` and `linear_url`** in `00-overview.md` frontmatter
|
|
93
93
|
from the adopted issue. That is the whole link: every later skill
|
|
94
|
-
(`/spec-push`, `/spec-status`, `/spec-
|
|
94
|
+
(`/spec-push`, `/spec-status`, `/spec-start`) keys off it being present.
|
|
95
95
|
- **Do not run the project picker** and never send `project`. The issue was filed
|
|
96
96
|
somewhere deliberately — where it lives is Linear's business, and adoption is
|
|
97
97
|
not a mint.
|
|
@@ -113,7 +113,12 @@ not write the spec until this is resolved.
|
|
|
113
113
|
|
|
114
114
|
- Break the problem into **distinctive areas** and work them in logical order,
|
|
115
115
|
resolving dependencies between decisions one at a time.
|
|
116
|
-
-
|
|
116
|
+
- **Batch independent questions; sequence dependent ones.** When several
|
|
117
|
+
questions do not affect each other's answers, put them to the user together
|
|
118
|
+
(up to four at once — use the harness's multi-question ask tool where it has
|
|
119
|
+
one) rather than spending a round trip on each. When an answer would change
|
|
120
|
+
what you ask next, ask that one alone and wait for it. Give your
|
|
121
|
+
**recommended answer** either way.
|
|
117
122
|
- If a question can be answered by **reading the codebase, read it** instead of
|
|
118
123
|
asking. Verify endpoints/models/files actually exist before relying on them.
|
|
119
124
|
- Cover, at minimum, the areas that apply:
|
|
@@ -132,7 +137,7 @@ not write the spec until this is resolved.
|
|
|
132
137
|
this spec touch the DB / stateful services (so its worktree needs a Docker
|
|
133
138
|
stack), or is a plain worktree enough? Default `worktree`; escalate to
|
|
134
139
|
`worktree + docker` only when it must. This sets the `> **Stack:**` header
|
|
135
|
-
that `/spec-
|
|
140
|
+
that `/spec-start` acts on (it can be escalated later). Skip when isolation
|
|
136
141
|
isn't enabled — leave the default `worktree`.
|
|
137
142
|
10. **Open questions** — anything still undecided.
|
|
138
143
|
|
|
@@ -185,7 +190,7 @@ the codebase, link rather than duplicate):
|
|
|
185
190
|
# <Feature title>
|
|
186
191
|
|
|
187
192
|
> **Type:** Feature
|
|
188
|
-
> **Name:** feat-<kebab-name> (the spec folder name — the handle you paste into `/spec-
|
|
193
|
+
> **Name:** feat-<kebab-name> (the spec folder name — the handle you paste into `/spec-start`)
|
|
189
194
|
> **Status:** Ready — not started
|
|
190
195
|
> **Author:** <git user.name — `git config user.name`>
|
|
191
196
|
> **Developer:** —
|
|
@@ -281,7 +286,7 @@ Keep the `00-overview.md` phase index and the phase files in sync: the index row
|
|
|
281
286
|
is the one-line summary + status; the phase file is the detail.
|
|
282
287
|
|
|
283
288
|
The **State log** is the audit trail of folder/status transitions — every
|
|
284
|
-
lifecycle skill (`/spec-
|
|
289
|
+
lifecycle skill (`/spec-start`, `/spec-complete`, `/spec-cancel`) appends one row
|
|
285
290
|
when it moves the spec. The **Changelog** is for decisions and course-corrections
|
|
286
291
|
only — keep the two separate.
|
|
287
292
|
|
|
@@ -313,14 +318,14 @@ Rules for the spec body:
|
|
|
313
318
|
After writing, tell the user the path and that it's **`Ready`** in `backlog`
|
|
314
319
|
(grilling in Phase A resolved the open questions). If you deliberately left open
|
|
315
320
|
questions unresolved, write `Draft` instead and say what still needs deciding.
|
|
316
|
-
Either way, the next step is `/spec-
|
|
321
|
+
Either way, the next step is `/spec-start` to start building.
|
|
317
322
|
|
|
318
323
|
## Phase D — record the isolation stack (only if configured)
|
|
319
324
|
|
|
320
325
|
**Only when `specs/.core/env.config.json` exists** (per-spec isolation is
|
|
321
326
|
enabled), make sure the `> **Stack:**` header reflects the Phase A item 9
|
|
322
327
|
decision — `worktree` (default) or `worktree + docker` when it touches the DB /
|
|
323
|
-
stateful services. Nothing to provision now: `/spec-
|
|
328
|
+
stateful services. Nothing to provision now: `/spec-start` gives every in-progress
|
|
324
329
|
spec its own worktree automatically, and brings up Docker only when the Stack
|
|
325
330
|
says so. Mention the operator can escalate the Stack later (edit the header, or
|
|
326
331
|
run `skitterspec spec-env up <name>` to add Docker to an existing worktree). If
|
|
@@ -370,7 +375,7 @@ does — you never create the issue by hand:
|
|
|
370
375
|
`spec-sync record`. That path is fully supported — it is what anyone without
|
|
371
376
|
an API key uses.
|
|
372
377
|
5. **Echo the branch name** from `branch.pattern` so the user knows what
|
|
373
|
-
`/spec-
|
|
378
|
+
`/spec-start` will fork.
|
|
374
379
|
|
|
375
380
|
**If Linear can't be reached**, say so in one line and leave the spec written and
|
|
376
381
|
local — it is still a perfectly good spec, and `/spec-push` links it later. Do
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spec-bug
|
|
3
|
-
description: Investigate a bug, capture it as a Bug-type spec, and drive it red→green.
|
|
3
|
+
description: Investigate a bug, capture it as a Bug-type spec, and drive it red→green. ALWAYS starts by reproducing the bug with a failing test, then writes the spec and works the test to green — on the bug's own branch, never on main. Use when the user reports a bug, says "/spec-bug", "investigate this bug", "this is broken — find and fix it", or pastes an error/stack trace.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# /spec-bug — investigate a bug, prove it with a failing test, fix it
|
|
@@ -90,7 +90,7 @@ it happens differs (`/spec` writes the spec in Phase B, `/spec-bug` in its step
|
|
|
90
90
|
|
|
91
91
|
- **Stamp `linear_identifier` and `linear_url`** in `00-overview.md` frontmatter
|
|
92
92
|
from the adopted issue. That is the whole link: every later skill
|
|
93
|
-
(`/spec-push`, `/spec-status`, `/spec-
|
|
93
|
+
(`/spec-push`, `/spec-status`, `/spec-start`) keys off it being present.
|
|
94
94
|
- **Do not run the project picker** and never send `project`. The issue was filed
|
|
95
95
|
somewhere deliberately — where it lives is Linear's business, and adoption is
|
|
96
96
|
not a mint.
|
|
@@ -127,7 +127,7 @@ place), skip this whole section and fix on the current branch — same as when
|
|
|
127
127
|
isolation is off. Warn that the fix will land wherever you currently are (usually
|
|
128
128
|
`main`); reserve it for a trivial one-liner or an explicit request.
|
|
129
129
|
|
|
130
|
-
A bug fix changes real source, so — exactly like `/spec-
|
|
130
|
+
A bug fix changes real source, so — exactly like `/spec-start` — it belongs on the
|
|
131
131
|
bug's **own branch**, never directly on `main`. Provision the worktree **now**,
|
|
132
132
|
before the failing test, so the test, the fix, and the spec all land together and
|
|
133
133
|
arrive as one reviewable PR.
|
|
@@ -201,7 +201,7 @@ because work is already underway. Keep it lean:
|
|
|
201
201
|
# Bug: <short title>
|
|
202
202
|
|
|
203
203
|
> **Type:** Bug
|
|
204
|
-
> **Name:** bug-<kebab-name> (the spec folder name — the handle you paste into `/spec-
|
|
204
|
+
> **Name:** bug-<kebab-name> (the spec folder name — the handle you paste into `/spec-start`)
|
|
205
205
|
> **Status:** In Progress — fixing (red test added)
|
|
206
206
|
> **Author:** <git user.name — who reported/captured it>
|
|
207
207
|
> **Developer:** <git user.name — you, since you're fixing it now>
|
|
@@ -237,8 +237,10 @@ Service, CLI command, Config key, Skill/rule, Business rule — or whatever fits
|
|
|
237
237
|
this project (skitterspec itself is a CLI with no HTTP surface). Keep `Detail`
|
|
238
238
|
terse — names/signatures, not sentences. List **only** surfaces that actually
|
|
239
239
|
change; the heading is always present, but if nothing external changes write the
|
|
240
|
-
single line below instead of an empty table
|
|
241
|
-
|
|
240
|
+
single line below instead of an empty table.>
|
|
241
|
+
|
|
242
|
+
<A bug fix often changes no external surface — that's fine, use the
|
|
243
|
+
one-liner.>
|
|
242
244
|
|
|
243
245
|
| Surface | Change | Detail |
|
|
244
246
|
|---------|--------|--------|
|
|
@@ -295,7 +297,7 @@ does — you never create the issue by hand:
|
|
|
295
297
|
`spec-sync record`. That path is fully supported — it is what anyone without
|
|
296
298
|
an API key uses.
|
|
297
299
|
5. **Echo the branch name** from `branch.pattern` so the user knows what
|
|
298
|
-
`/spec-
|
|
300
|
+
`/spec-start` will fork.
|
|
299
301
|
|
|
300
302
|
**If Linear can't be reached**, say so in one line and leave the spec written and
|
|
301
303
|
local — it is still a perfectly good spec, and `/spec-push` links it later. Do
|
|
@@ -312,6 +314,38 @@ and **never auto-push git** — Linear's own automation reacts to real branch/PR
|
|
|
312
314
|
events later. Report the Linear issue URL as part of the skill's finish-up
|
|
313
315
|
message.
|
|
314
316
|
|
|
317
|
+
### Picking the Linear Project
|
|
318
|
+
|
|
319
|
+
Run this **only when minting a spec issue** — creating it for the first time. On
|
|
320
|
+
an update the issue already has a project (or deliberately has none), and that
|
|
321
|
+
placement is **Linear's to own**: never send `project` on an update, and never
|
|
322
|
+
record the choice in the spec file or the snapshot. A PM re-homing a spec issue
|
|
323
|
+
must not show up as drift or be overwritten on the next push.
|
|
324
|
+
|
|
325
|
+
1. **List the candidates.** Ask the engine:
|
|
326
|
+
`skitterspec spec-sync projects --json`. On the API path it returns the team's
|
|
327
|
+
projects; on the MCP path it says so, and you call the discovered project-list
|
|
328
|
+
tool instead. Drop archived / completed projects — they can't take new work.
|
|
329
|
+
2. **Offer them.** Show the names (most recently updated first is fine), plus an
|
|
330
|
+
explicit **None (team only)** option. Pre-select `linear.projectId` from
|
|
331
|
+
`linear.config.json` when it's set and still in the list; otherwise pre-select
|
|
332
|
+
**None**.
|
|
333
|
+
3. **Narrow on request.** If the user types a fragment rather than choosing, filter
|
|
334
|
+
the list case-insensitively by name and re-offer. Don't re-fetch.
|
|
335
|
+
4. **Never offer to create a project.** Projects are the PM's surface — if none
|
|
336
|
+
fits, that's **None (team only)**, and someone makes the project in Linear.
|
|
337
|
+
5. **Pass it once**, to whichever thing mints the issue: `--project <chosen id>`
|
|
338
|
+
on `spec-sync apply`, or `project: <chosen id>` on the MCP issue-create call.
|
|
339
|
+
Chose None → omit it entirely (do not pass an empty string).
|
|
340
|
+
|
|
341
|
+
**Degrade, never block.** If the list can't be fetched — Linear not connected, no
|
|
342
|
+
project-list tool, no API key, or `spec-sync projects` reporting it couldn't ask —
|
|
343
|
+
say so in one line — *"project picker unavailable"* — and carry on with
|
|
344
|
+
`linear.projectId` if it's set, else no project at all. A missing picker must never fail the skill that called it.
|
|
345
|
+
|
|
346
|
+
If `linear.projectId` is set but that Project is archived or missing, relay
|
|
347
|
+
Linear's error and stop rather than silently minting an unparented issue.
|
|
348
|
+
|
|
315
349
|
## 5. Drive to GREEN
|
|
316
350
|
|
|
317
351
|
- Implement the **minimal, root-cause** fix. Match surrounding code; honour all
|
|
@@ -322,12 +356,12 @@ message.
|
|
|
322
356
|
|
|
323
357
|
If the root cause is large/uncertain and can't be fixed in one pass: keep the red
|
|
324
358
|
test, split the fix into phase files (`01-<slug>.md` …) with a phase index in
|
|
325
|
-
`00-overview.md`, and leave the spec in `in-progress` for `/spec-
|
|
359
|
+
`00-overview.md`, and leave the spec in `in-progress` for `/spec-next` to continue.
|
|
326
360
|
Say so explicitly — don't fake green.
|
|
327
361
|
|
|
328
362
|
**Then refresh the mirror (only if a provider is installed).** The Fix tasks are
|
|
329
363
|
ticked, so the repo is now the truth about this fix — and this skill can take a
|
|
330
|
-
bug all the way to green without `/spec-
|
|
364
|
+
bug all the way to green without `/spec-next` ever running. Without a provider this
|
|
331
365
|
is a no-op.
|
|
332
366
|
|
|
333
367
|
**Only when `specs/.core/linear.config.json` exists** and the spec carries a
|