@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.
- package/.claude-plugin/marketplace.json +15 -0
- package/README.md +15 -1
- package/config/templates/AGENTS.md +5 -3
- package/config/workflows/task-pipeline.yaml +103 -12
- package/package.json +15 -12
- package/plugins/README.md +655 -0
- package/plugins/sp/README.md +621 -0
- package/plugins/sp/agents/expert-spur.md +109 -0
- package/plugins/sp/agents/super-coder.md +126 -0
- package/plugins/sp/agents/super-planner.md +283 -0
- package/plugins/sp/agents/super-reviewer.md +154 -0
- package/plugins/sp/commands/dev-arch.md +30 -0
- package/plugins/sp/commands/dev-brainstorm.md +40 -0
- package/plugins/sp/commands/dev-changelog.md +28 -0
- package/plugins/sp/commands/dev-daily.md +29 -0
- package/plugins/sp/commands/dev-debug.md +29 -0
- package/plugins/sp/commands/dev-dogfood.md +33 -0
- package/plugins/sp/commands/dev-featurechange.md +130 -0
- package/plugins/sp/commands/dev-find-conflict.md +51 -0
- package/plugins/sp/commands/dev-find-issue.md +76 -0
- package/plugins/sp/commands/dev-find-next.md +60 -0
- package/plugins/sp/commands/dev-fixall.md +33 -0
- package/plugins/sp/commands/dev-gitmsg.md +28 -0
- package/plugins/sp/commands/dev-gtd.md +97 -0
- package/plugins/sp/commands/dev-handover.md +26 -0
- package/plugins/sp/commands/dev-idea.md +50 -0
- package/plugins/sp/commands/dev-next.md +31 -0
- package/plugins/sp/commands/dev-parallel.md +30 -0
- package/plugins/sp/commands/dev-plan.md +46 -0
- package/plugins/sp/commands/dev-refine.md +48 -0
- package/plugins/sp/commands/dev-refineall.md +65 -0
- package/plugins/sp/commands/dev-refresh.md +32 -0
- package/plugins/sp/commands/dev-reverse.md +32 -0
- package/plugins/sp/commands/dev-review.md +31 -0
- package/plugins/sp/commands/dev-run.md +63 -0
- package/plugins/sp/commands/dev-runall.md +80 -0
- package/plugins/sp/commands/dev-simplify.md +39 -0
- package/plugins/sp/commands/dev-unit.md +29 -0
- package/plugins/sp/commands/dev-verify.md +48 -0
- package/plugins/sp/commands/dev-verifyall.md +72 -0
- package/plugins/sp/commands/dev-wrap.md +30 -0
- package/plugins/sp/commands/dev-wrapall.md +33 -0
- package/plugins/sp/commands/rule-add.md +18 -0
- package/plugins/sp/commands/rule-refine.md +18 -0
- package/plugins/sp/commands/rule-scan.md +18 -0
- package/plugins/sp/commands/spur-init.md +22 -0
- package/plugins/sp/commands/workflow-add.md +18 -0
- package/plugins/sp/commands/workflow-refine.md +18 -0
- package/plugins/sp/hooks/agent-hint.ts +60 -0
- package/plugins/sp/hooks/careful-guard.ts +147 -0
- package/plugins/sp/hooks/context-post-tool.ts +325 -0
- package/plugins/sp/hooks/context-session-start.ts +182 -0
- package/plugins/sp/hooks/context-session-stop.ts +95 -0
- package/plugins/sp/hooks/hooks.json +51 -0
- package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
- package/plugins/sp/hooks/task-write-guard.ts +84 -0
- package/plugins/sp/plugin.json +8 -0
- package/plugins/sp/scripts/batch-preflight.ts +204 -0
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
- package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
- package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
- package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
- package/plugins/sp/scripts/task-size-precheck.ts +202 -0
- package/plugins/sp/scripts/validate-commands.ts +651 -0
- package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
- package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
- package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
- package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
- package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
- package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
- package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
- package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
- package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +176 -0
- package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
- package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
- package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
- package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
- package/plugins/sp/skills/code-review/SKILL.md +112 -0
- package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
- package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
- package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
- package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
- package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
- package/plugins/sp/skills/code-testing/SKILL.md +108 -0
- package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
- package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
- package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
- package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
- package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
- package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
- package/plugins/sp/skills/code-verification/SKILL.md +535 -0
- package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
- package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
- package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
- package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
- package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
- package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
- package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
- package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
- package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
- package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
- package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
- package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
- package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
- package/plugins/sp/skills/functional-review/SKILL.md +364 -0
- package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
- package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +424 -0
- package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
- package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
- package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
- package/plugins/sp/skills/issue-finding/references/session-formats.md +121 -0
- package/plugins/sp/skills/next-feature/SKILL.md +125 -0
- package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
- package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
- package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
- package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
- package/plugins/sp/skills/next-router/SKILL.md +181 -0
- package/plugins/sp/skills/next-router/references/messages.md +90 -0
- package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
- package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +100 -0
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
- package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
- package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
- package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
- package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
- package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
- package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
- package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
- package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
- package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
- package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
- package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
- package/plugins/sp/skills/spur-cli/references/features.md +234 -0
- package/plugins/sp/skills/spur-cli/references/init.md +119 -0
- package/plugins/sp/skills/spur-cli/references/message.md +98 -0
- package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
- package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
- package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
- package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
- package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
- package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
- package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +278 -0
- package/plugins/sp/skills/spur-cli/references/team.md +133 -0
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
- package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
- package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +664 -0
- package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +727 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +350 -0
- package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
- package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +88 -0
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
- package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
- package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
- package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
- package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
- package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
- package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
- package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
- package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
- 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).
|