@gobing-ai/spur 0.3.42 → 0.3.44
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/.claude-plugin/marketplace.json +1 -1
- package/config/templates/AGENTS.md +5 -0
- package/config/workflows/idea-pipeline.yaml +205 -33
- package/config/workflows/task-pipeline.yaml +11 -1
- package/package.json +9 -9
- package/plugins/sp/commands/dev-run.md +3 -3
- package/plugins/sp/commands/dev-runall.md +9 -4
- package/plugins/sp/commands/dev-wrap.md +21 -3
- package/plugins/sp/commands/dev-wrapall.md +21 -3
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/code-implementation/SKILL.md +27 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +21 -3
- package/plugins/sp/skills/issue-finding/references/session-formats.md +30 -0
- package/plugins/sp/skills/next-router/references/routing-table.md +2 -2
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +9 -0
- package/plugins/sp/skills/spur-cli/SKILL.md +3 -0
- package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +8 -3
- package/plugins/sp/skills/spur-cli/references/tasks.md +25 -1
- package/plugins/sp/skills/spur-dev/SKILL.md +12 -4
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +22 -6
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +13 -13
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +76 -4
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +4 -2
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +43 -11
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +53 -0
- package/spur.js +529 -290
- package/web/_astro/{BoardApp.8sc6Rb1t.js → BoardApp.BnhkWEOG.js} +99 -99
- package/web/_astro/BoardApp.CxOS4HSo.js +1 -0
- package/web/_astro/{TaskDetail.DOKJP-Kp.js → TaskDetail.B6yiT-U7.js} +1 -1
- package/web/_astro/{arc.CTqmqspU.js → arc.PbmgYm3_.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.B0iBdehs.js → architectureDiagram-3BPJPVTR.BkOMSdmD.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BHE5UFj5.js → blockDiagram-GPEHLZMM.BtomoUdy.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.DQApkgGM.js → c4Diagram-AAUBKEIU.UzrYwJnF.js} +1 -1
- package/web/_astro/channel.DRRsElzO.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.fPrKLM8v.js → chunk-2J33WTMH.nNChLHkw.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.DExvwBhn.js → chunk-4BX2VUAB.DLYAecPo.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.EjNkjuD6.js → chunk-55IACEB6.t5bzuj1J.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.Dl8xy5rT.js → chunk-727SXJPM.DBV62bIy.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.BSzMBgBs.js → chunk-AQP2D5EJ.BdaPhTPs.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.CAeOHpbb.js → chunk-FMBD7UC4.eoZ88KMf.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.Bbeu_ZOH.js → chunk-ND2GUHAM.QdNDyeSh.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.Da_GaIAZ.js → chunk-QZHKN3VN.DPaToLfx.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.sMfFYSQp.js → classDiagram-4FO5ZUOK.By9BMe7b.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.sMfFYSQp.js → classDiagram-v2-Q7XG4LA2.By9BMe7b.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.PS3IwOH4.js → cose-bilkent-S5V4N54A.DMypl6q_.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.EQCx8a6D.js → dagre-BM42HDAG.p26m9grg.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.aEFQl8v8.js → diagram-2AECGRRQ.C6m3oTIu.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.jyN4tqFX.js → diagram-5GNKFQAL.JCxivn2z.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.DaTVHnme.js → diagram-KO2AKTUF.DifbEd3P.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.DWsGRLAN.js → diagram-LMA3HP47.Bffga-cf.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.DYxmOViu.js → diagram-OG6HWLK6.CUKx5_Cx.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BKM75coa.js → erDiagram-TEJ5UH35.DaJ9KZR0.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.B7qpqDW5.js → flowDiagram-I6XJVG4X.Do6l5pzg.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.CYBL-hwy.js → ganttDiagram-6RSMTGT7.DqBKgB-3.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.Cz4ly3Kq.js → gitGraphDiagram-PVQCEYII.B3VLSQ22.js} +1 -1
- package/web/_astro/{index.yAse9IaO.css → index.QfZ9SC3X.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.CIS7cXrJ.js → infoDiagram-5YYISTIA.hK8ZC1oa.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.DQ-pmaOG.js → ishikawaDiagram-YF4QCWOH.C8DXwh9Z.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.DVS6F7UM.js → journeyDiagram-JHISSGLW.mj5aHQDb.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D8t-G-U6.js → kanban-definition-UN3LZRKU.Dwlhi49r.js} +1 -1
- package/web/_astro/{linear.IO8rTd_n.js → linear.7zBHdlwl.js} +1 -1
- package/web/_astro/{mermaid.core.CjVnvFNf.js → mermaid.core.AYdA0EJr.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.DZoEMTnU.js → mindmap-definition-RKZ34NQL.BSnniHEq.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.86r1QWnX.js → pieDiagram-4H26LBE5.B7EVpA3J.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.DzFA9uPk.js → quadrantDiagram-W4KKPZXB.rg4i8YOY.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.dQvdvfMr.js → requirementDiagram-4Y6WPE33.C4pr792x.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BvC-VNI8.js → sankeyDiagram-5OEKKPKP.DTXU996O.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DDQNwHs8.js → sequenceDiagram-3UESZ5HK.D73DOjzi.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BKwYy-tQ.js → stateDiagram-AJRCARHV.CVkeSaEH.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.KxCiRYYf.js → stateDiagram-v2-BHNVJYJU.DkBGwoN5.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.Bh9NDjOx.js → timeline-definition-PNZ67QCA.DnJ9Yh7G.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DIM-n6us.js → vennDiagram-CIIHVFJN.DN1tvR4Y.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.DW15qOFQ.js → wardley-L42UT6IY.D54jJ-7-.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.UTIvjsG9.js → wardleyDiagram-YWT4CUSO.C2grUBbE.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.CQYhkVDS.js → xychartDiagram-2RQKCTM6.D05okBnV.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/BoardApp.ChKnY1JD.js +0 -1
- package/web/_astro/channel.B0q9WGrH.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Wrap up a batch of completed tasks — learnings, metrics, doc-sync, feature transition, optional branch cleanup
|
|
3
|
-
argument-hint: "[--since <iso-date>] [--feature <id>] [--status <s>] [--auto] [--merge] [--dry-run]"
|
|
3
|
+
argument-hint: "[--since <iso-date>] [--feature <id>] [--status <s>] [--agent <inline|auto|name>] [--auto] [--merge] [--dry-run]"
|
|
4
4
|
allowed-tools: ["Bash", "Read", "AskUserQuestion"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -15,6 +15,7 @@ Wraps the **wrapup-pipeline.yaml** workflow.
|
|
|
15
15
|
| `--since` `<iso-date>` | Wrap tasks completed since a date. | configured |
|
|
16
16
|
| `--feature` `<id>` | Wrap tasks in a feature. | omitted |
|
|
17
17
|
| `--status` `<s>` | Only wrap tasks in a status. | done |
|
|
18
|
+
| `--agent` `<inline\|auto\|name>` | Who runs the wrap's model-bearing steps. Wrap is workflow-backed: omit/`inline` resolves to `agent.default` (objective trigger 3 — durable auditable run record required); `auto` tier-resolves an executor; a name pins that executor into `vars.agent`. | agent.default |
|
|
18
19
|
| `--auto` | Skip objective HITL gates. | off |
|
|
19
20
|
| `--merge` | Merge wrap branches. | off |
|
|
20
21
|
| `--dry-run` | Render wraps without writing. | off |
|
|
@@ -23,11 +24,28 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
23
24
|
|
|
24
25
|
## Usage
|
|
25
26
|
|
|
26
|
-
/sp:dev-wrapall [--since <iso-date>] [--feature <id>] [--status <s>] [--auto] [--merge] [--dry-run]
|
|
27
|
+
/sp:dev-wrapall [--since <iso-date>] [--feature <id>] [--status <s>] [--agent <inline|auto|name>] [--auto] [--merge] [--dry-run]
|
|
27
28
|
|
|
28
29
|
## Implementation
|
|
29
30
|
|
|
31
|
+
- Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
|
|
32
|
+
- Wrap stays **workflow-backed** — `spur workflow run .spur/workflows/wrapup-pipeline.yaml` is the only implementation; there is no inline wrap driver.
|
|
33
|
+
- Resolve the executor **before** launching the workflow:
|
|
34
|
+
- `--agent <name>` → pass the name unchanged into `vars.agent`.
|
|
35
|
+
- `--agent auto` → tier-resolve a concrete executor first, then merge it into `vars.agent`.
|
|
36
|
+
- omit/`--agent inline` → resolve to `agent.default` (the documented headless resolution of `inline`).
|
|
37
|
+
- Emit a pre-dispatch notice naming the override before `spur workflow run`, exactly:
|
|
38
|
+
`execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: inline|auto|<name>`, `executor: agent.default|<resolved-name>`.
|
|
39
|
+
- The wrap workflow still creates its durable run record — the notice reports the override, it does not change the workflow.
|
|
40
|
+
|
|
30
41
|
```bash
|
|
31
|
-
|
|
42
|
+
AGENT=… # resolved above: agent.default for inline/omitted, tier-resolved for auto, unchanged for <name>
|
|
43
|
+
echo "execution surface: subprocess; reason: trigger 3 — durable auditable run record required; requested agent: <inline|auto|name>; executor: $AGENT"
|
|
44
|
+
VARS=$(jq -nc --arg tasks "$TASKS" --arg feature "$FEATURE" --arg agent "$AGENT" --arg profile "$PROFILE" --arg merge "$MERGE" \
|
|
45
|
+
'{tasks:$tasks, feature:$feature, agent:$agent, profile:$profile, merge:$merge}')
|
|
46
|
+
spur workflow run .spur/workflows/wrapup-pipeline.yaml --vars "$VARS" [--dry-run]
|
|
32
47
|
```
|
|
33
48
|
|
|
49
|
+
The executor resolution is described in the bullets above; the snippet's `AGENT` variable carries
|
|
50
|
+
the resolved name (`agent.default` for omit/`inline`).
|
|
51
|
+
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.44",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -92,6 +92,33 @@ only burns wall clock and context budget.
|
|
|
92
92
|
- If a targeted probe reveals a failure you cannot fix within implement scope, note it in
|
|
93
93
|
`## Solution` and let the `test` hop's fixall handle it — do not pre-empt the gate.
|
|
94
94
|
|
|
95
|
+
## Changed-path targeted checks (dependency-aware verification, task 0510 R3)
|
|
96
|
+
|
|
97
|
+
"Run the narrow test first" needs a second half: *which* narrow tests, when a change to a shared
|
|
98
|
+
surface can break a downstream consumer. The matrix below is dependency-aware — domain → app →
|
|
99
|
+
CLI — so a shared change verifies its consumers without recreating the full project check inside
|
|
100
|
+
implement. **It augments narrow behavior tests; it never authorizes `bun run spur-check`,
|
|
101
|
+
`bun run test`, or another full project check inside implement** — the pipeline's `test` hop owns
|
|
102
|
+
that single full gate.
|
|
103
|
+
|
|
104
|
+
| Changed surface | Required targeted tests | Required typechecks |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `packages/domain/src/**` public type/query | affected domain test; affected app service test; affected CLI command test | `@gobing-ai/spur-domain`, `@gobing-ai/spur-app`, `@gobing-ai/spur` |
|
|
107
|
+
| `packages/app/src/**` public service/type | affected app test; affected CLI command test | `@gobing-ai/spur-app`, `@gobing-ai/spur` |
|
|
108
|
+
| `apps/cli/src/**` | affected `apps/cli/tests/**` file | `@gobing-ai/spur` |
|
|
109
|
+
| shared plugin flag/command/reference | affected plugin structure/contract test; add `flag-contract-parity.test.ts` **only** when the shared flag surface changes | no package typecheck unless TypeScript also changed |
|
|
110
|
+
|
|
111
|
+
- Apply **only the matching rows** for the surfaces actually changed; a multi-surface change applies
|
|
112
|
+
the union.
|
|
113
|
+
- Workspace typechecks run as `bun run --filter <workspace> typecheck` for each listed workspace
|
|
114
|
+
(monorepo; installed/other projects substitute their package-manager surface).
|
|
115
|
+
- The shared plugin row is deliberately conditional: a pure reference/prose change needs only the
|
|
116
|
+
affected structure test; `flag-contract-parity.test.ts` is added only when the shared flag surface
|
|
117
|
+
(a flag the plugin layer consumes) actually changes, so an unconditional parity suite does not
|
|
118
|
+
creep into every plugin edit.
|
|
119
|
+
- Run the applicable rows, then stop: the single full project check belongs to the pipeline's
|
|
120
|
+
`test` hop (`task-pipeline.yaml` `${vars.qualityGateCmd}`).
|
|
121
|
+
|
|
95
122
|
## Behavior
|
|
96
123
|
|
|
97
124
|
This skill behaves as a **technique**: given a task (read its Background, AC, Design, Plan), it maps
|
|
@@ -169,9 +169,27 @@ count identical commands for loop detection.
|
|
|
169
169
|
Produce per-session metrics (duration, tools, compactions, test runs, spur calls, guard failures,
|
|
170
170
|
key finding). Aggregate totals across sessions.
|
|
171
171
|
|
|
172
|
-
When `--use-history` is set,
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
When `--use-history` is set, the **selected-file history bridge** supplies ETL aggregates for the
|
|
173
|
+
frozen session set (task 0507 R3):
|
|
174
|
+
|
|
175
|
+
1. **Freeze Phase 1's selected OMP JSONL files once** — the same inventory the raw analysis reads.
|
|
176
|
+
Discovery roots: the normal OMP session root (`~/.omp/agent/sessions/`) **and**
|
|
177
|
+
`.spur/run/<run-id>/agent-sessions/<omp-executor>/*.jsonl` for workflow subprocess sessions.
|
|
178
|
+
Never import a broad `.spur/run` scan and never run a full/source-root reconciliation here.
|
|
179
|
+
2. **Import each frozen file once, through the source-local CLI**, with single-file `force-file`
|
|
180
|
+
mode:
|
|
181
|
+
`bun run apps/cli/src/index.ts history import --source omp --file <absolute-file> --mode force-file --json`.
|
|
182
|
+
The importer derives the session key from the filename; use the same stem for analysis.
|
|
183
|
+
3. **Analyze scoped to that key**: `history analyze --session <filename-stem> --json`.
|
|
184
|
+
4. Use the artifact for the aggregates ETL can represent — tokens, cost, messages, tool calls,
|
|
185
|
+
loops, and assistant response duration. **Continue parsing the same raw files** for command text,
|
|
186
|
+
compactions, test/guard retries, tool execution duration/status/errors, and every other signal
|
|
187
|
+
the ETL does not carry.
|
|
188
|
+
|
|
189
|
+
ETL supplies normalized aggregates; it is **not** a substitute for raw tool-loop evidence. If an
|
|
190
|
+
import fails or the DB is empty, continue with raw logs and note that cost data is unavailable.
|
|
191
|
+
Before any ad-hoc verification SQL against `history_*` tables, follow the schema-first rule in
|
|
192
|
+
[references/session-formats.md](references/session-formats.md) — inspect the live schema once.
|
|
175
193
|
|
|
176
194
|
### Phase 3: IDENTIFY — Root Cause Ranking
|
|
177
195
|
|
|
@@ -104,6 +104,36 @@ For issue-finding:
|
|
|
104
104
|
Import does not invent bottleneck categories. If import fails or the DB is empty, continue with
|
|
105
105
|
raw logs and note that cost data is unavailable.
|
|
106
106
|
|
|
107
|
+
**Schema-first rule (task 0506 R3):** history tables are owned by
|
|
108
|
+
`@gobing-ai/ts-llm-jsonl-importer` and can change between versions — never copy column lists
|
|
109
|
+
into this skill. Before any ad-hoc verification SQL that references importer-owned `history_*`
|
|
110
|
+
tables, run **one** schema-introspection query for every table you need and compose the data
|
|
111
|
+
queries from that result:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# one introspection pass, then write data queries against what it reports
|
|
115
|
+
sqlite3 <db> "SELECT name, sql FROM sqlite_schema WHERE type='table' AND name LIKE 'history_%';"
|
|
116
|
+
# (or a single `.schema history_<table>` invocation per referenced table)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
If a column you expected is absent, trust the live schema — do not guess. The importer's
|
|
120
|
+
`HISTORY_IMPORT_SCHEMA_SQL` is the authority; this skill holds no duplicate column contract.
|
|
121
|
+
|
|
122
|
+
**Selected-file bridge (task 0507 R3):** `--use-history` imports the frozen Phase-1 file set one
|
|
123
|
+
file at a time — never a root scan, never a full reconciliation. Ambient discovery covers the
|
|
124
|
+
normal OMP root (`~/.omp/agent/sessions/`) **and** workflow subprocess sessions under
|
|
125
|
+
`.spur/run/<run-id>/agent-sessions/<omp-executor>/*.jsonl` (same `type: "message"` envelope). For
|
|
126
|
+
each file, the session key is the JSONL filename stem (importer `sessionIdFromContext`); import and
|
|
127
|
+
analyze per key:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bun run apps/cli/src/index.ts history import --source omp --file <absolute-file> --mode force-file --json
|
|
131
|
+
bun run apps/cli/src/index.ts history analyze --session <filename-stem> --json
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
ETL owns token/cost/message/tool/loop/assistant-duration aggregates; raw JSONL stays authoritative
|
|
135
|
+
for command text, compactions, test/guard retries, and tool execution duration/status/errors.
|
|
136
|
+
|
|
107
137
|
## Edge cases
|
|
108
138
|
|
|
109
139
|
| Scenario | Handling |
|
|
@@ -65,7 +65,7 @@ Statuses from `TASK_STATUSES`: backlog | todo | wip | testing | blocked | done |
|
|
|
65
65
|
| A5 | `status == wip` (no usable checkpoint) | `task.show.status` | `/sp:dev-run <wbs> --mode implement --auto --next` | yes | **yes** → verify | Completes implement step then chain |
|
|
66
66
|
| A6 | `status == testing` | `task.show.status` | `/sp:dev-verify <wbs> --auto --next` | yes | **yes** — verify `--next` → done (FSM + provenance guards) | On PARTIAL/FAIL → stop review-pending (do not force done) |
|
|
67
67
|
| A7 | `status == blocked` | `task.show` + Notes/History for blocker text | `/sp:dev-handover "<blocker summary from Notes or status>"` | no | no | **STOP** after handover doc; human unblocks |
|
|
68
|
-
| A8 | `status == done` | `task.show.status` | `/sp:dev-wrap <wbs>` | no | **no** (wrap's `--merge` is irreversible HITL; never auto) | Operator may re-invoke with `--merge` explicitly later |
|
|
68
|
+
| A8 | `status == done` | `task.show.status` | `/sp:dev-wrap <wbs>` (`--agent <value>` preserved when the originating command supplied it; omission remains omission) | no | **no** (wrap's `--merge` is irreversible HITL; never auto) | Operator may re-invoke with `--merge` explicitly later |
|
|
69
69
|
| A9 | `status == cancelled` | `task.show.status` | *(none)* | no | no | **STOP** — no-op; print "cancelled — nothing to advance" |
|
|
70
70
|
|
|
71
71
|
**Priority when multiple TABLE A rows could match:** lowest row number wins (A1–A9 are mutually
|
|
@@ -83,7 +83,7 @@ When input is a feature id:
|
|
|
83
83
|
| B3 | Feature has ≥1 frontier task | task list under feature | **Recurse TABLE A** on chosen task | per A | per A | Frontier = open (`backlog`\|`todo`\|`wip`\|`testing`\|`blocked`), unblocked (all `dependencies[]` done), prefer WBS-ascending among `todo` then `backlog` then `wip` then `testing` then `blocked` |
|
|
84
84
|
| B4 | No frontier tasks AND `feature.status == backlog` AND AC placeholder/invalid | `feature check` / AC body | `/sp:dev-plan` continuation is not WBS-shaped — **STOP** with: run `/sp:dev-plan --feature <id>` or fix AC then `spur feature check <id>` | no | no | Planning-half entry needs a description; do not invent idea text |
|
|
85
85
|
| B5 | No frontier tasks AND feature has valid AC but zero tasks | feature + empty task roster | **STOP** with: `/sp:dev-plan --feature <id>` (decompose/batch-create) | no | no | Avoid auto-running plan without operator description confirmation in v1 |
|
|
86
|
-
| B6 | No frontier tasks AND all child tasks `done` AND feature in `active`\|`verifying` | task list all done | `/sp:dev-wrapall --feature <id>` | no | no | Advances feature via wrapall guards; `--merge` never auto |
|
|
86
|
+
| B6 | No frontier tasks AND all child tasks `done` AND feature in `active`\|`verifying` | task list all done | `/sp:dev-wrapall --feature <id>` (`--agent <value>` preserved when the originating command supplied it; omission remains omission) | no | no | Advances feature via wrapall guards; `--merge` never auto |
|
|
87
87
|
| B7 | No frontier tasks AND mixed cancelled/done only | statuses | **STOP** — print summary; suggest feature status update manually | no | no | |
|
|
88
88
|
| B8 | `feature.status == blocked` | feature status | **STOP** — print feature blocked; do not pick tasks | no | no | |
|
|
89
89
|
|
|
@@ -89,6 +89,15 @@ non-sandboxed shell, or a workspace that owns the storage path). The upstream fi
|
|
|
89
89
|
pi-coding-agent's storage-path resolution; it is out of scope here and recorded as motivating
|
|
90
90
|
evidence only.
|
|
91
91
|
|
|
92
|
+
## Composition with the inline pipeline driver (task 0508)
|
|
93
|
+
|
|
94
|
+
The interactive inline driver (`cross-cutting.md` § Inline-default execution surface) applies this
|
|
95
|
+
reference's default — native subagent first — to sequential `task-pipeline.yaml` `agent.run`
|
|
96
|
+
stages. Eligibility there is the same observable test (pure-slash action, non-interactive state,
|
|
97
|
+
native subagent with shared-worktree capability); the inline driver remains the authority for
|
|
98
|
+
provenance, artifact validation, and no-replay guarantees. This reference stays the authority for
|
|
99
|
+
the native-subagent versus `spur agent run` choice everywhere else.
|
|
100
|
+
|
|
92
101
|
## See also
|
|
93
102
|
|
|
94
103
|
- **`parallel-execution`** SKILL.md - the dispatch disciplines this rule sits beside.
|
|
@@ -101,6 +101,9 @@ the whole point of this facade is that the CLI surface has a single, scalable ho
|
|
|
101
101
|
prose checks here.
|
|
102
102
|
- **Not a competency.** Design, implementation, testing, and review are competency skills, not CLI
|
|
103
103
|
verbs — they are not documented here.
|
|
104
|
+
- **Not the orchestration owner.** The ADR-054 boundary: this facade owns CLI noun/verb/flag
|
|
105
|
+
semantics — including task and feature status-transition verbs — while multi-step lifecycle
|
|
106
|
+
orchestration belongs to `sp:spur-dev`.
|
|
104
107
|
|
|
105
108
|
## See also
|
|
106
109
|
|
|
@@ -117,15 +117,15 @@ If any check fails → **child of best parent** or **task under existing feature
|
|
|
117
117
|
| --- | --- | --- |
|
|
118
118
|
| Board module + UX slice as child | `F8` Features board → `F81` detail action group | **Good** — same product surface, finer grain |
|
|
119
119
|
| Restructure tooling under Feature CLI | `F3` Feature management CLI → `F31` restructure kit | **Good** — not a new root letter (was root `S`, moved) |
|
|
120
|
-
|
|
|
120
|
+
| Runtime vs plugin harness | `B` Agent execution (`spur agent`) vs `I` sp plugin (`plugins/sp`) | **Keep separate** — B owns runner/process/session/executor behavior; I owns skills, commands, subagents, hooks, and orchestration guidance. H is frozen history. |
|
|
121
121
|
| Observability UX as sibling roots | `J` board + `K` System Events table redesign + `L` payload enrichment | **Reparent K,L under J** — not body-merge; not peer roots (audit 0356) |
|
|
122
|
-
| Plugin epics as new letters | `N` dev-next UX
|
|
122
|
+
| Plugin epics as new letters | Historical `N` dev-next UX and `O` token architecture | **Historical move under H is retained; new plugin work goes under I** — do not extend frozen H |
|
|
123
123
|
| Workflow observability as board root | `P` workflow run observability as peer of `D` Workflows | **Reparent under D** — object is `spur workflow run`, not board J |
|
|
124
124
|
| Planning validation as root | `Q` AC-verifiable gates as peer of `F` Planning | **Reparent under F** |
|
|
125
125
|
| Status feedback as root | `R` feature status loop as peer of `F` | **Reparent under F** (corpus status is planning) |
|
|
126
126
|
| CLI backbone vs board product | `G` Collaboration (message/team CLI) vs `M` Teams board | **Keep both** — different surfaces; do not merge |
|
|
127
127
|
| One-off polish as root | New letter for “fix button loading” | **Bad** — task under existing feature |
|
|
128
|
-
| Done
|
|
128
|
+
| Done plugin epic as root | `I1` sp plugin hands-off ready (`done`) | **Good after reparent** — completed delivery under durable plugin root I |
|
|
129
129
|
|
|
130
130
|
### Audit 0356 snapshot (A–R dispositions)
|
|
131
131
|
|
|
@@ -144,6 +144,11 @@ Authoritative seed for restructure mapping lives in task 0356 Solution and
|
|
|
144
144
|
|
|
145
145
|
**Rejected merges:** B∪H (name-only overlap); J∪K body-merge (use reparent for K/L).
|
|
146
146
|
|
|
147
|
+
**Ownership amendment (2026-08-11):** audit 0356 is a historical snapshot. The current active
|
|
148
|
+
boundary is B = runtime agent execution, I = `sp` plugin harness, H = frozen mixed history. The
|
|
149
|
+
applied map is `docs/plans/2026-08-11-sp-plugin-feature-tree-restructure-map.md`; do not place new
|
|
150
|
+
work under H.
|
|
151
|
+
|
|
147
152
|
---
|
|
148
153
|
|
|
149
154
|
## Checklist: before `spur feature create`
|
|
@@ -18,6 +18,21 @@ pipeline run) lives in **`sp:spur-dev`** — do not reimplement that loop here.
|
|
|
18
18
|
*drive* a task through its lifecycle, reach for `sp:spur-dev`; when you need to know *which verb
|
|
19
19
|
does what*, this skill.
|
|
20
20
|
|
|
21
|
+
## WBS lookup fast path
|
|
22
|
+
|
|
23
|
+
Start from the WBS, not the corpus layout:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
spur task show <wbs> --json # metadata + full content + filePath
|
|
27
|
+
spur task path <wbs> --json # absolute path only
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Do not search `docs/tasks*` or guess `--folder` to locate a known WBS. `show` is the default when an
|
|
31
|
+
agent needs to read a task; use `path` only when another filesystem command needs the absolute path.
|
|
32
|
+
Both commands resolve across configured task folders. Add `--folder` only when deliberately limiting
|
|
33
|
+
the lookup to one non-default corpus. Capture `show` once per run and reuse its response instead of
|
|
34
|
+
re-reading or re-tokenizing the task.
|
|
35
|
+
|
|
21
36
|
## Verb map
|
|
22
37
|
|
|
23
38
|
| Verb | Purpose | Key flags |
|
|
@@ -68,7 +83,9 @@ See [tasks/verbs.md](tasks/verbs.md) for the variant detail.
|
|
|
68
83
|
exit code `3` and names the existing WBS — reuse it.
|
|
69
84
|
- **`--dedupe-within <seconds>`** overrides the default window (e.g. `--dedupe-within 60`).
|
|
70
85
|
- **`--allow-duplicate-name`** disables the guard entirely (explicit override).
|
|
71
|
-
-
|
|
86
|
+
- The guard applies to every create: feature-scoped tasks collide within the same
|
|
87
|
+
feature; unscoped tasks (no `--feature`) collide with other unscoped tasks of the
|
|
88
|
+
same title (their own collision scope).
|
|
72
89
|
- With `--json`, a duplicate emits `{ ok: false, error: { code, message, existingWbs,
|
|
73
90
|
existingName, attemptedName } }` for deterministic reuse.
|
|
74
91
|
|
|
@@ -217,6 +234,13 @@ spur task check --strict --json # elevate ALL warnings to failures
|
|
|
217
234
|
spur task check 0040 --strict-core # the testing→done gate variant
|
|
218
235
|
```
|
|
219
236
|
|
|
237
|
+
**Folder resolution (task 0522):** a WBS-targeted check (`<wbs>` present, no `--folder`) resolves
|
|
238
|
+
the task across **all configured task folders** — the same resolution as `task show` / `task path` /
|
|
239
|
+
`task update` — so a task in an inactive configured folder is checked, not reported missing. An
|
|
240
|
+
explicit `--folder <path>` is normalized to an absolute path and restricts lookup to that single
|
|
241
|
+
directory (relative and absolute spellings are equivalent). Unscoped checks (no WBS) and
|
|
242
|
+
`task list` remain active-folder-only.
|
|
243
|
+
|
|
220
244
|
`--json` emits the structured matrix — per-task findings (missing sections, broken feature edges,
|
|
221
245
|
AC-coverage orphans via L4 traceability) keyed by WBS, plus a per-task `pass` verdict. **Query this,
|
|
222
246
|
do not re-derive it**: parse the JSON to answer "which tasks are ready?", "what's blocking 0040?",
|
|
@@ -45,6 +45,10 @@ the lifecycle*; the competency skills know *how to do each job*; the CLI knows *
|
|
|
45
45
|
The skill was decomposed **by function** (ADR-028): design, decomposition, implementation, testing,
|
|
46
46
|
and verification each became a standalone competency skill, leaving this spine to orchestrate them.
|
|
47
47
|
|
|
48
|
+
**Ownership (ADR-054).** This spine owns multi-step lifecycle orchestration — intake, gates,
|
|
49
|
+
decomposition, pipeline runs, HITL pauses. CLI noun/verb/flag semantics, including
|
|
50
|
+
status-transition verbs, are the facade's (`sp:spur-cli`), never this skill's.
|
|
51
|
+
|
|
48
52
|
**The competencies the spine dispatches:**
|
|
49
53
|
|
|
50
54
|
| Unit of work | Competency skill |
|
|
@@ -154,13 +158,17 @@ CLI does.
|
|
|
154
158
|
you ship corrupted corpus.
|
|
155
159
|
2. **The pipeline, not you, writes results.** `## Testing` and `## Review` sections are
|
|
156
160
|
filled by the pipeline's `record` step. Do not edit them directly during execution.
|
|
157
|
-
3. **
|
|
161
|
+
3. **Resolve task IDs through the CLI.** Read a known WBS with `spur task show <wbs> --json`; it
|
|
162
|
+
returns metadata, full content, and `filePath` across configured task folders. Use `spur task
|
|
163
|
+
path <wbs> --json` only when another tool needs the absolute path. Never search `docs/tasks*` or
|
|
164
|
+
guess `--folder`; reuse the first `show` response throughout the run.
|
|
165
|
+
4. **Check before every write.** Run `spur task check <wbs> --json` to know what sections
|
|
158
166
|
the task needs at its current status. Guessing produces matrix violations.
|
|
159
|
-
|
|
167
|
+
5. **AC titles are identity keys.** Renaming a scenario after tasks are created breaks
|
|
160
168
|
traceability edges. If you must rename, update the task's scenario references too.
|
|
161
|
-
|
|
169
|
+
6. **Batch-create is atomic.** A single schema violation rejects the entire batch. Validate
|
|
162
170
|
locally against `task-batch.schema.json` before invoking the CLI.
|
|
163
|
-
|
|
171
|
+
7. **Two-halves seam.** The planning and execution halves share this skill today but are
|
|
164
172
|
designed to split cleanly. Keep new logic in one half or the other — never straddle the
|
|
165
173
|
seam with cross-half dependencies.
|
|
166
174
|
|
|
@@ -41,7 +41,7 @@ in scripts and audit output but does not change the default.
|
|
|
41
41
|
|
|
42
42
|
| Value | Who does the work | Derived surface |
|
|
43
43
|
|---|---|---|
|
|
44
|
-
| `inline` (default when omitted) | Whoever is running this session (interactive) or `agent.default` (headless) | Interactive: inline
|
|
44
|
+
| `inline` (default when omitted) | Whoever is running this session (interactive) or `agent.default` (headless) | Interactive: inline — host-controlled, eligible model stages may use a native subagent (0508); headless: subprocess of `agent.default` |
|
|
45
45
|
| `auto` | Tier-resolved from the stage's `min_tier` + `fallback` | Subprocess — a tier-resolved executor pins a specific agent/model, which the host session cannot supply |
|
|
46
46
|
| `<name>` (coding agent or configured executor) | That executor | Inline when it resolves to the current session's agent; subprocess otherwise |
|
|
47
47
|
|
|
@@ -105,11 +105,18 @@ meaningless.
|
|
|
105
105
|
**Interactive task pipelines invert control into the host session (ADR-047 amendment).**
|
|
106
106
|
`dev-run --mode full` and sequential `dev-runall` with omit/`inline` interpret the existing
|
|
107
107
|
`task-pipeline.yaml` in the host session; they do not launch `spur workflow run` and never redirect
|
|
108
|
-
silently to `agent.default`.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
108
|
+
silently to `agent.default`. Interactive inline is **host-controlled and non-subprocess**, but no
|
|
109
|
+
longer guarantees host-context execution for every model stage (task 0508): an eligible `agent.run`
|
|
110
|
+
stage — pure-slash input, non-interactive state, native subagent with shared-worktree
|
|
111
|
+
read/write/shell capability — dispatches **once** to that native subagent and joins before the
|
|
112
|
+
driver continues; any pre-dispatch eligibility failure falls back to one host execution, and a
|
|
113
|
+
failure after dispatch follows the stage's error policy with no automatic host replay. Operator
|
|
114
|
+
confirmation actions, `pause: true`, and approve/taste/ask decisions stay host-owned. Each inline
|
|
115
|
+
model stage appends `stage <id> executed inline in session <session-id>` to its run log; a
|
|
116
|
+
subagent-dispatched stage appends `stage <id> executed via subagent <agent-id> (host session
|
|
117
|
+
<session-id>)` instead. `dev-plan` remains a workflow subprocess, as do `dev-run`/`dev-runall` with
|
|
118
|
+
`--agent auto` or a name, parallel batches, and every headless `spur workflow run` / `spur agent
|
|
119
|
+
run`. `dev-run --mode implement` continues to run its single competency in-session under omit/`inline`.
|
|
113
120
|
|
|
114
121
|
### Executor precedence chain (R7)
|
|
115
122
|
|
|
@@ -429,6 +436,15 @@ iterating one task).
|
|
|
429
436
|
2. Loop on that narrow target until green.
|
|
430
437
|
3. **Then** run the single full `spur-check` (or `bun run check`) as the final gate.
|
|
431
438
|
|
|
439
|
+
**Dependency-aware selection (task 0510 R3).** "Narrow" is not "whatever file I touched" — a change
|
|
440
|
+
to a shared surface must also verify its downstream consumers. Pick the targeted tests and
|
|
441
|
+
typechecks from the **changed-path matrix** in `code-implementation/SKILL.md` (§ Changed-path
|
|
442
|
+
targeted checks): domain changes run affected domain + app/CLI consumer tests and
|
|
443
|
+
domain/app/CLI typechecks; app changes run affected app + CLI tests and app/CLI typechecks; CLI
|
|
444
|
+
changes run affected CLI tests and the CLI typecheck; shared plugin flag/command contract changes
|
|
445
|
+
run their focused structure/parity tests. Run only the applicable rows, then stop — the full
|
|
446
|
+
project check is still the pipeline's single final gate, never a per-iteration re-run.
|
|
447
|
+
|
|
432
448
|
Do not re-run the full suite per iteration, and do not `spur-check` before you have a green narrow
|
|
433
449
|
target. **Target:** full `spur-check` runs ≤2 per task (one during iteration, one final) instead of
|
|
434
450
|
4 across a chain.
|
|
@@ -77,8 +77,8 @@ each would be scope creep for one-liner procedures.
|
|
|
77
77
|
| 12 | brainstorm | `dev-brainstorm` | `Skill()` | `sp:brainstorm` (`dev-brainstorm`) | `<topic> [--depth <basic\|detailed\|comprehensive>] [--options <n>] [--agent <inline\|auto\|name>] [--skip-discovery] [--wayfind] [--task [<feature-id>]] [--feature [<parent-id>]] [--next]` |
|
|
78
78
|
| 13 | runall | `dev-runall` | `Skill()` → agent | `sp:spur-dev` (`runall`) → `sp:super-planner` | `--tasks <selector> [--feature <id>] [--mode <sequential\|parallel>] [--keep-going] [--auto] [--agent <inline\|auto\|name>] [--json] [--wrap] [--next] [--continue] [--worktree [<name>]]` |
|
|
79
79
|
| 13a | parallel | `dev-parallel` | `Skill()` | `sp:parallel-execution` | `--tasks <selector> [--feature <id>] [--mode <fan-out\|review-panel\|investigation>] [--agent <inline\|auto\|name>] [--json]` |
|
|
80
|
-
| 14 | wrap | `dev-wrap` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `<wbs> [--auto] [--merge] [--dry-run]`
|
|
81
|
-
| 15 | wrapall | `dev-wrapall` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `[--since <iso>] [--feature <id>] [--status <s>] [--auto] [--merge] [--dry-run]`
|
|
80
|
+
| 14 | wrap | `dev-wrap` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `<wbs> [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
|
|
81
|
+
| 15 | wrapall | `dev-wrapall` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `[--since <iso>] [--feature <id>] [--status <s>] [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
|
|
82
82
|
| 16 | idea | `dev-idea` | `Skill()` | `spur workflow run` (idea-pipeline) | `"<idea>" [--auto] [--skip-design] [--approve-taste]` |
|
|
83
83
|
|
|
84
84
|
## Skill-backed operations
|
|
@@ -137,10 +137,10 @@ must not be changed without updating the backing skill.
|
|
|
137
137
|
### 4. run
|
|
138
138
|
|
|
139
139
|
- **Purpose:** Run a task through the execution pipeline (full) or execute a single pipeline step (implement).
|
|
140
|
-
- **Inputs:** `<wbs>` (required). `--mode <full|implement>` selects the execution mode. `implement` invokes `sp:code-implementation` inline by default. Interactive `full` with omit/`--agent inline` reads `task-pipeline.yaml` and drives its actions/guards in the host session; `--agent auto`, a name, or headless invocation launches the workflow subprocess. `--agent <inline|auto|name>` selects the execution surface (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips the HITL approve gate / confirmations and propagates down the `--next` chain. `--next` controls chaining only and never changes the mode; a pipeline implement stage must invoke `/sp:dev-run <wbs> --mode implement`. On implement success with `--next`, transition `todo → wip → testing` through the FSM (guards honored — no `--no-lifecycle`) + chain to `/sp:dev-verify <wbs> --auto --next`. On a guard failure, stop as review-pending. **Partial-deliverable rule:** if the task ships only part of its requirements (e.g. an R1/R2 split with the rest in a follow-up task), the `## Solution` section must state that explicitly and the verify verdict will record the scope.
|
|
140
|
+
- **Inputs:** `<wbs>` (required). `--mode <full|implement>` selects the execution mode. `implement` invokes `sp:code-implementation` inline by default. Interactive `full` with omit/`--agent inline` reads `task-pipeline.yaml` and drives its actions/guards in the host session — host-controlled and non-subprocess, with eligible `agent.run` stages dispatching once to a native subagent and host fallback (task 0508); `--agent auto`, a name, or headless invocation launches the workflow subprocess. `--agent <inline|auto|name>` selects the execution surface (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips the HITL approve gate / confirmations and propagates down the `--next` chain. `--next` controls chaining only and never changes the mode; a pipeline implement stage must invoke `/sp:dev-run <wbs> --mode implement`. On implement success with `--next`, transition `todo → wip → testing` through the FSM (guards honored — no `--no-lifecycle`) + chain to `/sp:dev-verify <wbs> --auto --next`. On a guard failure, stop as review-pending. **Partial-deliverable rule:** if the task ships only part of its requirements (e.g. an R1/R2 split with the rest in a follow-up task), the `## Solution` section must state that explicitly and the verify verdict will record the scope. `--wrap` hands off to `/sp:dev-wrap <wbs>` after the main step; the `--agent` selector is preserved into that handoff when supplied (omission remains omission), and the wrap hop reports its own trigger-3 subprocess override per the wrap contract.
|
|
141
141
|
- **Backing:** `sp:spur-dev` skill — `run` operation for the full pipeline (the spine drives it); `sp:code-implementation` competency skill for the implement step (the spine dispatches to it).
|
|
142
142
|
- **Modes:**
|
|
143
|
-
- **`full`** (default): Drive the full pipeline — precheck → implement → test → review → approve(HITL) → verify → record → done. Interactive omit/inline uses [inline-pipeline-driver.md](inline-pipeline-driver.md); explicit/headless executor selection invokes `spur workflow run .spur/workflows/task-pipeline.yaml --vars '{"wbs":"<wbs>"}'` (with `profile: auto` when `--auto`). Both monitor/surface HITL and preserve the YAML gates. `--next` never changes this mode.
|
|
143
|
+
- **`full`** (default): Drive the full pipeline — precheck → implement → test → review → approve(HITL) → verify → record → done. Interactive omit/inline uses [inline-pipeline-driver.md](inline-pipeline-driver.md) (host-controlled; eligible stages may use a native subagent); explicit/headless executor selection invokes `spur workflow run .spur/workflows/task-pipeline.yaml --vars '{"wbs":"<wbs>"}'` (with `profile: auto` when `--auto`). Both monitor/surface HITL and preserve the YAML gates. `--next` never changes this mode.
|
|
144
144
|
- **`implement`** (explicit `--mode implement` only): Execute only the implement step. Read the task's `## Requirements` / `## Design` / `## Plan`, write the code that satisfies them, author the `## Solution` change-map section (file:line + what/why per changed file) via `spur task update <wbs> --section Solution --from-file`. This is the implement step the pipeline calls — it is NOT the pipeline driver. With `--next`: on success, transition `todo → wip → testing` through the FSM (guards honored — no `--no-lifecycle`) + chain to `/sp:dev-verify <wbs> --auto --next`; on a guard failure, stop as review-pending. **Partial-deliverable rule:** if the task ships only part of its requirements (e.g. an R1/R2 split with the rest in a follow-up task), the `## Solution` and `## Review` sections MUST carry a `⚠️ PARTIAL` marker naming the deferred part and the follow-up WBS — see `plugins/sp/commands/dev-run.md` → "Section ownership".
|
|
145
145
|
- **Delegation:** `Skill(skill="sp:spur-dev", args="run-inline $ARGUMENTS")` for interactive full omit/inline; `Skill(skill="sp:spur-dev", args="run $ARGUMENTS")` for explicit/headless full mode; `Skill(skill="sp:code-implementation", args="$ARGUMENTS")` for implement mode.
|
|
146
146
|
|
|
@@ -288,7 +288,7 @@ must not be changed without updating the backing skill.
|
|
|
288
288
|
### 13. runall
|
|
289
289
|
|
|
290
290
|
- **Purpose:** Run a batch of tasks through their pipelines in dependency-correct order — resolve a set, topo-sort, run each via `task-pipeline.yaml`, inspect verdicts, apply the failure policy, emit a batch report.
|
|
291
|
-
- **Inputs:** `--tasks <selector>` (required — explicit WBS list, status pseudo-list, `feature:<id>`, or `ready`). `--mode <sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset per `execution-batch.md` § Parallel Execution). `--keep-going` skips a failed task's in-batch dependents and continues independents (default halts on first failure). `--auto` sets `profile=auto` on each per-task run (skips the HITL approve gate). The orchestrator loop itself continues in this session;
|
|
291
|
+
- **Inputs:** `--tasks <selector>` (required — explicit WBS list, status pseudo-list, `feature:<id>`, or `ready`). `--mode <sequential|parallel>` (default `sequential`; `parallel` fans out a proven-independent subset per `execution-batch.md` § Parallel Execution). `--keep-going` skips a failed task's in-batch dependents and continues independents (default halts on first failure). `--auto` sets `profile=auto` on each per-task run (skips the HITL approve gate). `--feature <id>` is sugar for `--tasks feature:<id>`; when the effective selector is feature-derived, the batch runs `spur feature check <id> --strict --json` **once** before task resolution — a non-zero strict check aborts with verdict `aborted`, zero attempted tasks, and the structured findings (task 0510 R2); scoped: `L4.scenario-unverified` (expected pre-run state of any not-yet-run feature) is reported verbatim but does not abort — any other strict error aborts. Explicit WBS/status/`ready` selectors add no feature check. The orchestrator loop itself continues in this session; interactive sequential omit/`inline` uses the host driver — host-controlled with eligible `agent.run` stages dispatching once to a native subagent and host fallback (task 0508) — while `--agent auto`/a name, parallel mode, and headless invocation keep the isolated per-task workflow subprocess boundary. `--agent <inline|auto|name>` pins the executor for the per-task stages (see [SSOT](cross-cutting.md#inline-default-execution-surface)); the value crosses into per-task `vars.agent`, not the orchestrator. `--json` emits the report as JSON. `--wrap` triggers `wrapup-pipeline.yaml` after the batch completes, `--next` chains each task to terminal status then runs the wrap hop **once for the batch**, `--continue` resumes from checkpoint.
|
|
292
292
|
- **Three orthogonal axes (do not confuse):** `--keep-going` = batch failure policy (halt vs skip dependents); `--continue` = resume from checkpoint (pick up an interrupted batch); `--next` = per-task lifecycle chaining (advance status on a verdict — `dev-verify`/`dev-verifyall` only). `routing-table.md` offers `--continue` and `--next` as competing options for the same situation only when the batch was interrupted mid-run; otherwise they address different problems.
|
|
293
293
|
- **Backing:** `sp:spur-dev` skill, `runall` operation → delegates the driver loop to the **`sp:super-planner`** agent (the batch orchestrator).
|
|
294
294
|
- **Behavior:** The orchestrator reads [execution-batch.md](execution-batch.md) and drives: resolve selector → freeze set → topo-sort by `dependencies[]` (Kahn, WBS-ascending tie-break; cycle aborts) → resolve out-of-set deps by status (done → allow, else → block subtree) → run each task via `spur workflow run task-pipeline.yaml --async` + `spur workflow trace` polling → inspect terminal state + `.spur/run/<wbs>-verdict.json` → stop-the-batch default or `--keep-going` subtree skip → emit batch report. Per-task pipeline is invoked **verbatim** — no new FSM, no step edits. `--auto`/`--agent` are the only flags that cross the orchestrator→pipeline boundary (both into per-task `--vars`).
|
|
@@ -297,14 +297,14 @@ must not be changed without updating the backing skill.
|
|
|
297
297
|
### 14. wrap
|
|
298
298
|
|
|
299
299
|
- **Purpose:** Wrap up a single completed task — capture learnings, record metrics, sync docs, and optionally advance the feature / clean up the branch.
|
|
300
|
-
- **Inputs:** `<wbs>` (required, positional). `--auto` skips objective confirmations (the branch-cleanup HITL gate still pauses — irreversible). `--merge` triggers branch cleanup (irreversible HITL gate).
|
|
300
|
+
- **Inputs:** `<wbs>` (required, positional). `--agent <inline|auto|name>` names the wrap's model-bearing executor (default: `agent.default`); wrap is workflow-backed, so omit/`inline` resolves to `agent.default` under objective trigger 3 (durable auditable run record required), `auto` tier-resolves an executor, and a name pins that executor into `vars.agent` (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips objective confirmations (the branch-cleanup HITL gate still pauses — irreversible). `--merge` triggers branch cleanup (irreversible HITL gate).
|
|
301
301
|
- **Backing:** `spur workflow run .spur/workflows/wrapup-pipeline.yaml` — direct workflow invocation (no backing skill; the pipeline IS the procedure).
|
|
302
|
-
- **Behavior:**
|
|
302
|
+
- **Behavior:** Resolves the executor (`agent.default` for omit/`inline`, tier-resolved for `auto`, unchanged for a name), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[\"<wbs>\"]","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs: task-resolve → doc-sync → learning-capture → metrics-record → (feature-transition) → (branch-cleanup) → done. Task statuses are NOT mutated. Branch cleanup is an irreversible HITL gate that always pauses, even under `--auto`.
|
|
303
303
|
- **Vars string typing:** `tasks` is a JSON-encoded **string**, not a JSON array — `spur workflow run --vars` accepts only string values (`--vars values must be strings`); the pipeline's guards parse the string with `jq length`. `jq -nc` guarantees the shape:
|
|
304
304
|
|
|
305
305
|
```bash
|
|
306
|
-
VARS=$(jq -nc --arg tasks "[\"$WBS\"]" --arg profile "$PROFILE" --arg merge "$MERGE" \
|
|
307
|
-
'{tasks:$tasks, profile:$profile, merge:$merge}')
|
|
306
|
+
VARS=$(jq -nc --arg tasks "[\"$WBS\"]" --arg agent "$AGENT" --arg profile "$PROFILE" --arg merge "$MERGE" \
|
|
307
|
+
'{tasks:$tasks, agent:$agent, profile:$profile, merge:$merge}')
|
|
308
308
|
spur workflow run .spur/workflows/wrapup-pipeline.yaml --vars "$VARS"
|
|
309
309
|
```
|
|
310
310
|
|
|
@@ -313,14 +313,14 @@ must not be changed without updating the backing skill.
|
|
|
313
313
|
### 15. wrapall
|
|
314
314
|
|
|
315
315
|
- **Purpose:** Wrap up a batch of completed tasks — capture learnings, record metrics, sync docs, advance a feature through legal lifecycle edges, and optionally clean up branches.
|
|
316
|
-
- **Inputs:** `--since <iso-date>` filters done tasks by frontmatter `updated_at >= date` (v1 approximation). `--feature <id>` selects all tasks under a feature AND advances the feature through legal lifecycle edges (`backlog → active → verifying → done`, guards honored). `--status <s>` (default: `done`) filters by task status. `--auto` skips objective confirmations. `--merge` triggers branch cleanup (irreversible HITL gate).
|
|
316
|
+
- **Inputs:** `--since <iso-date>` filters done tasks by frontmatter `updated_at >= date` (v1 approximation). `--feature <id>` selects all tasks under a feature AND advances the feature through legal lifecycle edges (`backlog → active → verifying → done`, guards honored). `--status <s>` (default: `done`) filters by task status. `--agent <inline|auto|name>` names the wrap's model-bearing executor (default: `agent.default`); wrap is workflow-backed, so omit/`inline` resolves to `agent.default` under objective trigger 3 (durable auditable run record required), `auto` tier-resolves an executor, and a name pins that executor into `vars.agent` (see [SSOT](cross-cutting.md#inline-default-execution-surface)). `--auto` skips objective confirmations. `--merge` triggers branch cleanup (irreversible HITL gate).
|
|
317
317
|
- **Backing:** `spur workflow run .spur/workflows/wrapup-pipeline.yaml` — direct workflow invocation.
|
|
318
|
-
- **Behavior:** Resolves the task list via `spur task list --json` (filtered by `--feature`, `--since`, `--status`), builds `--vars '{"tasks":"[...]","feature":"<id>","profile":"interactive|auto","merge":"true|false"}'
|
|
318
|
+
- **Behavior:** Resolves the task list via `spur task list --json` (filtered by `--feature`, `--since`, `--status`), resolves the executor (`agent.default` for omit/`inline`, tier-resolved for `auto`, unchanged for a name), emits a pre-dispatch notice naming the subprocess override — `execution surface: subprocess`, `reason: trigger 3 — durable auditable run record required`, `requested agent: <selector>`, `executor: <resolved>` — then builds `--vars '{"tasks":"[...]","feature":"<id>","agent":"<resolved>","profile":"interactive|auto","merge":"true|false"}'` and invokes the wrapup pipeline. The pipeline runs the same states as `wrap` but with the full task list and optional feature transition. Task statuses are NOT mutated. Feature transitions go through `spur feature update` so lifecycle guards apply. Branch cleanup is an irreversible HITL gate.
|
|
319
319
|
- **Vars string typing:** `tasks` is a JSON-encoded **string**, not a JSON array — `--vars` values must be strings (the CLI rejects raw arrays); `jq -nc` passes the array text through as a string value:
|
|
320
320
|
|
|
321
321
|
```bash
|
|
322
|
-
VARS=$(jq -nc --arg tasks "$TASKS" --arg feature "$FEATURE" --arg profile "$PROFILE" --arg merge "$MERGE" \
|
|
323
|
-
'{tasks:$tasks, feature:$feature, profile:$profile, merge:$merge}')
|
|
322
|
+
VARS=$(jq -nc --arg tasks "$TASKS" --arg feature "$FEATURE" --arg agent "$AGENT" --arg profile "$PROFILE" --arg merge "$MERGE" \
|
|
323
|
+
'{tasks:$tasks, feature:$feature, agent:$agent, profile:$profile, merge:$merge}')
|
|
324
324
|
spur workflow run .spur/workflows/wrapup-pipeline.yaml --vars "$VARS"
|
|
325
325
|
```
|
|
326
326
|
|
|
@@ -64,6 +64,39 @@ function normalizeArgs(raw: Args): Args {
|
|
|
64
64
|
- If `--feature FOO` is present and `--tasks` is absent, treat the effective selector as `feature:FOO`.
|
|
65
65
|
- If both are present, `--tasks` wins (with a one-line note in the batch report).
|
|
66
66
|
|
|
67
|
+
**Feature-derived strict preflight (R2, task 0510).** After normalization, if the **effective
|
|
68
|
+
selector** is `feature:<id>` (whether via `--tasks feature:<id>` or the `--feature <id>` sugar),
|
|
69
|
+
run a source-local strict feature check **once** before any task-list resolution, freeze,
|
|
70
|
+
dependency resolution, or worktree task execution:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# monorepo source; installed projects use their resolved `spur` binary
|
|
74
|
+
bun run apps/cli/src/index.ts feature check <id> --strict --json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **Abort shape.** A non-zero check aborts the batch immediately: verdict `aborted`, zero attempted
|
|
78
|
+
tasks, and the structured feature findings (the `--json` finding list) reported verbatim. This is
|
|
79
|
+
the same abort vocabulary as cycle / unknown selector (Step 4/Step 5). **Scoped to structural
|
|
80
|
+
findings:** `L4.scenario-unverified` is the expected state of any not-yet-run feature (its
|
|
81
|
+
covering tasks have no PASS verdicts yet) and `--strict` elevates it to error, so it is reported
|
|
82
|
+
verbatim but does **not** abort the batch; every other error finding (L1–L3 structural,
|
|
83
|
+
`L4.malformed-verdict-artifact`, `L4.uncovered-feature-scenario`) still aborts. The terminal
|
|
84
|
+
feature-transition gate enforces scenario verification after the batch runs, so pre-run unverified
|
|
85
|
+
scenarios are transient, not defects (dogfood 2026-08-11, feature I2).
|
|
86
|
+
- **Exactly once.** The check runs once per batch, before `task list`; it is not re-run per task.
|
|
87
|
+
- **Non-feature exclusion.** Explicit WBS lists, status pseudo-lists, and `ready` selectors add no
|
|
88
|
+
feature check — only an effective `feature:<id>` selector is feature-derived. When explicit
|
|
89
|
+
`--tasks` overrides `--feature`, the effective selector is not feature-derived, so no check runs.
|
|
90
|
+
- **Why.** `FeatureCheckService` emits `L3.scope-delineation` (Scope lacking an In/Out split) as a
|
|
91
|
+
**warning**; feature-scoped batches never ran a strict check before freezing, so the late feature
|
|
92
|
+
transition became the first blocking check. A selector-local strict preflight catches a known
|
|
93
|
+
strict finding before any task pipeline action without changing corpus-wide severity. A not-yet-run
|
|
94
|
+
feature always fails `L4.scenario-unverified` under `--strict`, so that class is
|
|
95
|
+
reported-not-aborting per the Abort shape above — the preflight targets defects, not the
|
|
96
|
+
expected pre-run state.
|
|
97
|
+
- **Scope.** This preflight is advisory to severity policy: it does not alter `FeatureCheckService`,
|
|
98
|
+
`L3.scope-delineation` severity, `feature sync`, or batch-create.
|
|
99
|
+
|
|
67
100
|
`--tasks <value>` (or the effective value after normalization) resolves to a frozen set of task WBS numbers. Resolution happens **once, at
|
|
68
101
|
kickoff** — the driver never re-queries `spur task list` to recompute membership mid-batch (R2.1).
|
|
69
102
|
|
|
@@ -71,7 +104,7 @@ kickoff** — the driver never re-queries `spur task list` to recompute membersh
|
|
|
71
104
|
|---|---|---|
|
|
72
105
|
| Explicit WBS list | `^[0-9, ]+$` | Split on comma; validate each token is a 4-digit WBS; collect the explicit set. (R1.1) |
|
|
73
106
|
| `feature:<id>` (via `--tasks` or `--feature <id>`) | literal `feature:` prefix or `--feature` flag | `spur task list --feature <id> --json`; collect `wbs` from each row. The `--feature` flag is sugar that becomes `--tasks feature:<id>` at the command layer. (R1.3) |
|
|
74
|
-
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json`). Report each excluded task with its unmet dependency. (R1.4) |
|
|
107
|
+
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json | jq '{wbs, status, dependencies, feature_id}'` — R5 metadata-only). Report each excluded task with its unmet dependency. (R1.4) |
|
|
75
108
|
| Status pseudo-list | `todo` \| `backlog` \| `wip` \| `blocked` \| `testing` | `spur task list --status <value> --json`; collect `wbs` from each row. (R1.2) |
|
|
76
109
|
| *(else)* | no match | Error: "unknown selector `<value>`" — list the valid forms and halt before running anything. |
|
|
77
110
|
|
|
@@ -113,7 +146,7 @@ edge `A → B` means "A depends on B" (B must complete before A runs). Only edge
|
|
|
113
146
|
### 2.3 Out-of-set dependency resolution
|
|
114
147
|
|
|
115
148
|
For each dependency edge to a task **outside** the frozen set, resolve its current status via
|
|
116
|
-
`spur task show <dep-wbs> --json
|
|
149
|
+
`spur task show <dep-wbs> --json | jq '{wbs, status, dependencies, feature_id}'` (R5 metadata-only):
|
|
117
150
|
|
|
118
151
|
- status `done` → edge satisfied, drop it from the graph (R2.5). The dependent is unblocked.
|
|
119
152
|
- status ≠ `done` → mark the dependent **blocked**. Transitively mark its in-set descendants blocked
|
|
@@ -211,7 +244,7 @@ step.
|
|
|
211
244
|
```bash
|
|
212
245
|
RUN=$(spur workflow run .spur/workflows/task-pipeline.yaml \
|
|
213
246
|
--vars '{"wbs":"<wbs>","profile":"auto","agent":"claude"}' --async --json | jq -r '.runId')
|
|
214
|
-
spur workflow trace "$RUN" --json # poll until status is terminal (done/failed)
|
|
247
|
+
spur workflow trace "$RUN" --json | jq '{runId, status, terminalState}' # poll until status is terminal (done/failed)
|
|
215
248
|
```
|
|
216
249
|
|
|
217
250
|
### 3.2 Flag → `--vars` passthrough (R4.2, R4.3)
|
|
@@ -262,6 +295,7 @@ in next-router; this only maps status → primary TABLE A hop for recovery.
|
|
|
262
295
|
|
|
263
296
|
### 3.3c Bounded feature-sync retry suppression (task 0411)
|
|
264
297
|
|
|
298
|
+
|
|
265
299
|
During a batch, the per-task `record` step and the wrap-up `feature-transition` step each invoke
|
|
266
300
|
feature status sync. When a feature is L4-gate-blocked (e.g. not all linked tasks are `done`), the
|
|
267
301
|
identical blocked proposal repeats on every call with no intervening input change — in the H9
|
|
@@ -295,6 +329,42 @@ pipeline's `record` step and the wrap-up's `feature-transition` step. The driver
|
|
|
295
329
|
The only observable difference is fewer redundant `feature sync` invocations and a one-line
|
|
296
330
|
`feature-sync-bounded:` annotation on stderr when a duplicate is suppressed.
|
|
297
331
|
|
|
332
|
+
### 3.4 Metadata-only host controller (R5, task 0510)
|
|
333
|
+
|
|
334
|
+
The batch **orchestrator** reads status, ordering, and terminal state — never task bodies or trace
|
|
335
|
+
output. Task `content`, section bodies (Solution/Testing/Review), and full workflow `output` are
|
|
336
|
+
stage/subagent data and must not enter the host context on the green path; the controller that
|
|
337
|
+
dispatches native subagents must not defeat that isolation by ingesting the very bodies the
|
|
338
|
+
subagents are meant to hold (task 0508's dispatch contract is preserved unchanged).
|
|
339
|
+
|
|
340
|
+
**Green-path projections — every controller-side read is projected to metadata:**
|
|
341
|
+
|
|
342
|
+
- `task show --json` reads pipe to `{wbs, status, dependencies, feature_id}` only:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
spur task show <wbs> --json | jq '{wbs, status, dependencies, feature_id}'
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Use this shape for out-of-set dependency resolution (Step 2.3), the `ready` selector's
|
|
349
|
+
dep-status lookups (Step 1), and any other controller-side `task show`. A status-only lookup may
|
|
350
|
+
narrow further (`| jq '.status'`), but never widen.
|
|
351
|
+
|
|
352
|
+
- Green-path trace observation projects to `{runId, status, terminalState}` only:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
spur workflow trace "$RUN" --json | jq '{runId, status, terminalState}'
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The controller decides continue/halt from `status`/`terminalState` (ADR-044: judge a run by
|
|
359
|
+
`status === 'done'`, never by string-matching a `finalState` name) plus the bounded verdict
|
|
360
|
+
artifact `.spur/run/<wbs>-verdict.json`. It never streams or re-reads a full trace merely to
|
|
361
|
+
summarize status.
|
|
362
|
+
|
|
363
|
+
**Failure-path reads are bounded.** On a failed/blocked task, request only the terminal error and
|
|
364
|
+
the minimal anchor set the batch report needs (e.g. the blocking finding line, the unmet-dep WBS,
|
|
365
|
+
the verdict line) — never the entire trace. If a fuller trace is needed for diagnosis, that read
|
|
366
|
+
belongs to a subagent or the operator, not to the batch controller's report loop.
|
|
367
|
+
|
|
298
368
|
## Step 4 — Failure policy (R3)
|
|
299
369
|
|
|
300
370
|
### 4.1 Stop-the-batch (default) (R3.1)
|
|
@@ -611,7 +681,7 @@ Resume, merge, or discard:
|
|
|
611
681
|
discard: git worktree remove <worktree-path> && git branch -D <branch>
|
|
612
682
|
```
|
|
613
683
|
|
|
614
|
-
The report reuses the [`--next` chain contract](flag-glossary.md
|
|
684
|
+
The report reuses the [`--next` chain contract](flag-glossary.md#--next-chain-contract) halt-report
|
|
615
685
|
shape (halt cause + where + why), not new vocabulary. Retention is the right default: these batches
|
|
616
686
|
are long and already resumable via `--continue`; auto-deleting is data loss, auto-merging is a
|
|
617
687
|
partial result presented as a whole. The answer to "what happens if it fails" is "nothing happens,
|
|
@@ -683,6 +753,8 @@ command doc so it does not read as a bug.
|
|
|
683
753
|
| R5.1 (orchestrator boundary) | "Zero engine code" preamble + Step 3 |
|
|
684
754
|
| R5.2 (structured batch report) | Step 5 |
|
|
685
755
|
| 0411 (bounded feature-sync retry suppression) | Step 3.3c — wrapper lives in pipeline `record` + wrap-up `feature-transition`; driver unchanged |
|
|
756
|
+
| 0510 R2 (feature-derived strict preflight) | Step 1 — "Feature-derived strict preflight (R2, task 0510)" |
|
|
757
|
+
| 0510 R5 (metadata-only host controller) | Step 3.4 + projected `task show` / trace snippets in Step 1, 2.3, 3.1 |
|
|
686
758
|
|
|
687
759
|
## Parallel Execution
|
|
688
760
|
|