@gobing-ai/spur 0.3.41 → 0.3.43

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