@gobing-ai/spur 0.3.40 → 0.3.42

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 (185) hide show
  1. package/.claude-plugin/marketplace.json +15 -0
  2. package/README.md +15 -1
  3. package/config/templates/AGENTS.md +5 -3
  4. package/config/workflows/task-pipeline.yaml +103 -12
  5. package/package.json +15 -12
  6. package/plugins/README.md +655 -0
  7. package/plugins/sp/README.md +621 -0
  8. package/plugins/sp/agents/expert-spur.md +109 -0
  9. package/plugins/sp/agents/super-coder.md +126 -0
  10. package/plugins/sp/agents/super-planner.md +283 -0
  11. package/plugins/sp/agents/super-reviewer.md +154 -0
  12. package/plugins/sp/commands/dev-arch.md +30 -0
  13. package/plugins/sp/commands/dev-brainstorm.md +40 -0
  14. package/plugins/sp/commands/dev-changelog.md +28 -0
  15. package/plugins/sp/commands/dev-daily.md +29 -0
  16. package/plugins/sp/commands/dev-debug.md +29 -0
  17. package/plugins/sp/commands/dev-dogfood.md +33 -0
  18. package/plugins/sp/commands/dev-featurechange.md +130 -0
  19. package/plugins/sp/commands/dev-find-conflict.md +51 -0
  20. package/plugins/sp/commands/dev-find-issue.md +76 -0
  21. package/plugins/sp/commands/dev-find-next.md +60 -0
  22. package/plugins/sp/commands/dev-fixall.md +33 -0
  23. package/plugins/sp/commands/dev-gitmsg.md +28 -0
  24. package/plugins/sp/commands/dev-gtd.md +97 -0
  25. package/plugins/sp/commands/dev-handover.md +26 -0
  26. package/plugins/sp/commands/dev-idea.md +50 -0
  27. package/plugins/sp/commands/dev-next.md +31 -0
  28. package/plugins/sp/commands/dev-parallel.md +30 -0
  29. package/plugins/sp/commands/dev-plan.md +46 -0
  30. package/plugins/sp/commands/dev-refine.md +48 -0
  31. package/plugins/sp/commands/dev-refineall.md +65 -0
  32. package/plugins/sp/commands/dev-refresh.md +32 -0
  33. package/plugins/sp/commands/dev-reverse.md +32 -0
  34. package/plugins/sp/commands/dev-review.md +31 -0
  35. package/plugins/sp/commands/dev-run.md +63 -0
  36. package/plugins/sp/commands/dev-runall.md +80 -0
  37. package/plugins/sp/commands/dev-simplify.md +39 -0
  38. package/plugins/sp/commands/dev-unit.md +29 -0
  39. package/plugins/sp/commands/dev-verify.md +48 -0
  40. package/plugins/sp/commands/dev-verifyall.md +72 -0
  41. package/plugins/sp/commands/dev-wrap.md +30 -0
  42. package/plugins/sp/commands/dev-wrapall.md +33 -0
  43. package/plugins/sp/commands/rule-add.md +18 -0
  44. package/plugins/sp/commands/rule-refine.md +18 -0
  45. package/plugins/sp/commands/rule-scan.md +18 -0
  46. package/plugins/sp/commands/spur-init.md +22 -0
  47. package/plugins/sp/commands/workflow-add.md +18 -0
  48. package/plugins/sp/commands/workflow-refine.md +18 -0
  49. package/plugins/sp/hooks/agent-hint.ts +60 -0
  50. package/plugins/sp/hooks/careful-guard.ts +147 -0
  51. package/plugins/sp/hooks/context-post-tool.ts +325 -0
  52. package/plugins/sp/hooks/context-session-start.ts +182 -0
  53. package/plugins/sp/hooks/context-session-stop.ts +95 -0
  54. package/plugins/sp/hooks/hooks.json +51 -0
  55. package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
  56. package/plugins/sp/hooks/task-write-guard.ts +84 -0
  57. package/plugins/sp/plugin.json +8 -0
  58. package/plugins/sp/scripts/batch-preflight.ts +204 -0
  59. package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
  60. package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
  61. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
  62. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
  63. package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
  64. package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
  65. package/plugins/sp/scripts/task-size-precheck.ts +202 -0
  66. package/plugins/sp/scripts/validate-commands.ts +651 -0
  67. package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
  68. package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
  69. package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
  70. package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
  71. package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
  72. package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
  73. package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
  74. package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
  75. package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
  76. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
  77. package/plugins/sp/skills/code-implementation/SKILL.md +176 -0
  78. package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
  79. package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
  80. package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
  81. package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
  82. package/plugins/sp/skills/code-review/SKILL.md +112 -0
  83. package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
  84. package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
  85. package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
  86. package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
  87. package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
  88. package/plugins/sp/skills/code-testing/SKILL.md +108 -0
  89. package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
  90. package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
  91. package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
  92. package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
  93. package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
  94. package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
  95. package/plugins/sp/skills/code-verification/SKILL.md +535 -0
  96. package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
  97. package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
  98. package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
  99. package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
  100. package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
  101. package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
  102. package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
  103. package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
  104. package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
  105. package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
  106. package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
  107. package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
  108. package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
  109. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
  110. package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
  111. package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
  112. package/plugins/sp/skills/functional-review/SKILL.md +364 -0
  113. package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
  114. package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
  115. package/plugins/sp/skills/issue-finding/SKILL.md +424 -0
  116. package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
  117. package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
  118. package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
  119. package/plugins/sp/skills/issue-finding/references/session-formats.md +121 -0
  120. package/plugins/sp/skills/next-feature/SKILL.md +125 -0
  121. package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
  122. package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
  123. package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
  124. package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
  125. package/plugins/sp/skills/next-router/SKILL.md +181 -0
  126. package/plugins/sp/skills/next-router/references/messages.md +90 -0
  127. package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
  128. package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
  129. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +100 -0
  130. package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
  131. package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
  132. package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
  133. package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
  134. package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
  135. package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
  136. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
  137. package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
  138. package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
  139. package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
  140. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
  141. package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
  142. package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
  143. package/plugins/sp/skills/spur-cli/references/features.md +234 -0
  144. package/plugins/sp/skills/spur-cli/references/init.md +119 -0
  145. package/plugins/sp/skills/spur-cli/references/message.md +98 -0
  146. package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
  147. package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
  148. package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
  149. package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
  150. package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
  151. package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
  152. package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
  153. package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
  154. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
  155. package/plugins/sp/skills/spur-cli/references/tasks.md +278 -0
  156. package/plugins/sp/skills/spur-cli/references/team.md +133 -0
  157. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
  158. package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
  159. package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
  160. package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
  161. package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
  162. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
  163. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +664 -0
  164. package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
  165. package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
  166. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
  167. package/plugins/sp/skills/spur-dev/references/execution-batch.md +727 -0
  168. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +350 -0
  169. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
  170. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
  171. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
  172. package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
  173. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
  174. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +88 -0
  175. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
  176. package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
  177. package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
  178. package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
  179. package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
  180. package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
  181. package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
  182. package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
  183. package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
  184. package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
  185. package/spur.js +6093 -5180
@@ -0,0 +1,664 @@
1
+ ---
2
+ name: cross-cutting
3
+ description: "Extracted section: cross-cutting write rules shared by both halves — every-write-is-CLI-gated, the section-editing body-only workflow, the section-status matrix, and check-before-write. These mechanics apply to all planning and execution writes."
4
+ see_also:
5
+ - spur-dev
6
+ ---
7
+
8
+ # Cross-cutting Rules
9
+
10
+ These mechanics apply to **every** write in both the planning and execution halves. The skill
11
+ knows *how to think*; the CLI knows *what is valid* — every mutation passes through a CLI verb
12
+ that validates before writing.
13
+
14
+ **Split from `glossary.md`:** this file owns **process rules** (how writes happen, what the Iron
15
+ Laws are, what `--auto` does). [glossary.md](glossary.md) owns **term definitions** (what a word
16
+ like *spine*, *gate*, or *verdict* means). A rule below may use a glossary term by name; it does
17
+ not redefine it.
18
+
19
+ ## Inline-default execution surface
20
+
21
+ > **This section is the single source of truth for `--agent` value semantics, the executor
22
+ > precedence chain, and the `implementAgent` override.** Every other reference (flag-glossary,
23
+ > execution-workflow, execution-batch, dev-operations, cmd_agent, cmd_workflow) links here and
24
+ > does not restate the contract. The value table below is authoritative; parity with it is
25
+ > enforced by `validate-flag-contracts.ts` (C3a/C3b).
26
+
27
+
28
+ ### The one rule
29
+
30
+ > **`--agent <value>` names *who* does the model-bearing work. The execution surface is derived from
31
+ > that choice, never declared separately:** if the named executor is the agent already running this
32
+ > session, the work happens inline; otherwise it dispatches a subprocess.
33
+
34
+ That is the whole contract. `--agent` answers *who*, not *where* — "where" is arithmetic on the
35
+ answer. Everything below is a consequence of that sentence, not an additional rule.
36
+
37
+ **Default: execute the backing skill directly in the current coding-agent session.** Do not invoke
38
+ `spur agent run` when no escalation trigger applies and the operator did not select subprocess via
39
+ the `--agent` selector. Omitting `--agent` is exactly `--agent inline`; the explicit value is useful
40
+ in scripts and audit output but does not change the default.
41
+
42
+ | Value | Who does the work | Derived surface |
43
+ |---|---|---|
44
+ | `inline` (default when omitted) | Whoever is running this session (interactive) or `agent.default` (headless) | Interactive: inline (host session); headless: subprocess of `agent.default` |
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
+ | `<name>` (coding agent or configured executor) | That executor | Inline when it resolves to the current session's agent; subprocess otherwise |
47
+
48
+ The previous `--inline` and `--subprocess` flags (feature H82, task 0413) are collapsed into this
49
+ single selector: `--inline` → `--agent inline`, `--subprocess` → `--agent auto`. The old two-flag
50
+ form is no longer part of the command surface.
51
+
52
+ This is a prompt-runtime rule owned by the command wrapper and its backing skill, not a branch in
53
+ `AgentService`: the current coding agent is already executing the command, so inline means continuing
54
+ in that session. Threading an `inline` option through `AiRunner` would still start a subprocess and
55
+ would therefore be a false implementation. On a headless surface (`spur agent run` / workflow
56
+ `agent.run`) `inline` is **not** rejected (ADR-047): it resolves exactly like omitting the flag to a
57
+ subprocess of `agent.default`.
58
+
59
+ ### Objective triggers override the answer
60
+
61
+ The one rule resolves operator *intent*. A trigger is a detected *requirement* the chosen executor
62
+ cannot satisfy, so it wins regardless:
63
+
64
+ | Trigger | Subprocess condition | Required report |
65
+ | --- | --- | --- |
66
+ | **Different model or coding agent required** | The requested `--agent <name>` / model cannot be supplied by the host session. | `trigger 1: different model or coding agent required` |
67
+ | **Headless or unattended step** | No live coding-agent session can own the step (scheduled, detached, async worker). | `trigger 2: headless or unattended step` |
68
+ | **Durable auditable run record required** | The caller requires a persisted cost/trace/exit-code record. | `trigger 3: durable auditable run record required` |
69
+ | **Workspace or credential isolation required** | The work must not share the host workspace or credentials. | `trigger 4: workspace or credential isolation required` |
70
+
71
+ A trigger selects subprocess even when `--agent inline` was supplied, and the applied trigger must be
72
+ named in the dispatch or result. When the operator selected a non-current executor and no objective trigger
73
+ applies, report `operator override` rather than inventing one of the four. The trigger vocabulary and
74
+ evidence standard are owned by
75
+ [dispatch-surface.md](../../parallel-execution/references/dispatch-surface.md). If none can be named
76
+ and the selector resolves to the current agent, stay inline.
77
+
78
+ Never hardcode an agent: forward the operator's selector; when none was provided, let
79
+ `spur agent run` resolve its configured default.
80
+
81
+ ### Consequence: where the selector is delivered
82
+
83
+ The one rule says *who*. How the selector reaches that executor depends on where the model-bearing
84
+ work lives in the command:
85
+
86
+ **Single-skill dispatch** — the command's own backing skill is the model-bearing work. Invoke
87
+ `spur agent run` exactly once. Strip the outer `--agent` selector from the command placed in the
88
+ child prompt; pass it to the outer `spur agent run --agent <value>` instead. Tell the child that the
89
+ surface is already resolved and name the trigger / `operator override`. A command already executing
90
+ inside that subprocess boundary runs its backing skill in that process; it must not spawn another
91
+ `spur agent run` for the same trigger. This prevents recursive dispatch.
92
+
93
+ **Pipeline wrappers (`dev-run`, `dev-runall`)** — the orchestrator is a loop; its *stages* do the
94
+ model-bearing work. Interactive omit/`inline` therefore uses the
95
+ [inline pipeline driver](inline-pipeline-driver.md): it reads `task-pipeline.yaml`, executes each
96
+ `agent.run` input through the backing skill in the host session, and preserves every shell action
97
+ and guard. `auto` or a named executor is merged into per-task `vars.agent` and
98
+ `vars.implementAgent`, and the workflow's `agent.run` steps run under that subprocess executor (see
99
+ `execution-batch.md` § 3.2). The loop itself continues in the current session.
100
+
101
+ This is **the same rule, not an exception**: `--agent` names who does the thinking, and in a pipeline
102
+ the thinking happens in the stages. Selecting an executor for a loop that runs no prompts would be
103
+ meaningless.
104
+
105
+ **Interactive task pipelines invert control into the host session (ADR-047 amendment).**
106
+ `dev-run --mode full` and sequential `dev-runall` with omit/`inline` interpret the existing
107
+ `task-pipeline.yaml` in the host session; they do not launch `spur workflow run` and never redirect
108
+ silently to `agent.default`. Each inline model stage appends
109
+ `stage <id> executed inline in session <session-id>` to its run log. `dev-plan` remains a workflow
110
+ subprocess, as do `dev-run`/`dev-runall` with `--agent auto` or a name, parallel batches, and every
111
+ headless `spur workflow run` / `spur agent run`. `dev-run --mode implement` continues to run its
112
+ single competency in-session under omit/`inline`.
113
+
114
+ ### Executor precedence chain (R7)
115
+
116
+ For workflow-pipeline `agent.run` steps on the explicit/headless subprocess surface, the executor is
117
+ resolved in this order; first match wins:
118
+
119
+ 1. **`--agent` / explicit `--vars '{"agent":"<value>"}'`** — the operator's selector, merged into
120
+ `vars.agent` by the command wrapper. This is the highest-precedence input.
121
+ 2. **`agent.default`** from `.spur/config.yaml` (project layer, then `~/.config/spur/config.yaml`) —
122
+ `spur workflow run` injects it as the `agent` var when `vars.agent` was not set by the caller.
123
+ 3. **YAML literal `agent:` in the pipeline file** — the last-resort fallback declared in the
124
+ workflow YAML (e.g. `agent: "omp"` in `task-pipeline.yaml`). This fires only when no
125
+ `agent.default` is configured anywhere.
126
+
127
+ `--agent auto` tier-resolves an executor (stage `model_policy` → `agent.default` → tier priority)
128
+ **before** merging, so it enters the chain at step 1 already resolved to a concrete name.
129
+ On a headless workflow surface, `--agent inline` resolves like omit to `agent.default`. Interactive
130
+ task wrappers consume omit/`inline` before this chain and use the host driver. Omitting the flag on a
131
+ headless surface forwards nothing, so the spawned step resolves to `agent.default` (step 2) or the
132
+ YAML literal (step 3).
133
+
134
+ ### Implement-only executor override (R6)
135
+
136
+ `task-pipeline.yaml` declares a separate `implementAgent` var. The `implement` state's `agent.run`
137
+ step reads `${vars.implementAgent}` instead of `${vars.agent}`, so an operator can pin the
138
+ implement hop to one executor while review/verify/test-fix hops keep the default agent:
139
+
140
+ ```bash
141
+ # Pin implement to a specific executor; other hops keep agent.default / YAML literal
142
+ --vars '{"implementAgent":"omp-zai"}'
143
+ ```
144
+
145
+ All other `agent.run` steps (test-fix, review, verify) read `${vars.agent}`. `implementAgent`
146
+ applies **only** to the implement hop. **The `--agent` flag forwards into BOTH `agent` and
147
+ `implementAgent`** at the execution-batch boundary (§3.2), so a pinned `--agent X` reaches every
148
+ hop including implement. To pin ONLY implement to a different executor while other hops keep the
149
+ default, pass `--vars '{"implementAgent":"..."}'` separately (task 0483 R2).
150
+
151
+ ### Executor exhaustion is survivable, not a pin-away problem (task 0482 R1/R5)
152
+
153
+ Every executor can exhaust its provider quota — **including `omp`/Claude**, which enforces its own
154
+ 5-hour rolling limits. No executor is exempt from hard limits, so "pick a safe executor to pin" is
155
+ not durable guidance: pinning one converts a recoverable failure into a rarer, unhandled one. The
156
+ pipeline survives exhaustion automatically — a dispatch that fails with a 429/quota body is
157
+ classified as `resource-exhaustion` and escalates to the stage's next eligible tier, **even when the
158
+ run started from a pinned executor**. The pin chooses where a run *starts*; it does not disable
159
+ recovery (0482 R1). To confirm recovery is wired, watch the run log for
160
+ `Escalating: <executor> (tier <t>) failed with resource-exhaustion; retrying on <executor>` — that
161
+ line, not quota state, is the signal that the fallback ladder fired.
162
+
163
+ Do not read provider quota from `spur agent doctor`. The doctor resolves provider keys from
164
+ `${PROVIDER}_API_KEY` env vars and cannot see an agent-owned credential store (e.g. omp's models
165
+ config), so its row degrades to `status: usable · auth: no · model: unknown` for GLM-style executors
166
+ and is useless as a preflight gate. Exhaustion is detected mid-run by the escalation classifier, not
167
+ by any preflight probe.
168
+
169
+ ### Explicit subprocess surfaces are unchanged
170
+
171
+ Direct `spur agent run` invocations are always subprocess execution. A workflow launched through
172
+ `spur workflow run` executes `agent.run` actions as subprocesses. Those surfaces already express an
173
+ explicit process boundary and retain their existing resolution, output, timeout, and trace
174
+ contracts. The interactive task wrapper does not change the YAML or engine; it reads the YAML as
175
+ SSOT and interprets the actions in-session before any workflow subprocess exists. It records inline
176
+ provenance without fabricating an `AgentRunTracedResult`.
177
+ `spur agent run` itself resolves omit/`inline` to `agent.default` and `--agent auto` tier-resolves —
178
+ the unified `--agent` selector on the dev command surface does not change the CLI's resolution.
179
+
180
+ ### Inline trade-off
181
+
182
+ Inline avoids process startup and preserves the host session's context and tools. Relative to
183
+ subprocess dispatch it provides **no isolated workspace**, **no per-stage subprocess action
184
+ record**, **no independent timeout or abort boundary**, and **no tier-selected executor**: the
185
+ executor is the current coding agent. Interactive task pipelines retain a run log, run-link, and
186
+ session provenance through the inline driver. If process isolation or an independently killable
187
+ stage is required, select the subprocess path (`--agent auto` or `--agent <name>`).
188
+
189
+ ## Every write is CLI-gated
190
+
191
+ Never edit a task or feature file directly. Every mutation goes through:
192
+
193
+ | Intent | CLI verb |
194
+ |--------|----------|
195
+ | Create a task | `spur task create` |
196
+ | Change status | `spur task update <wbs> <status>` |
197
+ | Edit a section | `spur task update <wbs> --section <name> --from-file <path>` |
198
+ | Record verify results | `spur task record <wbs> [--solution-from-diff] [--transition <status>]` |
199
+ | Create a feature | `spur feature create` |
200
+ | Batch create tasks | `spur task batch-create --file <json>` |
201
+
202
+ ## Status transitions in `--next` chains honor the FSM
203
+
204
+ The interactive `--next` step-chain (`dev-refine → dev-run → dev-verify → done`) moves a task's
205
+ status with `spur task update <wbs> <status>` **without `--no-lifecycle`**, so the lifecycle guards
206
+ run: `wip → testing` invokes `spur task check`, `testing → done` invokes
207
+ `spur task check --strict-core`. A guard failure **stops the chain as review-pending** — leave the
208
+ task at its current status, surface the blocking finding, do not advance. This is the gate that
209
+ keeps a malformed task out of `testing`/`done`.
210
+
211
+ `--no-lifecycle` is **bookkeeping, not a guard bypass**: `task-pipeline.yaml` suppresses
212
+ lifecycle-*run* creation because it is already a run and a nested one would orphan. The structural
213
+ gate still runs — `→ testing` and `→ done` invoke `spur task check` regardless of the flag.
214
+
215
+ > **Behavior corrected 2026-08-07.** `--no-lifecycle` previously suppressed enforcement as a side
216
+ > effect of suppressing the run record, because the FSM guards live inside the lifecycle workflow.
217
+ > Combined with `--force-done` (which waives the verify **verdict** only) it left nothing: a task
218
+ > walked `wip → done` carrying L3 errors. Neither flag leaks alone. The CLI now runs the gate
219
+ > inline whenever the FSM guard will not. **was: `--no-lifecycle` skipped the check entirely.**
220
+
221
+ ### Bounding context compaction in `--next` chains
222
+
223
+ Long `--next` chains that run several tasks in **one session** accumulate cross-task context (each
224
+ task's full tool transcript, diff, and re-ingested files) and trigger repeated LLM context
225
+ compactions. Each compaction is a context rebuild the model must re-ingest and re-reason over; on a
226
+ three-task chain this clustered 4 compactions in a single 2.9h run (task 0436 forensics). The
227
+ compaction mechanism is an LLM-window property, not a harness bug — the lever is to bound how much
228
+ one session accumulates, not to fight the window.
229
+
230
+ **Guidance for multi-task chains:**
231
+
232
+ 1. **Prefer one `/sp:dev-run <wbs>` per session.** Each invocation starts a fresh context window,
233
+ so a chain of independent tasks naturally bounds compaction. This is the v1, lowest-blast-radius
234
+ change — split the chain by invoking each task separately.
235
+ 2. **If `--next` chaining must stay in-session**, accept at most one compaction per long session
236
+ and emit a **compact per-task handoff** — a short `local://`-style note carrying only the
237
+ next task's goal + the completed task's done-set (not its full transcript) — so the session does
238
+ not re-accumulate the finished task's context.
239
+ 3. **Do not re-run full verification for already-done tasks** in a chain (see
240
+ [targeted-test-first](#targeted-test-first-verification-loop)). Re-running the full suite per
241
+ task is the other dominant session-cost driver.
242
+
243
+ **Target:** a three-task chain completes with **≤1 compaction** instead of 4. This is operator
244
+ guidance in the reference, not a codified hook — auto-splitting `--next` is a possible follow-up
245
+ but loses in-session continuity for later gates, so it is deliberately not done here.
246
+
247
+ ## Section-editing workflow
248
+
249
+ The dominant agent write pattern (hot path 2):
250
+
251
+ 1. Generate the new section content to a temp file.
252
+ 2. `spur task update <wbs> --section <name> --from-file <temp>` — the CLI writes it.
253
+ 3. Remove the temp file.
254
+
255
+ This is the only sanctioned path for LLM-generated content to enter the corpus. The CLI
256
+ validates the section against the status-section matrix before writing.
257
+
258
+ **Body-only format** (avoids the corruption class fixed in task 0115):
259
+
260
+ - **Body-only:** the temp file is the section *body* only — no `## SectionName` heading line.
261
+ The CLI adds the canonical heading (`### SectionName` for tasks). If the temp file starts with
262
+ a heading matching the section name the CLI strips it, but write body-only from the start.
263
+ - **No same-level sub-headings:** never use `###` sub-headings inside a task section body (e.g.
264
+ `### AC1 — …`). They sit at the canonical section level and would become phantom sections on
265
+ re-parse; the CLI now strips them with a stderr warning, but write clean. Use bullet lists,
266
+ tables, or `**bold**` labels for sub-structure instead.
267
+ - **Never suppress stderr:** run `spur task update` without `2>/dev/null`. Stderr carries the
268
+ diagnostic (including the strip warnings above); suppressing it turns a fixable error into a
269
+ silent exit-1 that wastes a round-trip.
270
+
271
+ ## The section-status matrix
272
+
273
+ `spur task check <wbs> --json` returns the required and optional sections for the task's
274
+ current status. Agents ask "what does this task need now?" with zero tokens by reading the
275
+ `--json` output — no need to load and parse the matrix YAML.
276
+
277
+ ## Check before write
278
+
279
+ Before editing any task file, run `spur task check <wbs>` to see what sections exist, what
280
+ is missing, and what format rules apply. The check is the single validation surface:
281
+ frontmatter schema, section-status matrix, section format rules, feature traceability.
282
+
283
+ After writing a section, run `spur task check <wbs>` again to confirm the write introduced no
284
+ structural issues (phantom sections, matrix violations) before moving on.
285
+
286
+ ## What belongs in a task file
287
+
288
+ **A task file is work to be done, not a question to be answered.** Every surface that creates tasks
289
+ is bound by this — decomposition, wayfinder, issue-finding, brainstorm exits, review findings,
290
+ dogfood follow-ups.
291
+
292
+ The test is one question: **can an implementer execute this to completion without the operator in the
293
+ loop?**
294
+
295
+ - **Yes → it is a task.** It has a definite outcome, and `### Requirements` states observable results
296
+ that `spur task check` and verify can be judged against. Writing code, extending tests, running a
297
+ measurement, producing a documented inventory, migrating data — all tasks, whether or not they ship
298
+ production code.
299
+ - **No, it needs the operator's judgment → it is not a task.** "Decide X", "choose between A and B",
300
+ "what should the contract be" are decision briefs. They are resolved in conversation with the
301
+ operator, and the *answer* is recorded where the decision belongs — the feature body, an ADR
302
+ (`docs/00_ADR.md`), or the design doc. A task may then be created for the work the answer implies.
303
+
304
+ **Why this is a rule and not a preference.** A decision filed as a task sits in `spur task list` and
305
+ in a feature's Tasks table looking like queued work. It gets handed to an implementing agent, which
306
+ either stalls or invents the decision and calls it done. It also inflates task counts, which is how
307
+ an over-decomposed batch hides. The corpus is a work queue; a question in it is a queue defect.
308
+
309
+ **Open questions do not live in task files either.** `### Q&A` records decisions that are *closed* —
310
+ "we chose X because Y", "deferred with reason Z". If a task's `### Q&A` or `### Design` still contains
311
+ an unanswered question at the point of handoff, the task is not ready: close the question with the
312
+ operator first, or state the assumption explicitly and proceed. An implementer must never have to
313
+ guess which of two designs was intended.
314
+
315
+ ## Task sizing: cohesion before hours
316
+
317
+ Applies to **every** surface that authors more than one task in a sitting — decomposition,
318
+ wayfinder charting, issue-finding, brainstorm exits, dogfood follow-ups, review findings. Ceremony
319
+ cost is **per task** (precheck, implement, test, review, approve, verify, record, done, plus a
320
+ verdict artifact), so an over-split batch pays that cost repeatedly for a diff the reviewer reads
321
+ once.
322
+
323
+ Before creating a set of tasks, apply the two dimensions in order:
324
+
325
+ 1. **Cohesion — is the split legitimate at all?** Candidates that would edit the same file surface,
326
+ or that must be read together to be judged, are **one task** — even when each would be a
327
+ respectable size alone. Merge them.
328
+ 2. **Hours — is the resulting cohesive task too large?** Only once cohesion permits the split do the
329
+ hour knobs bound it. Above `force_decompose_above_hours`, size overrides cohesion.
330
+
331
+ Sharpness is not sufficient justification for a separate task. A question can be sharp, need real
332
+ work, and still belong to a sibling's session.
333
+
334
+ Full treatment, the worked example, and the tunable knobs:
335
+ [`../../spec-decomposition/references/decomposition.md`](../../spec-decomposition/references/decomposition.md).
336
+
337
+ ## One writer per working tree (task 0487 R5/R6)
338
+
339
+ **One agent session writes a given working tree at a time.** Two sessions in the same tree do not
340
+ merge — they overwrite. Nothing detects it: the second writer's edit simply reappears after the
341
+ first reverts it, and the symptom reads as a model regression. During the 0486 drive a background
342
+ Codex session (PID 4087) re-applied a reverted change three times before a live-process check found
343
+ it, costing ~10 minutes of misdiagnosis.
344
+
345
+ - **Parallel agent work uses git worktree isolation** — one branch and one tree per agent, merged
346
+ back through the WT-4 sequence above. Not two agents, one checkout.
347
+ - **Suspect a second writer** when an edit you just made is gone, or a reverted change returns.
348
+ Check for live agent processes before blaming the model.
349
+
350
+ **Commit per task.** Start each task on a tree clean of other tasks' implementations. A dirty tree
351
+ mixes two tasks' evidence into one diff — 0486's run launched on top of 0485's uncommitted work
352
+ across nine files, forcing a commit-0485-first detour mid-pipeline, and the mixed diff is what the
353
+ implement stage then conflated. The pipeline precheck prints a WARNING with the file list when the
354
+ tree has uncommitted non-corpus changes; treat it as a stop-and-commit, not noise. It warns rather
355
+ than blocks because a legitimately in-progress tree is the operator's call.
356
+
357
+ ## Iron Laws
358
+
359
+ Seven non-negotiable invariants for the spur-dev lifecycle. These are laws, not guidelines — a
360
+ violation is a defect in the run, not a style choice. Every competency skill and the spine consume
361
+ them; they live here because they cross every phase boundary.
362
+
363
+ 1. **NEVER skip the verification gate.** A task is not done until `spur task check <wbs> --strict-core`
364
+ returns PASS and every AC scenario has a corresponding verify command that exited 0. "I tested it
365
+ manually" is not verification evidence.
366
+ 2. **NEVER write to task/feature corpus outside the `spur` CLI.** Direct file edits to
367
+ `docs/tasks2/*.md` or `docs/features/*.md` are forbidden. The only exception is working memory
368
+ under `.spur/memory/`. Every other mutation goes through `spur task` / `spur feature` so the
369
+ schema, matrix, and traceability guards run.
370
+ 3. **NEVER mark a task done without a PASS verdict.** `testing → done` requires
371
+ `spur task check --strict-core` PASS and a recorded verdict. PARTIAL or FAIL verdicts leave the
372
+ task at `testing` and surface to the operator.
373
+ 4. **NEVER proceed past a failed gate without explicit operator approval.** A failed
374
+ `feature-check`, `batch-create`, `precheck`, `review`, or `verify` stops the run. The operator
375
+ decides whether to fix-forward, rework, or abort — the agent does not auto-retry past a failure.
376
+ 5. **NEVER suppress gate failures with `--no-verify`, `--force`, or new `biome-ignore` /
377
+ `eslint-disable` suppressions.** Suppression is a silent bypass. If a gate fails, fix the root
378
+ cause. A suppression added solely to silence a gate is a defect, not a fix.
379
+ 6. **NEVER create a standalone PM skill or command.** Product-management judgment lives in
380
+ `product-planning.md` as a lens applied during intake and decomposition. No `sp:product-management`
381
+ skill, no `/sp:prd-*` commands, no `sp:super-pm` agent — unless a later task proves a stable,
382
+ distinct routing value (ADR-022).
383
+ 7. **NEVER claim completion without fresh verification evidence.** "Tests pass" must be backed by
384
+ the actual `bun run test` tail pasted into the record. "Lint clean" must be backed by
385
+ `bun run lint` output. Stale evidence from a prior run is not evidence — re-run the gate and
386
+ paste the current output.
387
+
388
+ ## Verification Before Completion
389
+
390
+ A universal honesty gate that applies to **every** completion claim, not only the pipeline verdict:
391
+ **no "done / passing / fixed / works / ready" claim without fresh verification evidence** — the
392
+ command *and* its output, run **this turn**. Iron Law 7 states the invariant for the corpus record;
393
+ this section generalizes it to every claim an agent makes, in any skill, at any phase.
394
+
395
+ **The rule.** Before you write or say a task or step is complete, working, or fixed:
396
+
397
+ 1. Run the check that proves it (the test, the build, the lint, the actual command).
398
+ 2. Paste the command and its real output (or the relevant tail) into your report.
399
+ 3. Only then make the claim — and phrase it against the pasted evidence, not against your expectation.
400
+
401
+ "I ran it earlier" is stale. "It should pass" is a prediction, not a result. A subagent's "success"
402
+ line is a claim to re-verify, not evidence to forward. Re-run and paste.
403
+
404
+ **Red Flags — an unverified claim is usually hiding behind one of these:**
405
+
406
+ | Red flag | What it usually means |
407
+ |---|---|
408
+ | "This should work" / "this will pass" / "probably fine" | You are predicting, not reporting. Run it and paste the result. |
409
+ | Expressing satisfaction ("great, that's done!") before any check ran | Relief is not evidence — the check has not been run this turn. |
410
+ | Forwarding a subagent's "success" without re-running its gate | You are trusting a claim, not verifying it. Re-run the check yourself. |
411
+ | "Tests pass" with no pasted command + output | Unbacked. Stale or imagined green is the default failure mode. |
412
+ | Marking done while any check was skipped, `.skip`'d, or commented out | A skipped check is an unknown, and "done with unknowns" is not done (fail loud). |
413
+ | "I fixed it" from a single non-reproduced success | One lucky run is not a fix. Reproduce, fix, then re-verify. |
414
+
415
+ This rule is behavioral, not CLI-enforced — the competency skills carry it into their own steps: the
416
+ verify step (`sp:code-verification`) enforces it hardest, and the implement (`sp:code-implementation`)
417
+ and test (`sp:code-testing`) steps apply it before claiming their work complete.
418
+
419
+ ### Targeted-test-first verification loop
420
+
421
+ The verification loop must run the **narrow** test before any full-suite gate, so iterating on a
422
+ failing test does not re-run the entire workspace on every attempt. This is the single biggest
423
+ verification-loop cost driver (task 0436 forensics: 12 `bun test` + 4 full `spur-check` runs while
424
+ iterating one task).
425
+
426
+ **The rule.** When a test fails and you are iterating to green:
427
+
428
+ 1. Run the narrow target first: `bun test <file> --test-name-pattern <test>`.
429
+ 2. Loop on that narrow target until green.
430
+ 3. **Then** run the single full `spur-check` (or `bun run check`) as the final gate.
431
+
432
+ Do not re-run the full suite per iteration, and do not `spur-check` before you have a green narrow
433
+ target. **Target:** full `spur-check` runs ≤2 per task (one during iteration, one final) instead of
434
+ 4 across a chain.
435
+
436
+ ## Auto-Decision Principles
437
+
438
+ Seven principles governing `--auto` mode. `--auto` sets `profile=auto` in the workflow vars; the
439
+ principles determine which gates route around HITL and which still pause.
440
+
441
+ 1. **Schema-valid → auto-approve.** If the input passes local schema validation
442
+ (`task-batch.schema.json`, BDD validator, frontmatter schema), the gate is entered without
443
+ pausing. The schema is the contract; schema-valid means structurally sound.
444
+ 2. **Gate-passed → auto-continue.** If `spur task check`, `spur feature check`, or
445
+ `spur workflow validate` exits 0, the run continues to the next state without surfacing.
446
+ 3. **Tests-green → auto-continue.** If `bun run lint` and `bun run test` exit 0, the verify step
447
+ continues. A red test suite is a hard stop, not an auto-retry.
448
+ 4. **Verdict-PASS → auto-continue.** If the verify step produces a PASS verdict, the run advances
449
+ to `record` and `done`. PARTIAL or FAIL verdicts surface to the operator regardless of `--auto`.
450
+ 5. **Taste-decision → surface to human.** Architecture approval, naming, UX shape, and
451
+ "is this the right abstraction" decisions are taste gates. `--auto` does not auto-resolve them.
452
+ 6. **Irreversible action → surface to human.** Branch deletion, force-push, schema migration,
453
+ `spur feature update <id> cancelled`, and any `--merge` / `--force` action pauses regardless of
454
+ `--auto`. Irreversible is irreversible.
455
+
456
+ **Exception — the worktree batch success path (`execution-batch.md` § WT-4).** The
457
+ `--worktree --auto` full-batch success sequence — `git merge --ff-only "$BRANCH"`, `git worktree
458
+ remove`, `git branch -d "$BRANCH"` — does **not** pause, even though it performs a merge and a
459
+ branch deletion. This is the single carve-out from Principle #6, and it is safe by construction:
460
+ `git merge --ff-only` refuses rather than rewriting history when the base ref has moved, and
461
+ `git branch -d` (lowercase) refuses to delete a branch that is not fully merged. Both fail closed,
462
+ so no work can be lost — the property #6 exists to protect. When FF is impossible, WT-4 falls
463
+ through to the WT-5 retention path, which leaves the worktree and branch intact. Every other
464
+ branch-deletion, `--merge` / `--force`, force-push, and schema-migration action continues to
465
+ pause regardless of `--auto`.
466
+ 7. **Error → stop.** Any unexpected error (CLI crash, schema parse failure, missing file) stops the
467
+ run. `--auto` is not a license to power through errors; it is a license to skip *objective* HITL
468
+ pauses, not to ignore failures.
469
+
470
+ ### The `--auto` routing contract
471
+
472
+ `--auto` sets `profile=auto`. The workflow YAML transitions must **route around** an auto-resolvable
473
+ HITL state **before entry** — the workflow engine does NOT auto-dismiss `hitl.confirm` states. This
474
+ is the critical contract: `--auto` is not "auto-click yes on every gate"; it is "use the transition
475
+ graph to skip gates whose objective preconditions are already met."
476
+
477
+ Concretely: an `idea-pipeline.yaml` with `profile=auto` transitions from `feature-check` directly
478
+ to `decompose` when the feature-check exits 0, never entering a `hitl.confirm` state for
479
+ `feature-check`. But `design-approval` (a taste gate) still enters `hitl.confirm` and pauses,
480
+ because there is no objective precondition that can route around it.
481
+
482
+ **Without `--auto`** (the default), all gates surface to the human — including objective gates.
483
+ The operator approves every state transition interactively. This is the safe default; `--auto` is
484
+ opt-in for trusted, low-risk runs.
485
+
486
+ ## Pipeline Alignment
487
+
488
+ The system has multiple pipelines, each owning exactly one lifecycle phase. This section documents
489
+ the phase-ownership model, the no-nesting principle, and lifecycle guard respect — the structural
490
+ invariants that keep the pipeline set coherent as new ones are added.
491
+
492
+ ### Pipeline phase table
493
+
494
+ | Pipeline | Lifecycle phase | Entry point | Terminal states |
495
+ |---|---|---|---|
496
+ | `idea-pipeline.yaml` | Ideation (vague idea → feature + AC + task batch) | `/sp:dev-idea` | `handoff`, `cancelled` |
497
+ | `planning-pipeline.yaml` | Design (known slug/task → design handoff) | `/sp:dev-plan` | `handoff`, `cancelled` |
498
+ | `task-pipeline.yaml` | Execution (one task → done) | `/sp:dev-run` | `done`, `failed` |
499
+ | `wrapup-pipeline.yaml` | Wrap-up (completed tasks → learning + metrics + doc-sync) | `/sp:dev-wrap`, `/sp:dev-wrapall` | `done`, `skipped` |
500
+ | `feature-dev.yaml` | Umbrella (brainstorm → plan → execute → feature-verify) | `/sp:dev-runall --feature <id>` (or `--tasks feature:<id>`) | `done`, `failed` |
501
+ | `basic.yaml` | Simple (generic implement/check/fix loop) | direct `spur workflow run` | `done`, `failed` |
502
+ | `feature-lifecycle.yaml` | Feature status FSM (entity lifecycle, not a phase pipeline) | `spur feature update` | `done`, `cancelled` |
503
+ | `task-lifecycle.yaml` | Task status FSM (entity lifecycle, not a phase pipeline) | `spur task update` | `done`, `cancelled` |
504
+
505
+ The two `*-lifecycle.yaml` workflows are entity FSMs, not phase pipelines. They guard persistent
506
+ entity state transitions; phase pipelines orchestrate work and may invoke lifecycle verbs but do
507
+ not replace them.
508
+
509
+ ### No-nesting principle
510
+
511
+ A pipeline may invoke another workflow through a command wrapper or `spur workflow run` **only at a
512
+ phase boundary** — it must NOT inline another pipeline's state graph. Concretely:
513
+
514
+ - `feature-dev.yaml`'s `execute-tasks` state may invoke `task-pipeline.yaml` per task via
515
+ `spur workflow run` (phase boundary: design → execution).
516
+ - `idea-pipeline.yaml`'s `handoff` state may output a command for the operator to run
517
+ `task-pipeline.yaml` (phase boundary: ideation → execution).
518
+ - `task-pipeline.yaml`'s `implement` state must NOT contain a nested state machine for
519
+ `code-implementation` — it dispatches the competency skill via `agent.run`, not by inlining
520
+ another workflow's states.
521
+
522
+ Nesting state graphs couples pipelines at the implementation level, making the set unmaintainable
523
+ and breaking the "orchestration is configuration" principle (ADR-022). The no-nesting rule is the
524
+ structural invariant validated by Phase 3's `idea-pipeline.yaml` design.
525
+
526
+ ### Lifecycle guard respect
527
+
528
+ New pipelines respect existing lifecycle guards — no new `*-lifecycle.yaml` workflows. Persistent
529
+ entity lifecycle legality remains in `feature-lifecycle.yaml` and `task-lifecycle.yaml`. New
530
+ pipelines advance entity status only through `spur` CLI verbs, which run the lifecycle guards:
531
+
532
+ - `task-pipeline.yaml` transitions a task `wip → testing → done` via `spur task update <wbs> <status>`
533
+ (without `--no-lifecycle`), so `task-lifecycle.yaml` guards run.
534
+ - `wrapup-pipeline.yaml` does NOT mutate task status — it consumes completed tasks. If it advances
535
+ a feature, it does so via `spur feature update <id> <status>`, running `feature-lifecycle.yaml`
536
+ guards.
537
+ - `idea-pipeline.yaml` creates features and tasks via `spur feature create` and
538
+ `spur task batch-create`, which run the lifecycle creation guards.
539
+
540
+ A new pipeline that needs to mutate entity status must do so through the CLI verb, never by
541
+ writing the file directly. This is the seam between phase orchestration (pipelines) and entity
542
+ legality (lifecycle FSMs).
543
+
544
+ ## Learning Log Convention
545
+
546
+ Working learnings are captured in `.spur/memory/learnings.md` — a markdown scratchpad, NOT a
547
+ CLI-gated corpus artifact. The `wrapup-pipeline.yaml` `learning-capture` step writes to it.
548
+
549
+ **Format:**
550
+
551
+ ```markdown
552
+ ## <YYYY-MM-DD> — Task <WBS>
553
+
554
+ - **Convention discovered:** <what the agent learned about the project>
555
+ - **Error hit and resolved:** <what went wrong, how it was fixed>
556
+ - **Pattern that worked:** <approach worth repeating>
557
+ - **Gotcha:** <what to watch for in future tasks>
558
+ ```
559
+
560
+ **Rules:**
561
+
562
+ - **Not CLI-gated.** The file is written directly by the wrap-up pipeline's `learning-capture`
563
+ agent.run step. It does not go through `spur task update` or `spur feature update`.
564
+ - **Not a validated corpus.** The file is a working scratchpad. High-value learnings are promoted
565
+ to `docs/99_PROJECT_CONSTITUTION.md §8` (lessons) by the `doc-sync` step (via `sp:doc-evolve`),
566
+ not by the learning-capture step itself.
567
+ - **Append-only within a session.** New entries are appended; existing entries are not rewritten.
568
+ - **Grouped by date and task.** Each entry has a date and task WBS header so the operator can
569
+ trace a learning back to its source task.
570
+ - **Operator-readable.** Markdown, not JSON. The operator can read and grep this file directly
571
+ without parsing.
572
+
573
+ ## Session Checkpoint Convention
574
+
575
+ Long-running pipelines write resumable checkpoints to `.spur/memory/sessions/` so an interrupted
576
+ run can be resumed. The convention is documented here; the actual checkpoint write/read actions
577
+ in pipeline YAMLs are added in Phase 4 (task 0171).
578
+
579
+ **Format:** Markdown file with YAML frontmatter:
580
+
581
+ ```yaml
582
+ ---
583
+ session_id: "2026-07-01-0167"
584
+ workflow: "task-pipeline"
585
+ run_id: "wf_..."
586
+ task_wbs: "0167"
587
+ feature_id: "I"
588
+ phase: "verify"
589
+ last_gate: "review-approved"
590
+ timestamp: "2026-07-01T18:30:00Z"
591
+ next_action: "run verification"
592
+ ---
593
+
594
+ ## Session Notes
595
+
596
+ <free-form markdown: what was done, what's pending, any blockers>
597
+ ```
598
+
599
+ **Write checkpoints after:**
600
+
601
+ - Every HITL gate decision (approved/rejected/deferred).
602
+ - Every phase transition in `planning-pipeline`, `task-pipeline`, `feature-dev`, `idea-pipeline`,
603
+ and `wrapup-pipeline`.
604
+ - Every terminal state (`done`, `failed`, `cancelled`, `skipped`).
605
+
606
+ **Read checkpoints when:**
607
+
608
+ - `/sp:dev-run --continue` or `/sp:dev-runall --continue` is used.
609
+ - The operator asks to resume a task or feature.
610
+ - A workflow run is paused and later continued (`spur workflow continue <run-id>`).
611
+
612
+ **Rules:**
613
+
614
+ - **Not CLI-gated.** Checkpoint files are written directly by the pipeline's checkpoint action
615
+ (a `shell` step that writes to `.spur/memory/sessions/<session-id>.md`). They do not go through
616
+ `spur task update`.
617
+ - **Not a validated corpus.** Checkpoints are working memory. They are overwritten when a session
618
+ resumes and re-checkpoints. They are NOT authoritative task state — the task file is.
619
+ - **One file per session.** The `session_id` is `<date>-<wbs-or-feature>`. A resumed session
620
+ overwrites the same file.
621
+ - **Operator-readable.** The YAML frontmatter is machine-parseable; the body is free-form markdown
622
+ for the operator to scan.
623
+
624
+ ## Design Approval Gate
625
+
626
+ The Design Approval Gate is the taste gate between system design and decomposition in the
627
+ `idea-pipeline.yaml`. It is a HARD gate — no downstream state proceeds without design approval.
628
+
629
+ **Two layers:**
630
+
631
+ 1. **Brainstorm design summary (always recorded).** The `discovery` state's `sp:brainstorm` dispatch
632
+ always records a design summary in the brainstorm artifact. This is the "nothing is too simple"
633
+ pattern (Phase 1, task 0168 R3) — even trivial ideas get a one-paragraph summary. The summary is
634
+ the contract between ideation and execution.
635
+
636
+ 2. **System design approval (taste gate, conditional).** When `system-design` runs (determined by
637
+ the `needs_design` signal), the `design-approval` state pauses for the operator to approve the
638
+ architecture. This is a taste gate, NOT an objective gate — `--auto` does NOT auto-approve it.
639
+
640
+ **Auto-mode behavior:**
641
+
642
+ - `--auto` routes around taste HITL states BEFORE entry only when the matching pre-clear vars are
643
+ true. CLI **`--approve-taste`** (idea + plan) sets `design_approved=true` and, on the idea path,
644
+ also `idea_approved=true`. Aliases: `--design-approved` / `--idea-approved` set one var each.
645
+ - Without explicit prior approval, `--auto` still pauses at idea-eval and design-approval — taste
646
+ gates are not auto-clicked (Auto-Decision Principle #5).
647
+ - The brainstorm design summary is ALWAYS recorded, regardless of `--auto` — `--auto` does not
648
+ bypass the "nothing is too simple" pattern.
649
+
650
+ **The `needs_design` signal routing:**
651
+
652
+ The signal is emitted by the `discovery` state's brainstorm dispatch and written to
653
+ `.spur/run/idea-needs-design.json`. The `feature-check` state's transition guards read it to
654
+ determine routing:
655
+
656
+ | `design` var | `needs_design` signal | Route |
657
+ |---|---|---|
658
+ | `skip` | (ignored) | `decompose` (skip system-design; brainstorm summary still recorded) |
659
+ | `auto` | `true` | `system-design` -> `design-approval` -> `decompose` |
660
+ | `auto` | `false` | `decompose` (skip system-design) |
661
+ | `auto` | (missing) | `system-design` (ties lean design) |
662
+
663
+ There is no `design=force` / `--design` path. See [brainstorm/SKILL.md](../../brainstorm/SKILL.md) §
664
+ "Design Approval Gate" for the brainstorm-side contract (6 patterns + `needs_design` criteria).