@gobing-ai/spur 0.3.55 → 0.3.57

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 (27) hide show
  1. package/.claude-plugin/marketplace.json +2 -3
  2. package/config/corpus-baseline.json +2521 -49
  3. package/config/rules/strict/runtime-boundaries.yaml +3 -0
  4. package/config/rules/surface/check-cli-surface.yaml +1 -0
  5. package/config/workflow-composition-baseline.json +241 -22
  6. package/package.json +1 -1
  7. package/plugins/sp/agents/expert-spur.md +3 -0
  8. package/plugins/sp/commands/dev-idea.md +7 -19
  9. package/plugins/sp/plugin.json +1 -1
  10. package/plugins/sp/scripts/task-size-precheck.ts +11 -6
  11. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +4 -4
  12. package/plugins/sp/skills/dogfood-testing/references/report-template.md +4 -2
  13. package/plugins/sp/skills/issue-finding/SKILL.md +23 -11
  14. package/plugins/sp/skills/spur-cli/SKILL.md +23 -15
  15. package/plugins/sp/skills/spur-cli/references/agent.md +5 -0
  16. package/plugins/sp/skills/spur-cli/references/builder.md +49 -0
  17. package/plugins/sp/skills/spur-cli/references/features.md +6 -1
  18. package/plugins/sp/skills/spur-cli/references/message.md +5 -0
  19. package/plugins/sp/skills/spur-cli/references/rules.md +5 -0
  20. package/plugins/sp/skills/spur-cli/references/self.md +101 -0
  21. package/plugins/sp/skills/spur-cli/references/tasks.md +6 -1
  22. package/plugins/sp/skills/spur-cli/references/team.md +5 -0
  23. package/plugins/sp/skills/spur-cli/references/workflows.md +40 -0
  24. package/plugins/sp/skills/spur-dev/references/dev-operations.md +9 -8
  25. package/plugins/sp/skills/spur-dev/references/execution-batch.md +19 -0
  26. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +27 -5
  27. package/spur.js +1546 -314
@@ -25,7 +25,7 @@ colon form — the dash form `sp-dogfood-testing@…` is rejected in new runs.
25
25
  Every dogfood run **always** writes **two** files — with or without `--save`:
26
26
 
27
27
  | Artifact | Path | Role |
28
- |----------|------|------|
28
+ | ---------- | ------ | ------ |
29
29
  | **Live** | `.spur/run/dogfood/<run_id>.md` | Mid-run SSOT; opened in Phase 1; ledger rows appended on every step resolve |
30
30
  | **Report** | `docs/dogfood/YYYY-MM-DD-<testee-slug>-dogfood.md` | Operator artifact; same content promoted on open + every step + finalize |
31
31
 
@@ -59,7 +59,7 @@ workspace_fingerprint: ← optional — recorded in Phase 1 for fix-mode and
59
59
  ### Status model (partial-OK)
60
60
 
61
61
  | `status` | When |
62
- |----------|------|
62
+ | ---------- | ------ |
63
63
  | `running` | Phase 1 opened; steps still in progress |
64
64
  | `aborted` | Finalize-or-abort after mid-run stop / incomplete narrative |
65
65
  | `complete` | Phase 4 finished a normal end-of-run report |
@@ -238,6 +238,7 @@ downstream task creation does not inherit an unactionable acceptance criterion:
238
238
  The tag is a prompt to whoever turns findings into tasks: `[stale]` → drop, `[unverifiable]` →
239
239
  reframe or defer, `[feasible]` → proceed. A finding without a tag is treated as `[feasible]`.
240
240
  Severity scale:
241
+
241
242
  - **P1** — blocks correct use or causes drift/wrong output; fix before shipping the testee.
242
243
  - **P2** — real friction or a latent correctness gap; fix soon. **Includes mandatory workspace-drift
243
244
  finding:** when a drift row (`drift:external`) is present in the ledger, a P2 finding naming the
@@ -310,6 +311,7 @@ Findings (P1+P2):
310
311
  ```
311
312
 
312
313
  Rules:
314
+
313
315
  - **Result** and **Tokens** lines are mandatory; always tag token numbers `[~estimate]`.
314
316
  - List Fixed / Unresolved / Findings; print `(none)` when empty — never omit a sub-list.
315
317
  - With `--full`, Findings include P3+P4.
@@ -139,14 +139,23 @@ sessions (typed ETL via `spur history` — or raw JSONL under the three fallback
139
139
  **Primary path (typed sources):** `spur history report --mode forensics` (task 0555).
140
140
 
141
141
  ```bash
142
- # 0568 R4: SPUR_BIN env > local CLI > PATH stale PATH spur fails history import.
143
- SPUR_BIN="${SPUR_BIN:-$([ -f apps/cli/src/index.ts ] && echo 'bun apps/cli/src/index.ts' || echo spur)}"
144
-
145
- $SPUR_BIN history import --source <source> --json # checkpoint resume
146
- $SPUR_BIN history analyze --json # writes versioned artifact (0554)
147
- $SPUR_BIN history report --mode forensics # pure renderer; latest artifact pointer
142
+ # 0568 R4 / 0504 R4: SPUR_BIN env > local CLI. NEVER a bare PATH `spur` for history validation —
143
+ # a stale global binary silently runs old code. If SPUR_BIN is unset and apps/cli/src/index.ts
144
+ # is absent, FAIL LOUDLY instead of falling back to PATH.
145
+ SPUR_BIN="${SPUR_BIN:-$([ -f apps/cli/src/index.ts ] && echo 'bun apps/cli/src/index.ts' || echo '')}"
146
+ [ -n "$SPUR_BIN" ] || { echo 'REFUSING: no source-local spur and SPUR_BIN unset (0504 R4)'; exit 1; }
147
+
148
+ $SPUR_BIN history import --source <source> --json # checkpoint resume; record provenance header
149
+ $SPUR_BIN history analyze --sessions <ids> --source <src> --json # narrow the artifact (T2: full run → 2.7 MB trap)
150
+ $SPUR_BIN history report --mode forensics # pure renderer; reads the LATEST artifact — verify it is the one you just wrote
148
151
  ```
149
152
 
153
+ **Artifact-size discipline:** `history analyze` without narrowing writes an artifact covering every
154
+ session in the DB — multi-MB blobs that drown the context. Narrow with `--sessions` / `--source` to
155
+ the corpus this investigation actually needs. `history report` renders whatever artifact the latest
156
+ pointer references; if you ran analyze for another purpose in between, re-run analyze (narrowed)
157
+ before reporting.
158
+
150
159
  The forensics renderer emits **8 CLI-derivable sections**: Session Data Summary, Tool Breakdown,
151
160
  Token Profile (tokens + cache-hit ratio — never prices), Time Decomposition, Per-Phase, Per-Tool
152
161
  Execution Time, Bottleneck Ranking, and the Raw Data appendix. The CLI does not write the
@@ -271,7 +280,9 @@ EOF
271
280
  spur task update <wbs> --section Background --from-file /tmp/issue-bg.md --json
272
281
  ```
273
282
 
274
- **Required sections for a meta issue-finding task:**
283
+ **Recommended sections for a meta issue-finding task** (live matrix `.spur/tasks/section-matrix.yaml`
284
+ meta variant — `Root Cause` is allowed at every status; `Notes` and `References` are **not** defined
285
+ sections and must not be authored):
275
286
 
276
287
  | Section | Content |
277
288
  | ------------------- | ---------------------------------------------------------------------------------------------------- |
@@ -281,17 +292,18 @@ spur task update <wbs> --section Background --from-file /tmp/issue-bg.md --json
281
292
  | Q&A | 4–6 Q&A pairs: rationale, approach, hook vs guidance, savings, decomposition |
282
293
  | Design | Per-fix evidence (counts, timestamps), fix content, target location |
283
294
  | Plan | Ordered checkboxes referencing requirements |
284
- | Notes | Root-cause analyses (RC1–RC*n*) with forensic evidence (meta template: **not** a Root Cause section) |
285
- | References | Session JSONL paths, source/agent, guard `file:line`, pipeline YAML, commits |
295
+ | Root Cause | RC1–RC*n* analyses with forensic evidence allowed at every status for meta tasks |
296
+
286
297
 
287
298
  **Section format rules** (from task 0379):
288
299
 
289
300
  1. **Solution `file:line` citations**: repo-relative `file:line` (e.g. `apps/web/src/components/SupervisorTab.tsx:17-20`), never bare `:line` or bare filename without path.
290
301
  2. **Review P1–P4 table**: if a Review section exists, include a table with a cell matching
291
302
  `/^\s*P[1-4]\s*$/` and a non-placeholder content cell.
292
- 3. **Meta template**: no `Root Cause` section put analyses in `Notes`.
303
+ 3. **Meta template**: `Root Cause` is allowed at every status for meta tasks (live matrix) —
304
+ put RC analyses there, never in `Notes` or `References` (undefined sections).
293
305
  4. **Canonical sections only**: `Background`, `Requirements`, `Acceptance Criteria`, `Q&A`,
294
- `Design`, `Plan`, `Solution`, `Root Cause`, `Testing`, `Review`, `References`, `History`, `Notes`.
306
+ `Design`, `Plan`, `Solution`, `Root Cause`, `Testing`, `Review`, `History`.
295
307
  5. **Section body**: body-only for `--section` (no duplicate heading).
296
308
  6. **Batch writes**: write all section temps → apply all `spur task update --section` calls →
297
309
  **one** `spur task check`. Never write-check-rewrite-check per section.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: spur-cli
3
- description: "The CLI facade for the `spur` command surface - one reference per noun (task/feature/rule/workflow/agent/message/team/init/status/serve): verbs, flags, `--json` shapes, exit codes, the CLI-gated write contract. NOT for driving the lifecycle (that is the spine, sp:spur-dev). Triggers: \"spur task\", \"spur feature\", \"spur rule\", \"spur workflow\", \"spur agent\", \"spur message\", \"spur team\", \"spur status\", \"spur init\", \"spur serve\", \"create a task\", \"task check\", \"batch-create\", or looking up any spur CLI verb or convention."
3
+ description: "The CLI facade for the `spur` command surface - one reference per noun (task/feature/rule/workflow/builder/agent/message/team/self): verbs, flags, `--json` shapes, exit codes, the CLI-gated write contract. NOT for driving the lifecycle (that is the spine, sp:spur-dev). Triggers: \"spur task\", \"spur feature\", \"spur rule\", \"spur workflow\", \"spur agent\", \"spur message\", \"spur team\", \"spur self\", \"spur self init\", \"spur self status\", \"create a task\", \"task check\", \"batch-create\", or looking up any spur CLI verb or convention."
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: spur
@@ -14,12 +14,11 @@ metadata:
14
14
  - feature
15
15
  - rule
16
16
  - workflow
17
+ - builder
17
18
  - agent
18
19
  - message
19
20
  - team
20
- - status
21
- - init
22
- - serve
21
+ - self
23
22
  openclaw:
24
23
  emoji: "🧰"
25
24
  ---
@@ -27,7 +26,7 @@ metadata:
27
26
  # spur-cli — the CLI facade for the Spur command surface
28
27
 
29
28
  `spur-cli` is the single reference for operating the **`spur` command-line surface**. Each `spur`
30
- noun (`task`, `feature`, `rule`, `workflow`, `agent`, `message`, `team`, `init`, `status`, `serve`) has one reference file that documents *what each verb
29
+ noun (`task`, `feature`, `rule`, `workflow`, `builder`, `agent`, `message`, `team`, `self`) has one reference file that documents *what each verb
31
30
  is, how to use it well, its flags, `--json` shapes, and exit codes*. This skill is a **facade /
32
31
  dispatch reference** — it tells you which verb does what and routes you to the noun's detail. It is
33
32
  **not** an orchestrator and contains **no competency logic**: the skill knows *how to invoke*; the
@@ -38,17 +37,17 @@ CLI knows *what is valid*; the **spine** (`sp:spur-dev`) knows *how to drive the
38
37
  Pick the noun, read its reference. Each Tier A and Tier B reference owns that noun's full verb catalog and conventions.
39
38
 
40
39
  | Tier | Noun | Operate | Reference |
41
- |------|------|---------|-----------|
40
+ | ------ | ------ | --------- | ----------- |
42
41
  | **Tier A** | **task** | Task corpus: create (variants), `deps` mutation, canonical `sections` (`init`/`add`/`list`), status lifecycle, `record`/`verdict` artifacts, `run-link`, `check --json` matrix | [references/tasks.md](references/tasks.md) |
43
42
  | **Tier A** | **feature** | Feature tree: author with hierarchical IDs (DD-14), acceptance criteria (Gherkin), status lifecycle, move subtrees, `check --json` | [references/features.md](references/features.md) |
44
43
  | **Tier A** | **rule** | Constraint quality gate: run presets, author rules, fine-tune, validate rule files/presets, extend engine | [references/rules.md](references/rules.md) |
45
44
  | **Tier A** | **workflow** | Dual-mode workflow runtime: author state-machine / transition-flow workflows, validate, run, read traces | [references/workflows.md](references/workflows.md) |
45
+ | **Tier A** | **builder** | Release plumbing: bump a package (or the `workspace:`-pinned set) with `bump-ver`, delete release tags with `drop-tags`, commit + tag + optional push | [references/builder.md](references/builder.md) |
46
46
  | **Tier B** | **agent** | Coding-agent execution surface: run prompts via detected/named agents, manage team agent specs, persistent self-draining loop, readiness check | [references/agent.md](references/agent.md) |
47
47
  | **Tier B** | **message** | Durable inter-agent messaging: send, inbox, reply, watch | [references/message.md](references/message.md) |
48
48
  | **Tier B** | **team** | Team coordination and supervision: assign, status, up/down rosters, start/stop supervised processes | [references/team.md](references/team.md) |
49
- | **Tier B** | **init** / **status** | Project scaffolding (`init`) + status overview; post-scaffold init validation probes & layout classification | [references/init.md](references/init.md) |
50
- | **Tier B** | **serve** | Local web server fallback: Task Kanban + team supervisor API | [references/serve.md](references/serve.md) |
51
- | **Tier C** | **history** / **migrate** / **projects** / **help** | Excluded while immature (see exclusion reasons below). Read `spur <noun> --help` as last resort | Last-resort `--help` |
49
+ | **Tier B** | **self** | Self-management verbs: scaffold (`init`), schema migrations (`migrate`), local web server (`serve`), status overview (`status`); `self init` runs post-scaffold validation probes & layout classification | [references/self.md](references/self.md) |
50
+ | **Tier C** | **history** / **projects** / **help** | Excluded while immature (see exclusion reasons below). Read `spur <noun> --help` as last resort | Last-resort `--help` |
52
51
 
53
52
  **Execute-First Contract:** Load `sp:spur-cli` references first to execute Tier A and Tier B commands directly without calling `spur --help`. Use `spur <noun> --help` only as a last resort for Tier C nouns, version skew, unlisted long-tail flags, or parity assertion failures.
54
53
 
@@ -57,9 +56,8 @@ Pick the noun, read its reference. Each Tier A and Tier B reference owns that no
57
56
  These nouns are intentionally undocumented - each has a concrete immaturity reason, not an oversight:
58
57
 
59
58
  | Noun | Reason |
60
- |------|--------|
59
+ | ------ | -------- |
61
60
  | `history` | `report` verb is a TODO stub (`spur history report` prints a marker); surface is still converging. |
62
- | `migrate` | Zero verbs - bare `spur migrate --json` runs schema migrations. No verb catalog to document. |
63
61
  | `projects` | Multi-project management surface (`add`/`remove`/`list`/`start`/`stop`); still evolving and not yet stable enough for a reference. |
64
62
  | `help` | Auto-generated by Commander.js; not a real noun. |
65
63
 
@@ -105,6 +103,17 @@ the whole point of this facade is that the CLI surface has a single, scalable ho
105
103
  semantics — including task and feature status-transition verbs — while multi-step lifecycle
106
104
  orchestration belongs to `sp:spur-dev`.
107
105
 
106
+ ## Shared option registry (0618)
107
+
108
+ Options shared by two or more command modules are declared once in
109
+ `apps/cli/src/commands/shared-options.ts` and spread at every call site
110
+ (`.option(...SHARED_OPTIONS.<key>)` — parser/default/collector args append after the spread). One
111
+ registry entry per **(flag, description) pair**: semantic homonyms (`--json`,
112
+ `--cwd`) keep separate keys with their distinct texts. When editing a command module, never
113
+ re-declare a shared flag inline — `apps/cli/tests/shared-option-parity.test.ts` fails on any literal
114
+ declaration of a flag string in `SHARED_OPTION_FLAGS`. Add a new shared option by adding the entry
115
+ and spreading it; full contract in `docs/04_DESIGN.md` §1.0.1.
116
+
108
117
  ## See also
109
118
 
110
119
  - **[references/agent.md](references/agent.md)** - coding-agent execution surface (`run`, `loop`,
@@ -114,10 +123,9 @@ the whole point of this facade is that the CLI surface has a single, scalable ho
114
123
  `inbox`, `reply`, `watch`).
115
124
  - **[references/team.md](references/team.md)** - team coordination and supervision (`assign`,
116
125
  `status`, `up`/`down`, `start`/`stop`).
117
- - **[references/serve.md](references/serve.md)** - local web server fallback (Task Kanban + team
118
- supervisor API).
119
- - **[references/init.md](references/init.md)** - `spur init` / `spur status` CLI verbs and
120
- post-scaffold init validation (Phase 1.5/1.6 probes).
126
+ - **[references/self.md](references/self.md)** - `spur self init|migrate|serve|status` CLI verbs
127
+ (the four legacy top-level nouns remain hidden aliases). `self init` runs post-scaffold init
128
+ validation (Phase 1.5/1.6 probes).
121
129
  - **`sp:spur-dev`** - the spine that dispatches these verbs into the planning +
122
130
  execution lifecycle. Use it to *drive* work; use this facade to *look up or operate a verb*.
123
131
  - **`plugins/sp/references/roles.md`** — the Layer-1 role→tier table (`scribe` / `coder` /
@@ -215,3 +215,8 @@ spur agent delete worker-1 --force
215
215
  supervision.
216
216
  - **`spur message` (see [message.md](message.md))** - the inbox `--drain` reads from.
217
217
  - **`sp:spur-cli`** SKILL.md - the facade that routes to this reference.
218
+
219
+ > **Shared option declarations (0618):** options shared across command modules resolve from
220
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
221
+ > inline in a command module — see SKILL.md "Shared option registry" and
222
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -0,0 +1,49 @@
1
+ ---
2
+ name: spur-cli-builder
3
+ description: "spur-cli noun reference: operate `spur builder` as the release plumbing surface - bump a workspace package (or the `workspace:`-pinned release set) with `bump-ver`, delete release tags with `drop-tags`, with commit + annotated tag + optional push. Promoted from spur-dev (task 0617, ADR-051); frozen at exactly these two verbs."
4
+ see_also:
5
+ - spur-cli
6
+ ---
7
+
8
+ # spur builder - release plumbing
9
+
10
+ `spur builder` is the CLI for **version bumps and release tags**. It wraps the internal
11
+ `spur-dev release` flow behind a public two-verb surface, promoted verbatim from
12
+ `scripts/commands/release.ts` (now a thin forwarder to the same implementation). Package ids are
13
+ the unscoped short names (`@gobing-ai/spur` → `spur`); the released set and the aggregate tag are
14
+ discovered from the repo's own workspace manifests, so the same code serves any git+semver
15
+ monorepo.
16
+
17
+ This noun is **frozen at exactly two verbs** by operator consent (`docs/design/harness-surface-governance.md`
18
+ §3) — do not invent additional `builder` subcommands.
19
+
20
+ ## Verb map
21
+
22
+ | Verb | Purpose | Key flags |
23
+ | ---- | ------- | --------- |
24
+ | `bump-ver [package-id] <version>` | Bump one package (manifest + in-source `binaryVersion` + consumer `workspace:` pins), commit, tag, optionally push | `--all` `--push` `--json` |
25
+ | `drop-tags [package-id] <version>` | Delete a package's release tag (local only by default) | `--all` `--remote` `--json` |
26
+
27
+ A bare `bump-ver <version>` (single positional that parses as semver) or explicit `--all` bumps
28
+ every package pinned via `workspace:` by another workspace package, then adds per-package trace
29
+ tags plus the aggregate `@<scope>/<root>-v<version>` publish tag. `drop-tags --all` mirrors that
30
+ for deletion.
31
+
32
+ **Exit codes:** `0` success, `1` error (invalid semver, unknown package id, dirty tree, detached
33
+ HEAD, or an existing local/origin tag). **Errors abort before any write** — a re-run after fixing
34
+ the cause is safe.
35
+
36
+ ## `bump-ver` - bump and tag a release
37
+
38
+ ```bash
39
+ spur builder bump-ver spur 0.1.4 # one package: manifest, pins, commit, tag @gobing-ai/spur-v0.1.4
40
+ spur builder bump-ver --all 0.1.4 # every workspace:-pinned package + aggregate tag
41
+ spur builder bump-ver --all 0.1.4 --push # also push branch + tags to origin
42
+ ```
43
+
44
+ ## `drop-tags` - delete release tags
45
+
46
+ ```bash
47
+ spur builder drop-tags spur 0.1.4 # delete the local tag @gobing-ai/spur-v0.1.4
48
+ spur builder drop-tags --all 0.1.4 --remote # delete per-package + aggregate tags, locally and on origin
49
+ ```
@@ -28,7 +28,7 @@ what* or *how to write a scenario*, this skill.
28
28
  | `list` | List features, filtered | `--status <s>` `--priority <p>` `--folder` `--json` |
29
29
  | `move <id>` | Re-parent a subtree (cascade-rename of descendants) | `--parent <id>` `--dry-run` `--folder` `--json` |
30
30
  | `refresh` | Rebuild INDEX + each feature `## Tasks` table from task edges (**docs only**; no status change) | `--feature <id>` `--folder` `--json` |
31
- | `check [id]` | Validate one feature / the tree; the 4-layer gate | `--strict` `--folder` `--json` |
31
+ | `check [id]` | Validate one feature / the tree; the 4-layer gate; `--fix` repairs structural findings in place | `--strict` `--fix` `--folder` `--json` |
32
32
  | `sync [id]` | Align feature **lifecycle status** with linked task states (real transitions + guards) | `--all` `--dry-run` `--force` `--folder` `--json` |
33
33
 
34
34
  **`refresh` vs `sync` (do not conflate):**
@@ -235,3 +235,8 @@ spur feature sync H2 --folder docs/custom-tasks --json # non-default tasks fol
235
235
  *drive* planning; use this skill to *look up a verb* or *author AC*.
236
236
  - **`spur task` (see [tasks.md](tasks.md))** — the companion for `spur task` (WBS lifecycle, section editing, the
237
237
  readiness matrix).
238
+
239
+ > **Shared option declarations (0618):** options shared across command modules resolve from
240
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
241
+ > inline in a command module — see SKILL.md "Shared option registry" and
242
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -107,3 +107,8 @@ lines.
107
107
  - **`spur agent` (see [agent.md](agent.md))** - `run --drain` and `loop` consume the inbox.
108
108
  - **`spur team` (see [team.md](team.md))** - team lifecycle that assigns agents to tasks.
109
109
  - **`sp:spur-cli`** SKILL.md - the facade that routes to this reference.
110
+
111
+ > **Shared option declarations (0618):** options shared across command modules resolve from
112
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
113
+ > inline in a command module — see SKILL.md "Shared option registry" and
114
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -207,3 +207,8 @@ directly on the command line.
207
207
 
208
208
  **Template type**: technique
209
209
  **Purpose**: Operate `spur rule` across its full lifecycle as the deterministic constraint gate in LLM code delivery
210
+
211
+ > **Shared option declarations (0618):** options shared across command modules resolve from
212
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
213
+ > inline in a command module — see SKILL.md "Shared option registry" and
214
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: spur-cli-self
3
+ description: "spur-cli noun reference for `spur self`: self-management verbs — scaffold (`init`), schema migrations (`migrate`), local web server (`serve`), and status overview (`status`). Each verb mounts the same command builder as its legacy top-level noun, which remains a hidden alias over the identical command."
4
+ see_also:
5
+ - spur-cli
6
+ ---
7
+
8
+ # spur self - self-management verbs
9
+
10
+ `spur self` hosts the four self-management verbs. Each verb is the canonical path for a command
11
+ that also remains registered as a legacy top-level **hidden alias** (`spur init`, `spur migrate`,
12
+ `spur serve`, `spur status`) so existing scripts, workflow YAML, and habits keep working unchanged.
13
+ Both paths share the same command builder: identical flags, output, and exit codes. The legacy
14
+ top-level forms are omitted from `spur --help`, leaving `self` as the visible surface.
15
+
16
+ ## Verb map
17
+
18
+ | Verb | Purpose | Key flags |
19
+ | ---- | ------- | --------- |
20
+ | `init` | Scaffold a new Spur project in the current directory | `--name <name>` `--force` `--minimal` `--json` |
21
+ | `migrate` | Apply CLI-owned schema migrations | `--json` |
22
+ | `serve` | Start the Spur web server (local fallback) | `--port <n>` `--host <addr>` `--no-open` `--cwd <path>` `--json` |
23
+ | `status [path]` | Show project and git status for a Spur project | `--json` |
24
+
25
+ **Deep detail lives in the verb-owner references** — **[init.md](init.md)** owns the `init` and
26
+ `status` verbs (scaffold semantics + the Phase 1.5 / 1.6 post-scaffold validation probes),
27
+ **[serve.md](serve.md)** owns the `serve` verb (server flags and dry-probe semantics). `migrate`
28
+ has no reference of its own and is documented inline below.
29
+
30
+ ## `self init` - scaffold a Spur project
31
+
32
+ ```bash
33
+ spur self init # interactive: prompt for project name
34
+ spur self init --name my-project # non-interactive
35
+ spur self init --name my-project --force # overwrite existing .spur/ files
36
+ spur self init --minimal # skip optional scaffolding (rules, workflows)
37
+ spur self init --json # machine-readable
38
+ ```
39
+
40
+ Materializes the `.spur/` directory tree with config, docs, rules, and workflow templates. Flags:
41
+ `--name <name>` (default: current directory name), `--force` (recreate existing files), `--minimal`
42
+ (skip optional scaffolding), `--json` (machine-readable output). Post-scaffold validation probes
43
+ (Phase 1.5 / 1.6) run immediately after this verb completes — see **[init.md](init.md)** for the
44
+ probe protocol and rule-glob adaptation procedure.
45
+
46
+ ## `self migrate` - apply CLI-owned schema migrations
47
+
48
+ ```bash
49
+ spur self migrate # apply pending migrations
50
+ spur self migrate --json # machine-readable { ok, applied }
51
+ ```
52
+
53
+ Temporary helper: applies CLI-owned schema migrations and reports `{ ok, applied }`. Only flag is
54
+ `--json`.
55
+
56
+ ## `self serve` - start the local web server
57
+
58
+ ```bash
59
+ spur self serve # default: localhost:3000, opens browser
60
+ spur self serve --port 8080 --host 0.0.0.0
61
+ spur self serve --no-open # skip browser
62
+ spur self serve --json # dry probe: print { port, url, pid, running } and exit
63
+ ```
64
+
65
+ Starts the Hono/Cloudflare-Worker server that serves the web Task Kanban and exposes the team
66
+ supervisor API (`/api/team/*`). It is the local fallback when no remote server is configured.
67
+ Flags: `--port <n>`, `--host <addr>`, `--no-open`, `--cwd <path>`, `--json` (a dry probe — reports
68
+ the resolved port/url without starting the server). Full flag semantics: **[serve.md](serve.md)**.
69
+
70
+ ## `self status [path]` - project and git status
71
+
72
+ ```bash
73
+ spur self status # current directory
74
+ spur self status /path/to/project # specific project
75
+ spur self status --json # machine-readable
76
+ ```
77
+
78
+ Reports the project's Spur configuration state (init status, feature/task counts, rule preset
79
+ health) and git working-tree status. Optional `[path]` argument targets a different project
80
+ directory. Only flag is `--json`.
81
+
82
+ ## What this skill is NOT
83
+
84
+ - **Not the team supervisor.** `self serve` hosts the supervisor API; `spur team start` / `stop` /
85
+ `status` are the verbs that drive it. See **[team.md](team.md)**.
86
+ - **Not a production server.** This is the local fallback. Production deployment uses the Cloudflare
87
+ Worker build (`apps/server/`), not `self serve`.
88
+
89
+ ## See also
90
+
91
+ - **[init.md](init.md)** - `init` / `status` verbs: scaffold semantics and the Phase 1.5 / 1.6
92
+ post-scaffold validation probes.
93
+ - **[serve.md](serve.md)** - `serve` verb: server flags and the `--json` dry-probe contract.
94
+ - **`spur team` (see [team.md](team.md))** - `start`/`stop`/`status` require `self serve` for the
95
+ supervisor API.
96
+ - **`sp:spur-cli`** SKILL.md - the facade that routes to this reference.
97
+
98
+ > **Shared option declarations (0618):** options shared across command modules resolve from
99
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
100
+ > inline in a command module — see SKILL.md "Shared option registry" and
101
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -51,7 +51,7 @@ re-reading or re-tokenizing the task.
51
51
  | `batch-create` | Create many tasks from a validated JSON array | `--file <path>` `--folder` `--json` |
52
52
  | `record <wbs>` | Write `Testing` from a verify verdict (deterministic); bare-`## Review` fallback only; optional Solution + transition | `--verdict-file <path>` `--solution-from-diff` `--transition <status>` `--folder` `--json` |
53
53
  | `verdict <wbs>` | Derive PASS/PARTIAL/FAIL/UNKNOWN from verify answer text → verdict JSON; see [answer-file shape](tasks/verbs.md#answer-file-shape-what---from-answer-parses) | `--from-answer <path>` `--folder` `--json` |
54
- | `check [wbs]` | Four-layer validation; the readiness matrix | `--strict` `--as <status>` `--strict-core` `--folder` `--json` |
54
+ | `check [wbs]` | Four-layer validation; the readiness matrix; `--fix` repairs structural findings in place | `--strict` `--as <status>` `--strict-core` `--fix` `--folder` `--json` |
55
55
  | `resolve <file-path>` | Map a file path to its owning task WBS | `--strict` `--folder` `--json` |
56
56
  | `path <wbs>` | Map a WBS to its absolute task file path (inverse of `resolve`) | `--folder` `--json` |
57
57
  | `run-link <wbs>` | Record pipeline run provenance link for task | `--source <src>` `--run-id <id>` `--json` |
@@ -310,3 +310,8 @@ spur task path 0040 --json
310
310
  execution loop. Use it to *drive* work; use this skill to *look up a verb*.
311
311
  - **`spur feature` (see [features.md](features.md))** — the companion for `spur feature` (hierarchical IDs, AC conventions,
312
312
  traceability).
313
+
314
+ > **Shared option declarations (0618):** options shared across command modules resolve from
315
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
316
+ > inline in a command module — see SKILL.md "Shared option registry" and
317
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -138,3 +138,8 @@ process spawning. The started process runs `spur agent loop --agent <id>` under
138
138
  - **`spur message` (see [message.md](message.md))** - the durable inbox team members drain.
139
139
  - **`spur serve` (see [serve.md](serve.md))** - the local server `start`/`stop`/`status` require.
140
140
  - **`sp:spur-cli`** SKILL.md - the facade that routes to this reference.
141
+
142
+ > **Shared option declarations (0618):** options shared across command modules resolve from
143
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
144
+ > inline in a command module — see SKILL.md "Shared option registry" and
145
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -199,10 +199,45 @@ spur workflow run ./workflows/approval.yaml --steer # interactive
199
199
  - **`--steer`** is synchronous and in-process: it cannot combine with `--json` or `--async` (exit `2`).
200
200
  It accepts steering commands on stdin at declared action boundaries for interactive control.
201
201
 
202
+ ## Composition measures and the advisory (0615)
203
+
204
+ `workflow validate` (valid path only) also reports a **warn-only composition advisory** covering the
205
+ two detectable measures from ADR-069. It answers "does this workflow lean on ad-hoc shell or raw
206
+ agent prompts where a first-class surface would own it better?" — nothing more.
207
+
208
+ **The two triggers:**
209
+
210
+ - **Shell measure** — a `shell` action (state hooks `onEnter`/`onExit`; guards are exempt) flags when
211
+ its `command` has **≥6** non-comment units (split on newline and `;`, blank/`#` units skipped).
212
+ - **agent.run measure** — an `agent.run` action flags when its `input` is a **non-slash** prompt;
213
+ raw prompt length only sets the reported severity (<200 low / ≤1000 medium / >1000 high).
214
+
215
+ **How to run it:** it is not a separate command — `spur workflow validate <file> --json` returns
216
+ `composition: {findings[], suppressed}` on the valid path; human mode prints the advisory to stderr
217
+ with exit 0. Actions with a recorded disposition in
218
+ `config/workflow-composition-baseline.json` (resolved by walking up from the workflow file) are
219
+ counted in `suppressed`, not `findings`.
220
+
221
+ **How to read it, and the fix path per defect class:**
222
+
223
+ - **Shell finding** → pick one of the five recorded owner options from
224
+ `docs/design/workflow-shell-ownership.md`: (a) public `spur` verb (consent-gated),
225
+ (b) application service, (c) least-privilege built-in action kind, (d) workflow-relative external
226
+ extension, (e) deliberately-stays-shell exception (record the reason in the baseline).
227
+ - **agent.run finding** → move the operation behind a centralized agent skill or slash command and
228
+ make the action's `input` reference it (ADR-043 preference).
229
+
230
+ **Advisory-only posture (binding):** findings never justify blocking a run, failing a gate, or
231
+ editing a pipeline that is currently executing. The advisory never changes `validate`'s exit status,
232
+ never blocks `workflow run`, and is not part of `spur-check` / `spur-check-new`. Treat a finding as
233
+ a to-be-enhanced note for the workflow's owner — surface it in your report, apply the fix only when
234
+ the operator accepts it, and never hot-edit a running workflow's shell in place.
235
+
202
236
  ## Command surface
203
237
 
204
238
  ```
205
239
  spur workflow validate <file> [--no-schema] [--json]
240
+ spur workflow show <file>
206
241
  spur workflow run <file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer] [--json]
207
242
  spur workflow continue [run-id] [--yes] [--answer <yes|no|cancel>] [--json]
208
243
  spur workflow cancel <run-id> [--json]
@@ -359,3 +394,8 @@ directly on the command line.
359
394
 
360
395
  **Template type**: technique
361
396
  **Purpose**: Operate `spur workflow` across its full lifecycle — choose the execution mode, author, validate, run, and refine dual-mode workflows
397
+
398
+ > **Shared option declarations (0618):** options shared across command modules resolve from
399
+ > `apps/cli/src/commands/shared-options.ts` (`SHARED_OPTIONS`). Never re-declare a shared flag
400
+ > inline in a command module — see SKILL.md "Shared option registry" and
401
+ > `docs/04_DESIGN.md` §1.0.1.
@@ -412,14 +412,15 @@ is the procedure. The backing is a combination of git CLI, `spur` CLI, and agent
412
412
  - **Behavior:** 0. **Start at the anchors, never at a discovery run.** If `--findings <anchors>` is given, that space-separated `file:line` list IS the failing set — open those locations first, in order, and fix them; do not run the gate to find out what broke. If only `--gate-log <path>` is given, read that log first and identify the failing findings (lint/test errors with their `file:line` anchors) before running the loop — the captured log is the authoritative source. Either way the first action of this hop is a read, not a gate run (R3, task 0482).
413
413
  1. Run `bun run format` (add `-- <path>` if `--scope` is given) to settle formatter-only diffs first — `bun run lint` asserts `--error-on-warnings` + typecheck but does **not** rewrite formatting, so a formatter-only change (e.g. a multi-line import reflow) can pass `lint` locally yet still be unformatted. Formatting before linting removes that class of false-green.
414
414
  2. Run `bun run lint` (add `-- <path>` if `--scope` is given). Collect all errors.
415
- 3. If lint is clean, skip to step 5.
416
- 4. **Lint fix loop:** for each error, diagnose the root cause and apply the smallest fix. **Use targeted probes to verify each fix** (`bunx tsc --noEmit` on the affected package, `bun run lint -- <file>`) — do NOT re-run the full gate after every batch. Loop until lint is green.
417
- 5. Run `bun run test`. Collect all failures.
418
- 6. If tests are green, done.
419
- 7. **Test fix loop:** for each failure, diagnose (test bug vs implementation bug), apply the fix, re-run the **failing test only** (`bun test <file> --test-name-pattern "<test>"`). Do NOT re-run the full suite per fix — it is the dominant loop cost (task 0436 R2).
420
- 8. **Confirming run (at most once).** After all fixes, run `bun run format && bun run lint && bun run test` **at most once** to confirm. If it passes, the hop is done.
421
- 9. **Pipeline-awareness (R4, task 0483).** When `/sp:dev-fixall` is invoked from the pipeline's `test-fix` hop, `test-recheck` runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run that writes PASS to `.spur/run/<wbs>-test-gate.status`. Do NOT re-run the full gate beyond the single confirming run in step 8; the deciding run belongs to `test-recheck`. If your confirming run already passed, return immediately — a second or third gate run inside this hop is pure redundancy (0482 ran the gate 3× plus a standalone `bun run test`; all four were followed by `test-recheck` running it a 5th time). If your confirming run failed and you fixed more, re-run the full gate once more within `--max-retry` budget, then return — let `test-recheck` judge.
422
- 10. Report: list what was fixed (file + one-line summary per fix). If any error could not be resolved, report it explicitlydo not suppress.
415
+ 3. **Surface-change sweep (before any fix).** If the failing set is a **surface/parity** change — CLI noun/verb/flag surface, reference-file structure, or a renamed/moved symbol — do one upfront `rg` sweep across ALL test dirs + docs for stale references to the changed symbols (e.g. `rg -l "<old-noun>|<old-file>.md|Tier C" apps/*/tests plugins/sp/tests plugins/sp/skills docs`), and fix every pinned test/docs file in that sweep. A surface change is pinned in **multiple independent test files** (each with its own hardcoded noun→reference map); discovering them one-by-one via full-suite probes is the dominant waste — each wave costs a suite run and a fresh edit loop (task 0436 R2 lesson). One sweep produces the complete edit set upfront.
416
+ 4. If lint is clean, skip to step 6.
417
+ 5. **Lint fix loop:** for each error, diagnose the root cause and apply the smallest fix. **Use targeted probes to verify each fix** (`bunx tsc --noEmit` on the affected package, `bun run lint -- <file>`) — do NOT re-run the full gate after every batch. Loop until lint is green.
418
+ 6. Run `bun run test`. Collect all failures.
419
+ 7. If tests are green, done.
420
+ 8. **Test fix loop:** for each failure, diagnose (test bug vs implementation bug), apply the fix, re-run the **failing test only** (`bun test <file> --test-name-pattern "<test>"`). Do NOT re-run the full suite per fix it is the dominant loop cost (task 0436 R2).
421
+ 9. **Confirming run (at most once).** After all fixes, run `bun run format && bun run lint && bun run test` **at most once** to confirm. If it passes, the hop is done.
422
+ 10. **Pipeline-awareness (R4, task 0483).** When `/sp:dev-fixall` is invoked from the pipeline's `test-fix` hop, `test-recheck` runs the full `${vars.qualityGateCmd}` gate immediately after this hop returns — that is the **deciding** run that writes PASS to `.spur/run/<wbs>-test-gate.status`. Do NOT re-run the full gate beyond the single confirming run in step 9; the deciding run belongs to `test-recheck`. If your confirming run already passed, return immediately — a second or third gate run inside this hop is pure redundancy (0482 ran the gate 3× plus a standalone `bun run test`; all four were followed by `test-recheck` running it a 5th time). If your confirming run failed and you fixed more, re-run the full gate once more within `--max-retry` budget, then return let `test-recheck` judge.
423
+ 11. Report: list what was fixed (file + one-line summary per fix). If any error could not be resolved, report it explicitly — do not suppress.
423
424
  - **Invariants:** Never bypass with `--no-verify`, `--force`, or new `biome-ignore`/`eslint-disable` suppressions. Never skip or `.skip` a test to make the suite green. Fix the root cause, not the symptom. Never claim green on `bun run lint` alone — a formatter-only diff passes `lint` but fails the formatter; run `bun run format` (or assert it produces no diff) before declaring the gate clean. **Never re-run the full gate more than once per confirming pass** (R4) — use targeted probes during the fix loops and let the pipeline's `test-recheck` state be the deciding run.
424
425
  - **MANDATORY Exit Condition.** The ONLY way to complete successfully:
425
426
  1. Run validation command: `eval "$VALIDATION_CMD"`
@@ -734,6 +734,25 @@ command doc so it does not read as a bug.
734
734
  `sp:super-planner` surfaces blockers/HITL only at the **batch boundary** (between task runs), not
735
735
  from inside a pipeline step.
736
736
 
737
+ ## Gate preflight (dogfood 2026-08-21, feature A3)
738
+
739
+ The A3 batch burned multiple full `spur-check-new` runs (~2 min each) that failed only at the tail
740
+ gates. The cheap rule gates fail fast when run first — the full-gate run is dominated by the ~65 s
741
+ test suite, so a gate run that dies at `test-post-check` or `corpus-check` wasted most of its wall
742
+ time. Before launching a full `spur-check-new`:
743
+
744
+ 1. **Run the two rule gates first** — `bun run test-pre-check` (43 rules: `no-console-output`,
745
+ `no-direct-process-spawn`, `cli-*`, `require-corresponding-test`) and `bun run test-post-check`
746
+ (`every-export-has-tsdoc`, `coverage-gate`). They catch boundary/TSDoc violations in seconds.
747
+ 2. **Promoted code must satisfy the boundary rules `scripts/` never enforced.** A command module
748
+ moving from `scripts/` into `apps/cli/src` must route output through the `CommandOutput` seam (no
749
+ `console.*`), spawn processes via `NodeProcessExecutor` (no `Bun.spawnSync`), get a
750
+ `runtime-boundaries` fs-io exemption for sync reads (mirrors `task.ts`), and a non-command helper
751
+ must not live in `apps/cli/src/commands/` (the noun scan treats every file there as a noun).
752
+ 3. **Doc/TSDoc edits shift `file:line` anchors** cited by other tasks — `corpus-check` surfaces them
753
+ as `L4.anchor-subject-mismatch`. Repoint the shifted citations (via `spur task update --section`)
754
+ in the same commit, and reconcile new/stale baseline entries before the gate run.
755
+
737
756
  ## AC traceability
738
757
 
739
758
  | AC | Where satisfied |
@@ -124,12 +124,34 @@ Transition guards are not advisory. Execute the declared guard exactly, in order
124
124
  resolved variables and artifacts. `--no-lifecycle` remains bookkeeping only; the YAML's task checks,
125
125
  verdict gate, record step, and done guard all remain authoritative.
126
126
 
127
- ## Batch use
127
+ ## Record & done sequencing (dogfood 2026-08-21, feature A3)
128
128
 
129
- Sequential `/sp:dev-runall` with omit/`inline` runs this driver once per ready WBS, with a fresh run
130
- id and the same frozen/topologically ordered batch plan. Batch inspection, halt/keep-going policy,
131
- and reporting remain in `execution-batch.md`. Parallel mode cannot share one host session safely and
132
- therefore keeps the existing isolated subprocess/worktree path (trigger 4).
129
+ Order matters for the `testing done` hop. The A3 batch hit the same clobbering spiral on two
130
+ tasks (0617, 0619) because the sections were hand-written **before** the verdict artifact existed:
131
+
132
+ 1. **Write the verdict artifact first.** `spur task record --solution-from-diff --transition testing`
133
+ reads `.spur/run/<wbs>-verdict.json` (default). With no artifact it emits a **UNKNOWN** verdict and
134
+ **overwrites** a hand-authored `## Testing` with an auto-generated "No requirements recorded" table,
135
+ plus replaces `## Solution` with a bare auto change-map. Creating the artifact first (PASS, with
136
+ requirement rows keyed by scenario title) makes `task record` the compliant path.
137
+ ```bash
138
+ # verdict artifact first (shape: {wbs, verdict, requirements:[{id,status,evidence}], checks:[], source})
139
+ # then the record hop; then re-write Testing/Solution if record's backfill is thinner than intended.
140
+ spur task update <wbs> wip --no-lifecycle
141
+ spur task record <wbs> --solution-from-diff --transition testing
142
+ ```
143
+ The engine now preserves an already-authored Testing when the verdict is UNKNOWN (task-service
144
+ `record` fallback-only, mirroring the Review 0593 precedent) — but the order above is still the
145
+ contract for the standard pipeline.
146
+ 2. **Done-probe before done.** Run the check projected to `done` (`spur task check <wbs> --as done`
147
+ via the `TaskCheckService` probe pattern) — it surfaces `L3.unchecked-checklist` (flip `- [ ]` → `- [x]`)
148
+ and `L3.required-section-placeholder` before the transition, not after.
149
+ 3. **Solution change-map anchor rule (L4.anchor-subject-mismatch).** A Solution change-map table must
150
+ list **one `file:line` per row**. A ·-joined paragraph makes every anchor's "subject" the other
151
+ anchors and trips the L4 subject check. Paths containing `_` (e.g. `docs/help/cmd_*.md`,
152
+ `spur-cli-matrix.md`) can **never** match their cited line — the snake_case filename token is
153
+ extracted as the subject and cannot appear in the line content — so drop those rows from the table
154
+ (prose still covers them).
133
155
 
134
156
  ## Failure contract
135
157