@gobing-ai/spur 0.3.67 → 0.3.68

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 (73) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/corpus-baseline.json +2 -50
  3. package/config/templates/docs/99_PROJECT_CONSTITUTION.md +21 -16
  4. package/config/workflow-composition-baseline.json +109 -59
  5. package/config/workflows/docs-pipeline.yaml +98 -22
  6. package/config/workflows/idea-pipeline.yaml +20 -22
  7. package/config/workflows/task-pipeline.yaml +207 -108
  8. package/package.json +9 -9
  9. package/plugins/sp/README.md +6 -7
  10. package/plugins/sp/commands/dev-idea.md +5 -3
  11. package/plugins/sp/commands/dev-plan.md +3 -1
  12. package/plugins/sp/commands/dev-review-session.md +2 -1
  13. package/plugins/sp/hooks/context-post-tool.ts +101 -2
  14. package/plugins/sp/hooks/context-session-start.ts +22 -1
  15. package/plugins/sp/plugin.json +1 -1
  16. package/plugins/sp/scripts/stage-registry-adapter.ts +144 -2
  17. package/plugins/sp/skills/session-review/SKILL.md +16 -0
  18. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +40 -16
  19. package/plugins/sp/skills/spur-dev/references/dev-operations.md +6 -6
  20. package/plugins/sp/skills/spur-dev/references/execution-batch.md +80 -11
  21. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +18 -13
  22. package/spur.js +2069 -597
  23. package/web/_astro/{BoardApp.BEtcJqde.js → BoardApp.BQFbkeqq.js} +15 -15
  24. package/web/_astro/BoardApp.CTkqrhWd.js +1 -0
  25. package/web/_astro/{TaskDetail.ClAbCXom.js → TaskDetail.Dl2Eaj1w.js} +1 -1
  26. package/web/_astro/{arc.CCvf51_y.js → arc.uG14rp8A.js} +1 -1
  27. package/web/_astro/{architectureDiagram-3BPJPVTR.C0cb0J5M.js → architectureDiagram-3BPJPVTR.Dye6uD_x.js} +1 -1
  28. package/web/_astro/{blockDiagram-GPEHLZMM.CIyjqoCE.js → blockDiagram-GPEHLZMM.B9Pkh7Hb.js} +1 -1
  29. package/web/_astro/{c4Diagram-AAUBKEIU.fs14IuFs.js → c4Diagram-AAUBKEIU.C2x7SC_X.js} +1 -1
  30. package/web/_astro/channel.Dsvulp7W.js +1 -0
  31. package/web/_astro/{chunk-2J33WTMH.CaBKv4ZO.js → chunk-2J33WTMH.D2p4-nWk.js} +1 -1
  32. package/web/_astro/{chunk-4BX2VUAB.BOllTPto.js → chunk-4BX2VUAB.S-6jf33o.js} +1 -1
  33. package/web/_astro/{chunk-55IACEB6.ChEof0O4.js → chunk-55IACEB6.DVXj4Fdh.js} +1 -1
  34. package/web/_astro/{chunk-727SXJPM.Co2kdjD8.js → chunk-727SXJPM.Dz689FMN.js} +1 -1
  35. package/web/_astro/{chunk-AQP2D5EJ.SWmfcnog.js → chunk-AQP2D5EJ.KxYj5TnI.js} +1 -1
  36. package/web/_astro/{chunk-FMBD7UC4.rDAFifF3.js → chunk-FMBD7UC4.itTQyHQB.js} +1 -1
  37. package/web/_astro/{chunk-ND2GUHAM.BCnoXKCw.js → chunk-ND2GUHAM.euSrbJf5.js} +1 -1
  38. package/web/_astro/{chunk-QZHKN3VN.RSmy2hDO.js → chunk-QZHKN3VN.OWASJRQy.js} +1 -1
  39. package/web/_astro/{classDiagram-4FO5ZUOK.Be7PEfrX.js → classDiagram-4FO5ZUOK.BLvrlpNO.js} +1 -1
  40. package/web/_astro/{classDiagram-v2-Q7XG4LA2.Be7PEfrX.js → classDiagram-v2-Q7XG4LA2.BLvrlpNO.js} +1 -1
  41. package/web/_astro/{cose-bilkent-S5V4N54A.BkUp2aSK.js → cose-bilkent-S5V4N54A.XBF-rmyD.js} +1 -1
  42. package/web/_astro/{cynefin-OW5HDTMX.BegGGlUV.js → cynefin-OW5HDTMX.DlCx762Z.js} +1 -1
  43. package/web/_astro/{dagre-BM42HDAG.BkUdjsaC.js → dagre-BM42HDAG.D17Rshxv.js} +1 -1
  44. package/web/_astro/{diagram-2AECGRRQ.E9vugt3-.js → diagram-2AECGRRQ.AhBIVJC8.js} +1 -1
  45. package/web/_astro/{diagram-5GNKFQAL.Dj4yeHXB.js → diagram-5GNKFQAL.C9ximjyC.js} +1 -1
  46. package/web/_astro/{diagram-KO2AKTUF.Buaquwli.js → diagram-KO2AKTUF.CZb7Ru_9.js} +1 -1
  47. package/web/_astro/{diagram-LMA3HP47.BV3dgGgm.js → diagram-LMA3HP47.BW7LwqoS.js} +1 -1
  48. package/web/_astro/{diagram-OG6HWLK6.Cnx3s-tc.js → diagram-OG6HWLK6.XC025W0V.js} +1 -1
  49. package/web/_astro/{erDiagram-TEJ5UH35.DKK_abu4.js → erDiagram-TEJ5UH35.CpMXmBDP.js} +1 -1
  50. package/web/_astro/{flowDiagram-I6XJVG4X.BNuu9fbm.js → flowDiagram-I6XJVG4X.D2ednJWg.js} +1 -1
  51. package/web/_astro/{ganttDiagram-6RSMTGT7.b16KUMjy.js → ganttDiagram-6RSMTGT7.BjL9FGKO.js} +1 -1
  52. package/web/_astro/{gitGraphDiagram-PVQCEYII.Kh41lbG5.js → gitGraphDiagram-PVQCEYII.B90g1VGk.js} +1 -1
  53. package/web/_astro/{infoDiagram-5YYISTIA.DEWBXkp-.js → infoDiagram-5YYISTIA.RqgycKtQ.js} +1 -1
  54. package/web/_astro/{ishikawaDiagram-YF4QCWOH.DiAdmcL6.js → ishikawaDiagram-YF4QCWOH.Ctn-zt6a.js} +1 -1
  55. package/web/_astro/{journeyDiagram-JHISSGLW.D1Ki7IRm.js → journeyDiagram-JHISSGLW.DJhT8Ctp.js} +1 -1
  56. package/web/_astro/{kanban-definition-UN3LZRKU.CWUhrQpc.js → kanban-definition-UN3LZRKU.BY1QdejI.js} +1 -1
  57. package/web/_astro/{linear.BaFsgcCe.js → linear.Di7YObSt.js} +1 -1
  58. package/web/_astro/{mermaid.core.CHw_AsGy.js → mermaid.core.CbxtJS3Q.js} +4 -4
  59. package/web/_astro/{mindmap-definition-RKZ34NQL.UIhghgmN.js → mindmap-definition-RKZ34NQL.CxvR4g_J.js} +1 -1
  60. package/web/_astro/{pieDiagram-4H26LBE5.D05l3JUA.js → pieDiagram-4H26LBE5.jNWqnBHH.js} +1 -1
  61. package/web/_astro/{quadrantDiagram-W4KKPZXB.BcWIhIcE.js → quadrantDiagram-W4KKPZXB.BCp12MbA.js} +1 -1
  62. package/web/_astro/{requirementDiagram-4Y6WPE33.B1rYvKGn.js → requirementDiagram-4Y6WPE33.Dxhm4TyR.js} +1 -1
  63. package/web/_astro/{sankeyDiagram-5OEKKPKP.CKylVRC4.js → sankeyDiagram-5OEKKPKP.BtQXp4J9.js} +1 -1
  64. package/web/_astro/{sequenceDiagram-3UESZ5HK.Dm3uA_s4.js → sequenceDiagram-3UESZ5HK.BWEM1R_Q.js} +1 -1
  65. package/web/_astro/{stateDiagram-AJRCARHV.Bgca_BLe.js → stateDiagram-AJRCARHV.BG3wUkWB.js} +1 -1
  66. package/web/_astro/{stateDiagram-v2-BHNVJYJU.C1T7YFrG.js → stateDiagram-v2-BHNVJYJU.BLtMeFVP.js} +1 -1
  67. package/web/_astro/{timeline-definition-PNZ67QCA.ZOHJn3Sn.js → timeline-definition-PNZ67QCA.D5fHo0az.js} +1 -1
  68. package/web/_astro/{vennDiagram-CIIHVFJN.DegZitjD.js → vennDiagram-CIIHVFJN.0DcuMluU.js} +1 -1
  69. package/web/_astro/{wardleyDiagram-YWT4CUSO.BDsC115d.js → wardleyDiagram-YWT4CUSO.BZ-dxgHm.js} +1 -1
  70. package/web/_astro/{xychartDiagram-2RQKCTM6.D0MO70ea.js → xychartDiagram-2RQKCTM6.Bg-XWF7z.js} +1 -1
  71. package/web/index.html +1 -1
  72. package/web/_astro/BoardApp.DBEin4N5.js +0 -1
  73. package/web/_astro/channel.BGn_DUCD.js +0 -1
@@ -78,15 +78,25 @@ vars:
78
78
  # Answer captured by the approve gate's hitl.confirm (R1): "yes" | "no" | "cancel".
79
79
  # Empty by default; only meaningful once the approve state has been entered.
80
80
  __hitlAnswer: ""
81
- # Proof-state bracket (task 0612, ADR-071). `proofDigest` is captured at verify-exit, once the
82
- # verdict artifact exists; `proofDigestNow` is the re-capture compared against it immediately
83
- # before `record`. A mismatch means a proof input changed after the verdict was established, so
84
- # the run routes to `failed` instead of crossing the completion boundary. `taskSpecPath` carries
85
- # the task file path because `docs/tasks*` is excluded from the digest's git-tree half — spec
86
- # content is folded in explicitly or a task-file edit would go undetected.
81
+ # Proof-state bracket (task 0612, ADR-071; restructured by task 0703). `proofDigest` is the
82
+ # canonical capture taken at quality-gate ENTRY immediately before the evidence-producing
83
+ # final chain (quality review verify) and re-captured at `test-recheck` when bounded
84
+ # remediation mutated the tree, so every evidence stage names one fresh digest (R2/R4).
85
+ # `proofDigestNow` is the live re-capture compared against `proofDigest` at verify entry and
86
+ # immediately before `record`; a mismatch means a proof input changed after evidence was
87
+ # established, so the run routes to `failed` instead of crossing the completion boundary (R5).
88
+ # `taskSpecPath` carries the task file path because `docs/tasks*` is excluded from the digest's
89
+ # git-tree half — spec content is folded in explicitly or a task-file edit would go undetected.
90
+ # The fingerprint scopes task content to the proof-input sections only (Background, Requirements,
91
+ # Acceptance Criteria, Design, Plan), so record-time Solution/Testing/Review evidence writes do
92
+ # not retroactively invalidate the certified input set (R6).
87
93
  proofDigest: ""
88
94
  proofDigestNow: ""
89
95
  taskSpecPath: ""
96
+ # 0710 R4: task priority tier (P0..P4) extracted from the task frontmatter at the
97
+ # quality-gate stage. P0/P1 make the review/verify distinct-executor policy apply;
98
+ # unknown/empty priority means fresh-context-only (executor reuse allowed).
99
+ taskPriority: ""
90
100
  # Project quality gate for the `test` hop (probe + fixall + recheck). Override per project
91
101
  # with the same package-manager surface (this monorepo is Bun-only):
92
102
  # `--vars '{"qualityGateCmd":"bun run lint && bun run test"}'`. Soft probe, hard recheck,
@@ -114,11 +124,11 @@ vars:
114
124
  # file:line instead of re-deriving it from a fresh gate run (0482 R3).
115
125
  gateFindings: ""
116
126
  # Max R-items in ## Requirements before size precheck fails (R2, task 0454).
117
- # Override with `--vars '{"maxImplementReqs":"12"}'`.
118
- maxImplementReqs: "5"
127
+ # Override with `--vars '{"maxImplementReqs":"20"}'`.
128
+ maxImplementReqs: "10"
119
129
  # Max checklist items under ## Plan before size precheck fails (R2, task 0454).
120
- # Override with `--vars '{"maxImplementPlanItems":"15"}'`.
121
- maxImplementPlanItems: "8"
130
+ # Override with `--vars '{"maxImplementPlanItems":"32"}'`.
131
+ maxImplementPlanItems: "16"
122
132
  # Diff-scope guard on the implement hop (R1, task 0487). When the target task
123
133
  # body backticks at least one path, non-corpus changes outside those paths
124
134
  # fail the step by name. New files beside a declared file are allowed. Empty
@@ -129,37 +139,9 @@ vars:
129
139
  states:
130
140
  - id: precheck
131
141
  description: >
132
- Pre-flight: soft agent doctor + transition guards for doctor PASS and
133
- `spur task check <wbs>`. Failures route to the `failed` terminal state
134
- (not a raw lifecycle abort mid-enter).
142
+ Fast deterministic task readiness and size checks. Failures route to the
143
+ `failed` terminal state (not a raw lifecycle abort mid-enter).
135
144
  onEnter:
136
- # Pre-launch executor doctor probe (task 0608 / D6 R4–R5). The auth classifier —
137
- # per-agent-family classification (omp/pi env-key misses soft, explicit auth
138
- # failures hard) plus the executor-divergence line — now lives in the
139
- # `doctor.probe` built-in action kind (`packages/app/src/workflow/actions/doctor-probe.ts`)
140
- # instead of this shell program; that is the ownership-surface landing for the
141
- # task-pipeline precheck doctor probe (option c, least-privilege built-in).
142
- #
143
- # Semantics preserved from the replaced shell (behavior parity is covered by
144
- # `packages/app/tests/workflow/actions/doctor-probe.test.ts`):
145
- # R2 (0487): probe BOTH resolved executors ($agent and $implementAgent) and
146
- # FAIL on `authenticated: unauthenticated`. Previously only $agent was probed
147
- # and auth was informational, so a run whose implement executor had no
148
- # provider key sailed through precheck into a guaranteed implement failure
149
- # (runs e8cb00e7 / b16bfbf4). `unknown` auth keeps the old soft behavior —
150
- # some agents expose no auth-status verb. `spur agent doctor` CLI exit-code
151
- # semantics are deliberately untouched; the gate lives here.
152
- # R4 (0487): one divergence line when the two executors differ.
153
- # R2 (0503): omp/pi env-key probe misses are soft because the CLI process
154
- # cannot see relay-owned credentials; explicit non-omp auth failures remain hard.
155
- # Soft probe: writes PASS/FAIL to the status file and always succeeds so the
156
- # transition guards below route on the token (never a raw lifecycle abort).
157
- - kind: doctor.probe
158
- options:
159
- resultFile: ".spur/run/${vars.wbs}-precheck-doctor.status"
160
- spurBin: "${vars.spurBin}"
161
- agent: "${vars.agent}"
162
- implementAgent: "${vars.implementAgent}"
163
145
  # R6 (0487): pre-launch hygiene WARNING (never a block) — starting a task on
164
146
  # a tree already dirty with another task's implementation is how 0485's diff
165
147
  # got swept into 0486's run. Corpus dirs are excluded: the pipeline writes
@@ -207,9 +189,9 @@ states:
207
189
  # R2 (0454): task size precheck — evaluate R-item and Plan-item counts.
208
190
  # Writes PASS/FAIL to .spur/run/<wbs>-precheck-size.status. Always exit 0
209
191
  # (soft check, like doctor). The precheck→implement guard reads the file.
210
- # R3 (0487): `--executor` adds the size-vs-capability gate a task past the
211
- # DEFAULT caps routed to a sub-`capable-1` executor blocks here instead of
212
- # burning the full implementTimeoutMs and exiting 3 (run ca130182).
192
+ # Temporary config-only bypass (0723): keep deterministic size limits but defer
193
+ # the executor-tier policy to the dedicated task-pipeline upgrade. This avoids
194
+ # the script's second `spur agent doctor` call while the precheck path is repaired.
213
195
  - kind: shell
214
196
  options:
215
197
  command: >-
@@ -217,8 +199,7 @@ states:
217
199
  mkdir -p .spur/run &&
218
200
  if [ -f plugins/sp/scripts/task-size-precheck.ts ]; then
219
201
  bun plugins/sp/scripts/task-size-precheck.ts "$wbs"
220
- --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems"
221
- --executor "$implementAgent";
202
+ --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems";
222
203
  else
223
204
  echo "task-size-precheck skipped — plugins/sp/scripts/task-size-precheck.ts not present in project." >&2 &&
224
205
  echo "PASS" > "$SIZE_FILE";
@@ -243,7 +224,7 @@ states:
243
224
  options:
244
225
  agent: ${vars.implementAgent}
245
226
  # Pure slash command only (ADR-043). Anti-recursion / implement discipline
246
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
227
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
247
228
  role: coder
248
229
  # lives in /sp:dev-run --mode implement → sp:code-implementation, not YAML prose.
249
230
  input: /sp:dev-run --mode implement ${vars.wbs} --auto
@@ -253,6 +234,14 @@ states:
253
234
  # a silent no-op routes the run to `failed` here instead of drifting
254
235
  # into test/review and being caught a full pass later.
255
236
  requireDiff: true
237
+ # 0706 R6: this stage mutates the working tree unattended under the
238
+ # auto profile, so it declares minimum execution-capability
239
+ # requirements. Dispatch fails closed (before spawn) when the
240
+ # resolved executor's attestation cannot satisfy them — attest the
241
+ # executor in agent config.
242
+ requiresCapabilities:
243
+ fsWrite: available
244
+ processSpawn: available
256
245
  - kind: shell
257
246
  options:
258
247
  command: >-
@@ -296,11 +285,37 @@ states:
296
285
  # test-recheck — soft recheck → review | test-fix | failed (never silent lifecycle abort)
297
286
  - id: test
298
287
  description: >
299
- Soft quality-gate probe (single logical gate on the green path; bounded retries only
300
- for SQLite lock contention). Runs
288
+ Proof-chain entry + soft quality-gate probe (single logical gate on the green path; bounded retries only
289
+ for SQLite lock contention). Capture of the canonical proof-input digest happens HERE — before any
290
+ evidence-producing final check (task 0703, ADR-071) — so the gate, review, and verification evidence
291
+ all name one digest. Then runs
301
292
  `${vars.qualityGateCmd}`, records PASS|FAIL under
302
293
  `.spur/run/<wbs>-test-gate.status`, resets the fix attempt counter, always exit 0.
303
294
  onEnter:
295
+ # R6/R2 (0703): resolve the task-spec path BEFORE the digest capture. `docs/tasks*` is excluded
296
+ # from the digest's git-tree half, so the spec is folded in explicitly via `taskSpecPath`.
297
+ - kind: shell
298
+ options:
299
+ # 0710 R4: resolve the spec path, then extract `priority:` from the TASK FILE itself (not the
300
+ # path listing); normalize to upper so requiresDistinctExecutor's exact 'P0'/'P1' match hits.
301
+ # Missing spec/line -> empty var -> back-compat (no distinctness requirement).
302
+ command: '$spurBin task path $wbs --json 2>/dev/null | jq -r ".path // .filePath // empty" > ".spur/run/$wbs-taskpath.txt" || true; sed -n "s/^priority:[[:space:]]*//p" "$(cat ".spur/run/$wbs-taskpath.txt" 2>/dev/null)" 2>/dev/null | head -1 | tr -d "[:space:]" | tr "[:lower:]" "[:upper:]" > ".spur/run/$wbs-priority.txt"; exit 0'
303
+ - kind: file.read.into-var
304
+ options:
305
+ path: .spur/run/${vars.wbs}-taskpath.txt
306
+ var: taskSpecPath
307
+ # 0710 R4: carry the task's priority tier into the review/verify risk policy.
308
+ - kind: file.read.into-var
309
+ options:
310
+ path: .spur/run/${vars.wbs}-priority.txt
311
+ var: taskPriority
312
+ # R2 (0703, ADR-071): THE canonical proof capture. Placement is load-bearing: immediately before
313
+ # the final evidence chain, after every implement mutation (including the post-implement format).
314
+ # Capture-only here; `record` compares. A remediation pass re-captures at `test-recheck` (R4).
315
+ - kind: proof.fingerprint
316
+ options:
317
+ var: proofDigest
318
+ taskFile: ${vars.taskSpecPath}
304
319
  - kind: shell
305
320
  options:
306
321
  command: >-
@@ -331,13 +346,17 @@ states:
331
346
  else
332
347
  printf 'FAIL\n' > "$STATUS_FILE";
333
348
  fi &&
349
+ printf 'proof-digest: %s\n' "$proofDigest" >> "$LOG_FILE" &&
334
350
  exit 0
335
351
 
336
352
  - id: test-fix
337
353
  description: >
338
- Bounded auto-fix hop when the quality gate is red. Increments
339
- `.spur/run/<wbs>-test-fix-attempt`, then pure slash (ADR-043)
340
- `/sp:dev-fixall` against `${vars.qualityGateCmd}`.
354
+ Bounded auto-fix hop when the quality gate is red OR final verification returned a
355
+ repairable non-PASS (task 0703 R4: remediation never happens inside verify — it loops
356
+ through here, then re-enters quality → review → verify on a fresh digest). Increments
357
+ `.spur/run/<wbs>-test-fix-attempt` (the shared bound with the quality path), projects the
358
+ verify verdict into the gate log when one exists so the repair hop sees it, then pure
359
+ slash (ADR-043) `/sp:dev-fixall` against `${vars.qualityGateCmd}`.
341
360
  onEnter:
342
361
  - kind: shell
343
362
  options:
@@ -345,7 +364,13 @@ states:
345
364
  mkdir -p .spur/run &&
346
365
  ATTEMPT_FILE=".spur/run/$wbs-test-fix-attempt" &&
347
366
  n=$(cat "$ATTEMPT_FILE" 2>/dev/null || echo 0) &&
348
- printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE"
367
+ printf '%s\n' "$((n + 1))" > "$ATTEMPT_FILE" &&
368
+ if [ -f ".spur/run/$wbs-verdict.json" ]; then
369
+ { echo '--- verify verdict (remediation input, task 0703 R4) ---';
370
+ cat ".spur/run/$wbs-verdict.json";
371
+ } >> ".spur/run/$wbs-test-gate.log";
372
+ fi;
373
+ exit 0
349
374
  # R3 (0482): project the extracted gate anchors into a var so the dispatch input
350
375
  # can NAME the failing file:line, not merely point at a log. A vars template cannot
351
376
  # run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
@@ -357,11 +382,16 @@ states:
357
382
  options:
358
383
  agent: ${vars.agent}
359
384
  # R3 (0482): `--findings` names the failing anchors inline; `--gate-log` remains
360
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
385
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
361
386
  role: coder
362
387
  # the full-context escape hatch when the digest is not enough.
363
388
  input: /sp:dev-fixall "${vars.qualityGateCmd}" --gate-log .spur/run/${vars.wbs}-test-gate.log --findings "${vars.gateFindings}"
364
389
  timeoutMs: ${vars.stepTimeoutMs}
390
+ # 0706 R6: bounded remediation hop — unattended and tree-mutating,
391
+ # so it declares the same minimum requirements as `implement`.
392
+ requiresCapabilities:
393
+ fsWrite: available
394
+ processSpawn: available
365
395
 
366
396
  - id: test-recheck
367
397
  description: >
@@ -370,6 +400,13 @@ states:
370
400
  or the pipeline `failed` state (FAIL and attempts exhausted) — never a
371
401
  raw lifecycle abort that skips the terminal `failed` state.
372
402
  onEnter:
403
+ # R4 (0703, ADR-071): bounded remediation mutated the tree by design, so the fresh evidence
404
+ # chain (recheck gate → review → verify) must start from a NEWLY captured digest. Capture-only;
405
+ # the guards and `record` compare against this value.
406
+ - kind: proof.fingerprint
407
+ options:
408
+ var: proofDigest
409
+ taskFile: ${vars.taskSpecPath}
373
410
  # 0587 R3: probe-then-full recheck. A red gateProbeCmd records FAIL and skips the full
374
411
  # gate (the measured waste is re-running a 110–140s gate to learn the tree is still red);
375
412
  # a green probe (or empty gateProbeCmd) falls through to the full-gate loop unchanged.
@@ -413,6 +450,7 @@ states:
413
450
  else
414
451
  printf 'FAIL\n' > "$STATUS_FILE";
415
452
  fi &&
453
+ printf 'proof-digest: %s\n' "$proofDigest" >> "$LOG_FILE" &&
416
454
  exit 0
417
455
 
418
456
  - id: review
@@ -420,10 +458,19 @@ states:
420
458
  onEnter:
421
459
  - kind: agent.run
422
460
  options:
423
- agent: ${vars.agent}
461
+ # 0710 R2: review always runs on a fresh session — no implementation-session
462
+ # inheritance, no latch resume; implementation context reaches the reviewer
463
+ # only via the persisted task spec, the recorded diff, and run artifacts.
464
+ # 0710 R4/R5: the agent pin is deliberately gone — role: reviewer routes
465
+ # through the executor registry, and the runner enforces (pre-dispatch,
466
+ # fail-closed) that a P0/P1 task's review resolves a DIFFERENT executor
467
+ # spec than the implement stage recorded in __agentRouting_implement.
424
468
  input: /sp:dev-review ${vars.wbs} --auto
425
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
469
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
426
470
  role: reviewer
471
+ freshSession: true
472
+ priority: ${vars.taskPriority}
473
+ compareExecutorWith: implement
427
474
  timeoutMs: ${vars.stepTimeoutMs}
428
475
 
429
476
  - id: approve
@@ -441,47 +488,64 @@ states:
441
488
 
442
489
  - id: verify
443
490
  description: >
444
- Functional verification (BDD + traceability) via /sp:dev-verify. The agent's
491
+ Observe-only functional verification (BDD + traceability) via /sp:dev-verify --fix none
492
+ (task 0703 R1, ADR-071): the verifier certifies the state, it never repairs its own subject.
493
+ A live digest compare BEFORE the agent refuses to certify a state that drifted after the
494
+ quality/review evidence was produced (R2). The agent's
445
495
  captured answer is written to `.spur/run/<wbs>-verify-answer.txt` and MUST follow
446
496
  the answer-file schema contract (explicit `Verdict: PASS|PARTIAL|FAIL` line plus
447
497
  `| Req | Status | Evidence |` and `| AC | Status | Evidence Type | Evidence |` tables);
448
498
  a deterministic shell step then derives the verdict and writes the gate artifact
449
499
  `.spur/run/<wbs>-verdict.json` (so the completion gate reads a real verdict, not
450
- agent discretion — R9). The verdict is PASS only if the agent both reported PASS
451
- AND `spur task check` passes; otherwise FAIL.
500
+ agent discretion — R9) with a proof block naming the digest and the per-stage results (R3).
501
+ Repairable non-PASS routes once through the bounded remediation hop (verify → test-fix,
502
+ R4); the chain reruns on a fresh digest.
452
503
  onEnter:
504
+ # R2 (0703): midpoint bracket compare — refuse to spend verification on a state that no
505
+ # longer matches the digest the quality/review evidence names. Reuses `proofDigestNow`:
506
+ # set here and re-set by the final compare at `record` entry.
507
+ - kind: proof.fingerprint
508
+ options:
509
+ var: proofDigestNow
510
+ taskFile: ${vars.taskSpecPath}
511
+ expect: ${vars.proofDigest}
453
512
  - kind: agent.run
454
513
  options:
455
- agent: ${vars.agent}
456
- input: /sp:dev-verify ${vars.wbs} --auto --fix all --focus all
457
- # Declared Layer-1 role (0538 R2): routing reason beside the agent: pin.
514
+ # 0710 R2: verify is a separate fresh-session execution — never the review
515
+ # session, never the implement session (R6).
516
+ # 0710 R4/R5: role-routed like review; P0/P1 demands a distinct executor.
517
+ # R1 (0703, ADR-071): `--fix none` — final verification is observe-only. Remediation
518
+ # belongs to the bounded test-fix hop, never to the certifying pass.
519
+ input: /sp:dev-verify ${vars.wbs} --auto --fix none --focus all
520
+ # Declared Layer-1 role (0538 R2/0710 R7): routing reason; no executor pin — role routing feeds the distinctness gate.
458
521
  role: reviewer
522
+ freshSession: true
523
+ priority: ${vars.taskPriority}
524
+ compareExecutorWith: implement
459
525
  timeoutMs: ${vars.stepTimeoutMs}
460
526
  answerFile: .spur/run/${vars.wbs}-verify-answer.txt
461
527
  - kind: shell
462
528
  options:
463
529
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
464
- # Proof-state capture (task 0612, ADR-071). Placement is load-bearing: AFTER the verdict
465
- # artifact exists, never before `verify`. `/sp:dev-verify --fix all` writes to the tree by
466
- # design when it repairs a row, so an earlier capture would fire on verify's own legitimate
467
- # repairs instead of on a violation.
468
- - kind: shell
469
- options:
470
- command: '$spurBin task path $wbs --json 2>/dev/null | jq -r ".path // empty" > ".spur/run/$wbs-taskpath.txt" || true; exit 0'
471
- - kind: file.read.into-var
472
- options:
473
- path: .spur/run/${vars.wbs}-taskpath.txt
474
- var: taskSpecPath
475
- - kind: proof.fingerprint
476
- options:
477
- var: proofDigest
478
- taskFile: ${vars.taskSpecPath}
479
- # R3: the evidence must NAME the digest, not just assert proof validity in prose. Stamp it
480
- # into the verdict artifact's checks[] so the document that aggregates quality, review, and
481
- # verification results carries the value `record`'s compare then proves unchanged.
530
+ # R3 (0703): write the required proof block into the verdict artifact — the digest, the
531
+ # capture point, and the named per-stage results, each stage carrying the SAME digest
532
+ # value (prose asserting proof validity is insufficient). Also keeps the flat
533
+ # `proof-input-digest` check row for consumers that read `checks[]`. Soft action + hard
534
+ # guard: a missing/malformed stamp fails the `verify → record` guard below, not this step.
482
535
  - kind: shell
483
536
  options:
484
- command: 'V=".spur/run/$wbs-verdict.json"; if [ -f "$V" ] && [ -n "$proofDigest" ]; then jq --arg d "$proofDigest" ".checks += [{\"name\":\"proof-input-digest\",\"status\":\"pass\",\"evidence\":\$d}]" "$V" > "$V.tmp" && mv "$V.tmp" "$V"; fi; exit 0'
537
+ command: >-
538
+ V=".spur/run/$wbs-verdict.json";
539
+ if [ -f "$V" ] && [ -n "$proofDigest" ]; then
540
+ jq --arg d "$proofDigest" --arg g "$(cat .spur/run/$wbs-test-gate.status 2>/dev/null || echo UNKNOWN)"
541
+ '. + {proof: {digest: $d, capturePoint: "quality-gate-entry", stages: {
542
+ qualityGate: {status: $g, digest: $d},
543
+ review: {status: "completed", digest: $d},
544
+ verification: {status: .verdict, digest: $d}}}}
545
+ | .checks += [{name: "proof-input-digest", status: "pass", evidence: $d}]'
546
+ "$V" > "$V.tmp" && mv "$V.tmp" "$V";
547
+ fi;
548
+ exit 0
485
549
 
486
550
  - id: record
487
551
  description: >
@@ -492,10 +556,15 @@ states:
492
556
  retry-suppression) if `feature_id` is present, or appends an orphan link proposal
493
557
  to the run report if absent (task 0328 / ADR-0322).
494
558
  onEnter:
495
- # Proof-state compare (task 0612, ADR-071) FIRST action in the state, so it runs before any
496
- # record write. Re-captures the digest and asserts it equals the value taken at verify-exit.
497
- # A mismatch means a proof input changed after the verdict was established; the default `fail`
498
- # policy halts the sequence and routes the run to `failed` rather than crossing into `record`.
559
+ # Proof-state compare (task 0612, ADR-071; bracket closed against the pre-chain
560
+ # capture per task 0703) FIRST action in the state, before any record write.
561
+ # Re-captures the digest and asserts it equals the value the evidence chain started
562
+ # from. A mismatch means a proof input changed after evidence was established; the
563
+ # default `fail` policy halts the sequence and routes the run to `failed` rather
564
+ # than crossing into `record`. Task-spec evidence writes (Testing/Review/Solution,
565
+ # R6) happen only in the actions AFTER this comparison, and the fingerprint scopes
566
+ # task content to the proof-input sections, so they cannot invalidate the certified
567
+ # input set.
499
568
  - kind: proof.fingerprint
500
569
  options:
501
570
  var: proofDigestNow
@@ -573,10 +642,17 @@ states:
573
642
  - kind: note
574
643
  options:
575
644
  message: "Pipeline complete for task ${vars.wbs} (done gate cleared)."
576
- # Checkpoint write: record session state for resume (Phase 4, task 0171 R3)
645
+ # Checkpoint write: record session state for resume (0711 R1–R3)
646
+ # canonical frontmatter contract; mirrors the Session Checkpoint
647
+ # Convention in plugins/sp/skills/spur-dev/references/cross-cutting.md.
648
+ # Advisory only: the task file and the persisted run row stay authoritative.
577
649
  - kind: shell
578
650
  options:
579
- command: 'mkdir -p .spur/memory/sessions && echo "checkpoint: task-pipeline done wbs=$wbs ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .spur/memory/sessions/$wbs-checkpoint.md'
651
+ # Single logical line: the composition-baseline argument-split lint flags any
652
+ # command whose continuation lines look like argument lists (heredocs with
653
+ # `- item` entries trip it), so the checkpoint body is one printf with \n escapes.
654
+ command: >-
655
+ mkdir -p .spur/memory/sessions; CP_TS="$(date -u +%Y-%m-%dT%H:%M:%SZ)"; CP_COMMIT="$(git rev-parse HEAD 2>/dev/null || echo unknown)"; CP_DIGEST="$(cut -d= -f2 .spur/run/$wbs-proofdigest.txt 2>/dev/null || echo '')"; CP_RUN="$SPUR_RUN_ID"; [ -z "$CP_RUN" ] && CP_RUN="$RUN_ID"; printf '%s\n' '---' 'schema_version: 1' "session_id: $(date -u +%Y-%m-%d)-$wbs" 'workflow: task-pipeline' "run_id: $CP_RUN" "task_wbs: $wbs" 'feature_id: ""' 'phase: done' 'status: done' 'last_gate: record' "source_commit: $CP_COMMIT" "digest: $CP_DIGEST" "generated_at: $CP_TS" "updated_at: $CP_TS" "next_action: none - task $wbs complete (terminal; advisory only)" 'artifacts:' ' - .spur/run/$wbs-verdict.json' ' - .spur/run/$wbs-test-gate.log' '---' '' '## Session Notes' '' "Terminal checkpoint for task $wbs (task-pipeline done)." 'Advisory only; the task file is authoritative.' > .spur/memory/sessions/$wbs-checkpoint.md; exit 0
580
656
 
581
657
  - id: failed
582
658
  description: >
@@ -587,17 +663,17 @@ states:
587
663
  description: Terminal — pipeline cancelled by operator at the approval gate (R1).
588
664
 
589
665
  transitions:
590
- # ── precheck: doctor PASS + task check → implement; else → failed ──
666
+ # ── precheck: size PASS + task check → implement; else → failed ──
591
667
  - from: precheck
592
668
  to: implement
593
- description: Agent doctor PASS and task check green — begin implementation.
669
+ description: Deterministic size and task checks are green — begin implementation.
594
670
  guard:
595
671
  kind: shell
596
672
  options:
597
- command: 'test "$(cat .spur/run/$wbs-precheck-doctor.status 2>/dev/null)" = PASS && test "$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
673
+ command: 'test "$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)" = PASS && $spurBin task check $wbs'
598
674
  - from: precheck
599
675
  to: failed
600
- description: Doctor FAIL and/or task check failed — stop before implement.
676
+ description: Size and/or task check failed — stop before implement.
601
677
  guard:
602
678
  kind: always
603
679
 
@@ -707,39 +783,62 @@ transitions:
707
783
  command: 'test "$__hitlAnswer" = cancel'
708
784
 
709
785
  # ── completion gate (the YAML-native replacement for rd3's default-on --postflight-verify) ──
710
- # The verify step emits .spur/run/<wbs>-verdict.json. Only `verdict: PASS` clears
711
- # the gate to `record`; any non-PASS (PARTIAL/FAIL), a missing file, or malformed
712
- # JSON routes to `failed`. Declaration order: PASS guard tried FIRST.
786
+ # The verify step emits .spur/run/<wbs>-verdict.json with a required proof block (task 0703 R3/R5).
787
+ # Only `verdict: PASS` PLUS a proof block whose digest — top level and every named stage — equals
788
+ # the captured `proofDigest` clears the gate to `record`; any non-PASS, a missing file, malformed
789
+ # JSON, or missing/mismatched proof evidence does not. Declaration order: PASS+proof guard FIRST,
790
+ # then the bounded remediation route (R4), then the always catch-all so a PASS verdict with a
791
+ # missing/malformed proof block still terminates at `failed` instead of hanging the state.
713
792
  - from: verify
714
793
  to: record
715
- description: Verification verdict is PASS — record results and proceed to done.
794
+ description: Verification verdict is PASS and its proof block names the captured digest on every stage — record results and proceed to done.
716
795
  guard:
717
796
  kind: shell
718
797
  options:
719
- command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS'
798
+ command: >-
799
+ V=".spur/run/$wbs-verdict.json";
800
+ test "$(jq -r .verdict "$V" 2>/dev/null)" = PASS &&
801
+ test "$(jq -r '.proof.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
802
+ test "$(jq -r '.proof.stages.qualityGate.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
803
+ test "$(jq -r '.proof.stages.review.digest // ""' "$V" 2>/dev/null)" = "$proofDigest" &&
804
+ test "$(jq -r '.proof.stages.verification.digest // ""' "$V" 2>/dev/null)" = "$proofDigest"
720
805
  - from: verify
721
- to: failed
722
- description: Verification verdict is not PASS (PARTIAL/FAIL/missing) — block before done.
806
+ to: test-fix
807
+ description: >-
808
+ Verification returned a repairable non-PASS and the shared fix budget is not exhausted —
809
+ bounded remediation hop (task 0703 R4); the chain re-enters quality → review → verify on a
810
+ freshly captured digest. Never reached on PASS: remediation cannot follow certification.
723
811
  guard:
724
812
  kind: shell
725
813
  options:
726
- command: 'test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" != PASS'
727
- # ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23) ──
728
- # The record step guarantees every done-required section ([Solution, Testing, Review])
729
- # has real content (each owned by its pipeline step). This guard is defense-in-depth
730
- # it certifies the matrix before done; a genuinely non-compliant task routes to failed.
814
+ command: >-
815
+ V="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)";
816
+ test -n "$V" && test "$V" != PASS &&
817
+ test "$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)" -lt "$qualityGateMaxFixAttempts"
818
+ - from: verify
819
+ to: failed
820
+ description: >-
821
+ Non-PASS with the fix budget exhausted, or a PASS/missing/malformed verdict whose proof
822
+ block is absent or mismatched (task 0703 R5) — block before done; defense catch-all so the
823
+ state always has a viable outgoing edge.
824
+ guard:
825
+ kind: always
826
+ # ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23)
827
+ # PLUS the proof-block re-assertion (task 0703 R5): the verdict artifact must still be PASS and
828
+ # still name the captured digest — a forged or mutated completion artifact fails closed here.
731
829
  # Declaration order: pass guard first.
732
830
  - from: record
733
831
  to: done
734
- description: Task check passed — certify done.
832
+ description: Task check passed and the verdict proof block still names the captured digest — certify done.
735
833
  guard:
736
834
  kind: shell
737
835
  options:
738
- command: "$spurBin task check $wbs"
836
+ command: >-
837
+ $spurBin task check $wbs &&
838
+ test "$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" = PASS &&
839
+ test "$(jq -r '.proof.digest // ""' .spur/run/$wbs-verdict.json 2>/dev/null)" = "$proofDigest"
739
840
  - from: record
740
841
  to: failed
741
- description: Task check failed — block before done; investigate missing sections.
842
+ description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
742
843
  guard:
743
- kind: shell
744
- options:
745
- command: "! $spurBin task check $wbs"
844
+ kind: always
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.67",
3
+ "version": "0.3.68",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
@@ -53,14 +53,14 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@commander-js/extra-typings": "^14.0.0",
56
- "@gobing-ai/ts-db": "^0.4.46",
57
- "@gobing-ai/ts-ai-runner": "^0.4.46",
58
- "@gobing-ai/ts-dual-workflow-engine": "^0.4.46",
59
- "@gobing-ai/ts-infra": "^0.4.46",
60
- "@gobing-ai/ts-llm-jsonl-importer": "^0.4.46",
61
- "@gobing-ai/ts-rule-engine": "^0.4.46",
62
- "@gobing-ai/ts-runtime": "^0.4.46",
63
- "@gobing-ai/ts-utils": "^0.4.46",
56
+ "@gobing-ai/ts-db": "^0.4.48",
57
+ "@gobing-ai/ts-ai-runner": "^0.4.48",
58
+ "@gobing-ai/ts-dual-workflow-engine": "^0.4.48",
59
+ "@gobing-ai/ts-infra": "^0.4.48",
60
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.4.48",
61
+ "@gobing-ai/ts-rule-engine": "^0.4.48",
62
+ "@gobing-ai/ts-runtime": "^0.4.48",
63
+ "@gobing-ai/ts-utils": "^0.4.48",
64
64
  "@types/bun": "1.3.14",
65
65
  "@types/figlet": "^1.7.0",
66
66
  "@types/node-notifier": "8.0.5",
@@ -567,8 +567,9 @@ graph TB
567
567
  1. User types `/sp:dev-plan "add task body write API"`.
568
568
  2. **Command** (`dev-plan.md`) parses `$ARGUMENTS` and calls
569
569
  `Skill(skill="sp:spur-dev", args="plan $ARGUMENTS")`.
570
- 3. **Skill** (`spur-dev/SKILL.md`) drives the planning half: intake `spur feature create` → AC
571
- generation → `spur feature check` gate decomposition → `spur task batch-create`.
570
+ 3. **Skill** (`spur-dev/SKILL.md`) reads `idea-pipeline.yaml` and drives its states in the current
571
+ session by default: intake → `spur feature create` → AC generation → `spur feature check` gate →
572
+ decomposition → `spur task batch-create`. Explicit `--agent auto|<name>` uses the async worker.
572
573
  4. **CLI** validates each step before writing — feature IDs are race-safe, WBS allocation is atomic,
573
574
  `check` is the readiness matrix.
574
575
  5. Result: validated feature file + decomposed task batch in `docs/features/` and `docs/tasks/`.
@@ -577,10 +578,9 @@ graph TB
577
578
 
578
579
  1. User types `/sp:dev-run 0090`.
579
580
  2. **Command** delegates to `sp:spur-dev` skill (execution half).
580
- 3. **Skill** reads the task, loads `task-pipeline.yaml`, and runs
581
- `spur workflow run` with HITL surfacing.
582
- 4. **CLI** executes the workflow engine (`@gobing-ai/ts-dual-workflow-engine`), pauses at HITL gates,
583
- persists run state.
581
+ 3. **Skill** reads the task and `task-pipeline.yaml`, then drives its actions and guards in-session.
582
+ 4. **CLI** supplies deterministic actions and lifecycle gates; explicit executors use the async
583
+ workflow worker and persisted run state.
584
584
  5. Result: task driven through implement → check → fix → verify lifecycle.
585
585
 
586
586
  **Task-corpus write protection.**
@@ -606,7 +606,6 @@ pipeline owns one lifecycle phase:
606
606
  | `task-pipeline.yaml` | Single-task execution | `/sp:dev-run` |
607
607
  | `idea-pipeline.yaml` | Idea/planning → feature + tasks | `/sp:dev-idea`, `/sp:dev-plan` |
608
608
  | `feature-dev.yaml` | Feature umbrella execution | `/sp:dev-runall --feature` |
609
- | `idea-pipeline.yaml` | Idea to feature + AC + task batch | `/sp:dev-idea` |
610
609
  | `wrapup-pipeline.yaml` | Post-execution wrap-up | `/sp:dev-wrap`, `/sp:dev-wrapall` |
611
610
  | `docs-pipeline.yaml` | Docs-only task execution | `/sp:dev-run --mode implement` |
612
611
  | `wayfinder-resolution.yaml` | Wayfinder ticket resolution loop | `spur workflow run` (free-form) |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Turn a vague idea into a feature with AC and a decomposed task batch — discovery, idea-eval, feature-create, AC, feature-check, system-design, decompose, batch-create (Design by default), handoff
3
3
  role: planner
4
- argument-hint: "\"<idea>\" [--auto] [--skip-design] [--approve-taste] [--agent <auto|name>]"
4
+ argument-hint: "\"<idea>\" [--auto] [--skip-design] [--approve-taste] [--agent <inline|auto|name>]"
5
5
  allowed-tools: ["Bash", "Read", "Skill", "AskUserQuestion"]
6
6
  ---
7
7
 
@@ -20,7 +20,7 @@ contract below maps to that workflow's transitions.
20
20
  | `--approve-taste` | With `--auto`: set idea_approved + design_approved so idea-eval / design-approval do not pause. | off |
21
21
  | `--idea-approved` | Compatibility alias for idea_approved=true (subset of --approve-taste). | off |
22
22
  | `--design-approved` | Compatibility alias for design_approved=true (subset of --approve-taste). | off |
23
- | `--agent` `<auto\|name>` | Who runs the model-bearing ideation. The pipeline's `agent.run` stages are headless — they always dispatch a subprocess. Omission and explicit `--agent inline` resolve identically per task 0687: tier substitution plus one warning naming the substituted executor; `auto` (tier-resolves an executor); a name (pins that executor). | inline |
23
+ | `--agent` `<inline\|auto\|name>` | Who runs the model-bearing ideation. Omission and `inline` drive `idea-pipeline.yaml` in this session with zero external agent/workflow processes; `auto` tier-resolves an executor and a name pins one, both through the async workflow worker. | inline |
24
24
 
25
25
  For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
26
26
 
@@ -31,7 +31,7 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
31
31
  [--auto] # skip objective HITL only (feature-check, batch-create)
32
32
  [--skip-design] # design package off (system-design + task Design)
33
33
  [--approve-taste] # with --auto: skip idea-eval + design-approval pauses
34
- [--agent <auto|name>] # who runs the model-bearing ideation (default: agent.default)
34
+ [--agent <inline|auto|name>] # inline is the current session; auto/name are async workers
35
35
  ```
36
36
 
37
37
  There is **no** `--design` force flag. Design is default-on; only `--skip-design` opts out.
@@ -42,6 +42,8 @@ vars as subsets of `--approve-taste` (`idea_approved` / `design_approved`). Pref
42
42
  ## Implementation
43
43
 
44
44
  - Apply the [inline-default execution-surface contract](../skills/spur-dev/references/cross-cutting.md#inline-default-execution-surface).
45
+ - Omitted/`inline`: drive `idea-pipeline.yaml` through the [inline pipeline driver](../skills/spur-dev/references/inline-pipeline-driver.md). Do not launch `spur workflow run`, `spur agent run`, or a native subagent unless the operator explicitly requests delegation.
46
+ - `auto`/name: launch `spur workflow run idea-pipeline.yaml --async`, observe with one `workflow trace --follow`, and only report cancellation as stopped when `workflow cancel --json` returns `killed: true`.
45
47
  - `Skill(skill="sp:spur-dev", args="idea $ARGUMENTS")`
46
48
  - Stage contract (discovery → idea-eval → feature-create → AC → feature-check → system-design →
47
49
  decompose → batch-create → handoff): `plugins/sp/skills/spur-dev/references/dev-operations.md` § idea.