@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,129 @@
1
+ ---
2
+ name: validation-and-extension
3
+ description: Validate workflow definitions and extend the engine — validate semantics, custom action and guard runners, the trust-gated extension loader, and CLI-vs-library capability gaps.
4
+ see_also:
5
+ - spur-cli
6
+ - operations
7
+ ---
8
+
9
+ # Validation & Extension
10
+
11
+ Two concerns: trusting a definition (`validate`) and growing the engine's vocabulary (custom
12
+ actions/guards and extension modules).
13
+
14
+ ## Validation
15
+
16
+ `spur workflow validate <file> [--no-schema] --json` runs two layers:
17
+
18
+ 1. **Structural schema** — the state-machine or transition-flow JSON schema. Catches missing required
19
+ keys, wrong types, an unquoted `$schema`, or flow intent (`nodes`/`edges`) parsed against the
20
+ state-machine schema because `kind: transition-flow` was omitted.
21
+ 2. **Semantic invariants** — beyond what the schema can express: every `transition`/`edge` `from`/`to`
22
+ references a declared state/node; terminal states/nodes are reachable; `${vars.x}` has a matching
23
+ `vars` entry; `${env.X}` is listed in `env.allow`.
24
+
25
+ `--no-schema` skips only the `$schema` ref resolution (useful offline or for inline definitions),
26
+ keeping the structural + semantic checks. Classify a failure before fixing:
27
+
28
+ | Symptom | Layer | Typical cause | Fix |
29
+ | ------- | ----- | ------------- | --- |
30
+ | `parse error` near `$schema` | schema | unquoted `@`-leading value | quote the `$schema` string |
31
+ | validates as state-machine but you wrote nodes/edges | schema | missing `kind: transition-flow` | set `kind` explicitly |
32
+ | `unknown state/node` | semantic | a transition/edge target doesn't exist | fix the `to`/`from` id |
33
+ | terminal unreachable | semantic | no path to a `terminalStates`/`terminalNodes` entry | add the missing transition/edge |
34
+ | `${env.X}` empty at runtime | semantic-ish | `X` not in `env.allow` | add it to `env.allow` |
35
+
36
+ The error classes the library throws map to these: `WorkflowValidationError` (schema/semantic/template),
37
+ `FSMError` (runtime driver — missing state/node, invalid target), `RunCollisionError` (duplicate
38
+ `runId`). Definition errors throw; *run* failures (a failing action/guard) come back as
39
+ `status: 'failed'` and do not throw.
40
+
41
+ ## Custom actions and guards
42
+
43
+ When the built-ins (`note`, `shell`, `always`, `action-ok`) are not enough, register domain runners on
44
+ the host. An action's `kind` string is how a workflow references it.
45
+
46
+ ```ts
47
+ import { WorkflowEngineHost } from '@gobing-ai/ts-dual-workflow-engine';
48
+
49
+ const host = new WorkflowEngineHost();
50
+
51
+ // Custom action — receives resolved options + run context, returns an ActionResult
52
+ host.registerAction({
53
+ kind: 'send-email',
54
+ async execute(options, context) {
55
+ await mailer.send(String(options.to), String(options.subject));
56
+ return { ok: true }; // { ok: false, error } fails the action; { ok: true, terminal: true } ends the run
57
+ },
58
+ });
59
+
60
+ // Custom guard — returns a boolean
61
+ host.registerGuard({
62
+ kind: 'isBusinessHours',
63
+ async evaluate() {
64
+ const hour = new Date().getHours();
65
+ return hour >= 9 && hour < 17;
66
+ },
67
+ });
68
+ ```
69
+
70
+ Once registered, any definition can use `kind: send-email` (in `onEnter`/`onExit`/`node.action`) or
71
+ `kind: isBusinessHours` (in a `guard`/`condition`). The host tracks each registration's origin
72
+ (`builtin` / `extension` / `core`) — query with `host.actionOrigin(kind)` / `host.guardOrigin(kind)`.
73
+
74
+ > Inline `registerAction`/`registerGuard` is **not** gated — it is in-process code the caller already
75
+ > controls. Only the *module loader* (next section) is trust-gated.
76
+
77
+ ## Extension loading (trust-gated)
78
+
79
+ For modules that bundle multiple actions/guards, use `loadWorkflowExtensionsIntoHost`. The trust gate
80
+ is **fail-closed**: `allowExtensions` defaults to `false`, and a declared-but-not-allowed extension
81
+ **throws before any import** — never silently dropped.
82
+
83
+ ```ts
84
+ import { loadWorkflowExtensionsIntoHost, WorkflowEngineHost } from '@gobing-ai/ts-dual-workflow-engine';
85
+
86
+ const host = new WorkflowEngineHost();
87
+
88
+ await loadWorkflowExtensionsIntoHost(
89
+ host,
90
+ [{ kind: 'actions', absPath: '/abs/path/to/extension.ts', sourceName: 'my-config' }],
91
+ {
92
+ allowExtensions: true, // required — disabled by default
93
+ moduleLoader: (absPath) => import(absPath), // caller owns loading; tests use a stub
94
+ logger: { warn: (msg) => console.warn(msg) },// optional override warnings
95
+ },
96
+ );
97
+ ```
98
+
99
+ An extension module default-exports `{ name, actions?: [...], guards?: [...] }`. A ref with
100
+ `kind: 'actions'` registers only the module's `actions[]` (guards in the same module are ignored, and
101
+ vice versa). Security properties:
102
+
103
+ - `allowExtensions` is fail-closed — refs present without the flag throw before import.
104
+ - Extension paths are validated; `..` traversal is rejected.
105
+ - The caller supplies `moduleLoader`; the loader has no ambient code-loading capability of its own.
106
+
107
+ **Extensions execute arbitrary code.** Treat an extension path like a dependency: only load modules you
108
+ trust, and never enable `allowExtensions` for paths derived from untrusted input.
109
+
110
+ ## CLI vs. library capability gaps
111
+
112
+ The `spur workflow` CLI surfaces the lifecycle verbs (`validate`, `run`, `list`, `trace`, `continue`,
113
+ `cancel`, `clean`) over the default-host engine. Several engine capabilities are **library-only** —
114
+ reach for the library (`@gobing-ai/ts-dual-workflow-engine`) directly when you need them:
115
+
116
+ | Capability | CLI | Library |
117
+ | ---------- | --- | ------- |
118
+ | Validate / run / list definitions | ✅ | ✅ |
119
+ | Trace run history / continue HITL / cancel / clean orphans | ✅ | ✅ |
120
+ | Custom action/guard runners | ✅ (built-ins only) | ✅ (`registerAction`/`registerGuard`) |
121
+ | Extension modules | — | ✅ (`loadWorkflowExtensionsIntoHost`) |
122
+ | DB persistence + programmatic `listRuns()` | (via configured adapter + `trace`) | ✅ (`DbWorkflowPersistenceAdapter`) |
123
+ | Event-bus observability (progress bars, dashboards) | partial (CLI step reporter on sync human runs) | ✅ (`WorkflowEngineEvents` via `WorkflowRunOptions.events`) |
124
+ | OTel traces / structured logs | (emitted) | ✅ (`RunLifecycle`) |
125
+ | Programmatic schema parsing | — | ✅ (`WorkflowDefSchema`, `validateWorkflowDef`) |
126
+
127
+ When a workflow needs a capability the CLI doesn't expose, that is a signal to build a small host-side
128
+ integration in the consuming app (registering the runner, wiring the adapter/event bus), not to
129
+ work around it in the YAML. Keep domain behavior in action/guard runners, not in workflow parsing.
@@ -0,0 +1,355 @@
1
+ ---
2
+ name: spur-cli-workflows
3
+ description: "spur-cli noun reference: operate `spur workflow` across its full lifecycle — choose the right execution mode, author state-machine and transition-flow workflows, validate definitions, run them, read run traces, and refine existing flows. Wraps the dual-mode FSM/transition-flow runtime (`@gobing-ai/ts-dual-workflow-engine`)."
4
+ see_also:
5
+ - spur-cli
6
+ ---
7
+
8
+ # spur workflow — the dual-mode workflow CLI
9
+
10
+ `spur workflow` runs declarative YAML workflows (powered by `@gobing-ai/ts-dual-workflow-engine`) that
11
+ orchestrate a multi-step process — an implement→check→fix loop, an import→validate→transform→write
12
+ pipeline, an approval gate. The engine executes **two distinct workflow kinds**, and the first act of
13
+ any new workflow is choosing between them. Get the mode right and the rest of authoring follows the
14
+ schema; get it wrong and you fight the engine.
15
+
16
+ Operating a workflow well is a full lifecycle — choose the mode, author the YAML, validate it, run it,
17
+ read the trace, and refine. This skill covers all of it.
18
+
19
+ ## Choose the execution mode first
20
+
21
+ This is the defining decision and has no analogue in `spur rule`. **Every new workflow starts here.**
22
+ The engine runs two kinds; they use different schemas, different keys, and a different mental model.
23
+ Switching kinds later is a rewrite, not an edit — so decide deliberately and, in `add`, confirm.
24
+
25
+ ```
26
+ Is the run defined by ONE "current state" that picks its next state by evaluating
27
+ ordered guards, and may loop back on itself (e.g. implement → check → fix → check …)?
28
+ │ yes │ no
29
+ ▼ ▼
30
+ state-machine Does the run advance through a DAG of nodes,
31
+ (initialState / states[] each node carrying an action, following edges
32
+ with onEnter|onExit / forward — fan-out, gates, decisions — and
33
+ top-level transitions[] rarely looping (e.g. read → validate → write)?
34
+ with guard) │ yes
35
+
36
+ transition-flow
37
+ (initialNode / nodes[] typed
38
+ action|gate|parallel|decision with action /
39
+ edges[] with condition)
40
+ ```
41
+
42
+ **Discriminator table** (lifted from the two JSON schemas — authoritative, not heuristic):
43
+
44
+ | Question | → `state-machine` | → `transition-flow` |
45
+ | -------- | ----------------- | ------------------- |
46
+ | Mental model | One current state; guard-driven next-state | DAG of nodes advancing along edges |
47
+ | Where actions live | On states: `onEnter` / `onExit` | On nodes: `node.action` |
48
+ | Branching | Ordered `transitions[]` + `guard` (first pass wins) | `edges[]` + `condition` (first pass wins); unconditional edges allowed |
49
+ | Loops / retries | **Natural** — a transition points back to a prior state | Possible but DAG-oriented; loops are awkward |
50
+ | Node typing | none (states are untyped) | `type: action\|gate\|parallel\|decision` |
51
+ | Required keys | `name, initialState, states, transitions` | `kind, name, initialNode, nodes, edges` |
52
+ | `kind` field | optional (defaults to state-machine) | **required** — `kind: transition-flow` |
53
+ | Canonical example | implement→check→fix loop (`.spur/workflows/basic.yaml` — soft status-file probe + bounded fixall) | read→validate→transform→write pipeline |
54
+
55
+ **Heuristic:** loops / retries / one-active-state → **state-machine**; pipeline / fan-out / action-per-node → **transition-flow**.
56
+
57
+ When intent is ambiguous, default to **state-machine** (the simpler, default kind) and say so — but
58
+ in `add`, surface the recommendation **with its reason and the rejected alternative**, and confirm
59
+ before authoring. Full procedure: [workflows/authoring-workflows.md](workflows/authoring-workflows.md).
60
+
61
+ ## When to use
62
+
63
+ Use this skill to:
64
+
65
+ - **Author a workflow** — turn a described process into a validated, dry-run-verified YAML definition
66
+ in the right mode. → authoring-workflows.md
67
+ - **Validate before trusting** — schema + semantic-check a workflow file (references, terminal
68
+ reachability, template vars) before running it.
69
+ - **Run a workflow** — execute a definition and read its run trace (states/nodes entered, transitions
70
+ taken, terminal status).
71
+ - **Refine an existing workflow** — fix a stuck guard, add a state/node, retune `iterationBound`,
72
+ re-scope variables / `env.allow`, with the smallest change. → workflows/operations.md
73
+ - **Extend the engine** — register a custom action/guard runner or a trust-gated extension module when
74
+ the built-ins (`note`, `shell`, `always`, `action-ok`) fall short. → workflows/validation-and-extension.md
75
+
76
+ ## Operations
77
+
78
+ The skill's logic divides by **whether the LLM adds value**:
79
+
80
+ - **Direct CLI** (`validate`, `run`, `list`, `trace`, `continue`, `cancel`, `clean`) — deterministic,
81
+ single-verb commands. Run them straight. A slash-command wrapper would only forward flags and add
82
+ drift; **there is no command for these — use the CLI**. The skill still drives them in natural
83
+ language (interpreting a failed validate, reading a run trace).
84
+ - **Agent-driven** (`add`, `refine`) — convert fuzzy human intent into a reliable sequence the CLI
85
+ cannot express as one verb. `add` chooses the mode and authors a new workflow; `refine` tunes an
86
+ existing one. These are the operations worth a slash command, and the skill owns all their logic.
87
+ Full procedures: [workflows/operations.md](workflows/operations.md).
88
+
89
+ | Operation | Backed by | Input | Output (done-when) |
90
+ | --------- | --------- | ----- | ------------------ |
91
+ | `validate` | `spur workflow validate` (CLI) | `<file> [--no-schema]` | Schema + semantic verdict |
92
+ | `run` | `spur workflow run` (CLI) | `<file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer]` | Terminal state reached (sync) or run started (async); trace readable |
93
+ | `continue` | `spur workflow continue` (CLI) | `[run-id] [--yes] [--answer <yes\|no\|cancel>]` | Resume a paused HITL run (omit id -> most recent paused); `--answer` injects a gate answer before guard re-evaluation |
94
+ | `cancel` | `spur workflow cancel` (CLI) | `<run-id>` | Single non-terminal run marked failed (SIGTERM async worker when live) |
95
+ | `clean` | `spur workflow clean` (CLI) | `[--older-than <min>] [--force] [--logs] [--dry-run]` | Bulk-finalize stale `running`/`pending` runs as failed **and** reclaim retained run logs older than `workflow.logRetentionDays` (30d default) |
96
+ | `list` | `spur workflow list` (CLI) | — | Available workflow **YAML definition files** (not run records) |
97
+ | `trace` | `spur workflow trace` (CLI) | `[run-id] [--workflow <n>] [--status <s>] [--since <iso>] [--last <n>] [--follow] [--poll <ms>] [--output]` | Run history list or per-run timeline |
98
+ | `add` | agent procedure | `"<nl-description>" [--kind <state-machine\|transition-flow>] [--file <path>]` | **Mode chosen (confirmed)** → first reconciled against existing workflows (extend an existing flow rather than duplicate) → YAML authored in real schema shape → **validated AND dry-run** (reaches the expected terminal state) → [add](workflows/operations.md#add) |
99
+ | `refine` | agent procedure | `<workflow-file> [--intent "<goal>"] [--dry-run]` | Smallest change meeting the intent, re-validated and re-dry-run; `--dry-run` emits a diff only → [refine](workflows/operations.md#refine) |
100
+
101
+ `add` and `refine` are not CLI verbs. They compose `validate` + `run` around a generated/edited YAML
102
+ definition and both end in the same **validate-and-dry-run** core
103
+ ([operations.md](workflows/operations.md#sub-procedure-validate-and-dry-run)) so a tuned workflow is
104
+ verified exactly like an authored one. They also share the **find-existing-workflow** core
105
+ ([operations.md](workflows/operations.md#sub-procedure-find-existing-workflow)): `add` runs it up front
106
+ (don't duplicate an existing flow), `refine` runs it to locate the target. `add` additionally runs the
107
+ **mode-selection gate** before authoring — the one human-in-the-loop step unique to workflows.
108
+
109
+ ## The harness loop (choose → author → validate → dry-run → read trace)
110
+
111
+ ```
112
+ choose mode (decision tree above)
113
+
114
+
115
+ author YAML — real schema shape for that mode; quote $schema
116
+
117
+
118
+ spur workflow validate <file> --json ← schema + semantic gate
119
+
120
+ valid? ──no──▶ read errors → fix the definition → re-validate
121
+ │ yes
122
+
123
+ spur workflow run <file> --dry-run --run-id <throwaway> --json ← dry-run
124
+
125
+ status authoritative for pass/fail? ──no──▶ read trace,
126
+ (done = success; failed = failure) fix the offending
127
+ │ yes AND finalState === <expected> state/node/guard, re-run
128
+
129
+ trust the workflow
130
+ ```
131
+
132
+ **Reader contract (0425):** `status` alone is authoritative for pass/fail. A run that lands in a
133
+ declared `failureStates` terminal reports `status: 'failed'` (CLI exit non-zero) even when
134
+ `finalState` is a named terminal like `failed` or `cancelled`. Do **not** treat
135
+ `status === 'done' && finalState === 'failed'` as a success — that was the pre-0425 silent-success
136
+ hazard. Use `finalState` only to identify *which* terminal was reached after `status` has been
137
+ checked. Absent `failureStates`, every terminal still finalizes as `done` (backward compatible).
138
+
139
+ Two signals, two purposes: `validate` proves the definition is *well-formed and self-consistent*;
140
+ `run --dry-run` proves it *walks* — reaching the intended terminal state along the intended path
141
+ without executing side-effecting actions. A workflow you have not dry-run is a workflow you do not
142
+ trust. Always use `--json` when an agent consumes the result.
143
+
144
+ ### Step 1: Validate
145
+
146
+ ```bash
147
+ spur workflow validate ./workflows/approval.yaml --json
148
+ spur workflow validate ./workflows/import.yaml --no-schema --json # skip the $schema ref, keep semantic checks
149
+ ```
150
+
151
+ `validate` runs the structural Zod schema **and** semantic invariants (referenced states/nodes exist,
152
+ terminal states reachable, template vars resolve). A non-zero exit means **not well-formed** — fix the
153
+ definition, not the runner.
154
+
155
+ ### Step 2: Dry-run
156
+
157
+ ```bash
158
+ spur workflow run ./workflows/approval.yaml --dry-run --run-id dryrun-$(date +%s) --json
159
+ ```
160
+
161
+ Prefer **`--dry-run`** so actions are not executed. Use a throwaway `--run-id` so the dry-run does
162
+ not collide with a real run (duplicate ids raise `RunCollisionError`). Read **`status` first**
163
+ (authoritative for pass/fail), then `finalState` (which terminal). A failed run returns
164
+ `status: 'failed'` in the result — it does **not** throw; read the trace
165
+ (`spur workflow trace <run-id>`) to find the offending step.
166
+
167
+ ### Step 3: Read the trace and fix
168
+
169
+ Inspect which states/nodes were entered and which transitions/edges were taken. A run that stalls
170
+ short of the expected terminal state points at a guard/condition that never passed, a mistyped target,
171
+ or an `iterationBound` exhausted by a runaway loop. Fix the **specific** definition flaw — no drive-by
172
+ restructuring — then re-run. Loop until the run reaches the expected terminal state.
173
+
174
+ ### Run output and observability flags
175
+
176
+ The `run` verb has seven output/observability flags beyond the core `--dry-run`/`--async`/`--no-plan`.
177
+ The six human-output flags are ignored under `--json` (machine output stays byte-identical);
178
+ `--no-log` applies regardless of output mode (it controls the side-effect log file, not the stdout shape):
179
+
180
+ ```bash
181
+ spur workflow run ./workflows/approval.yaml --quiet # final summary only
182
+ spur workflow run ./workflows/approval.yaml --silent # errors only (non-zero exit on failure)
183
+ spur workflow run ./workflows/approval.yaml --verbose # transitions + correlation diagnostics
184
+ spur workflow run ./workflows/approval.yaml --detail minimal # tersest human output
185
+ spur workflow run ./workflows/approval.yaml --trace-file # persist redacted JSONL trace
186
+ spur workflow run ./workflows/approval.yaml --no-log # opt out of the consolidated .spur/run/<RUNID>.log
187
+ spur workflow run ./workflows/approval.yaml --steer # interactive steering on stdin
188
+ ```
189
+
190
+ - **`--quiet`**, **`--silent`**, **`--verbose`** are mutually constraining: `--quiet` and `--verbose`
191
+ are exclusive (exit `2`); `--silent` cannot combine with either (exit `2`).
192
+ - **`--detail <level>`** sets human verbosity: `minimal` (state changes only), `invocation` (default;
193
+ per-step headers), `full` (transitions + correlation). `--verbose` is shorthand for `--detail full`.
194
+ - **`--trace-file`** appends a redacted, schema-versioned JSONL trace under `.spur/runs/workflow/`
195
+ for post-run analysis - independent of human/JSON output.
196
+ - **`--no-log`** opts out of writing the consolidated all-in-one run log (`.spur/run/<RUNID>.log`).
197
+ By default the log is written **and retained** after the run ends; this flag skips it entirely
198
+ (propagates to the `--async` detached worker). No `--keep-log` / delete-by-default exists.
199
+ - **`--steer`** is synchronous and in-process: it cannot combine with `--json` or `--async` (exit `2`).
200
+ It accepts steering commands on stdin at declared action boundaries for interactive control.
201
+
202
+ ## Command surface
203
+
204
+ ```
205
+ spur workflow validate <file> [--no-schema] [--json]
206
+ spur workflow run <file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] [--quiet/--silent/--verbose] [--detail <level>] [--trace-file] [--no-log] [--steer] [--json]
207
+ spur workflow continue [run-id] [--yes] [--answer <yes|no|cancel>] [--json]
208
+ spur workflow cancel <run-id> [--json]
209
+ spur workflow clean [--older-than <minutes>] [--force] [--logs] [--dry-run] [--json]
210
+ spur workflow list [--json]
211
+ spur workflow trace [run-id] [--workflow <name>] [--status <s>] [--since <iso>] [--last <n>] [--follow] [--poll <ms>] [--output] [--json]
212
+ ```
213
+
214
+ | Flag (on `run`) | Effect |
215
+ | --------------- | ------ |
216
+ | `--vars <json>` | Per-run variable overrides (JSON object). Merged over the workflow's `vars`. Values must be strings. User vars win over injected defaults (`spurBin`). |
217
+ | `--dry-run` | Validate and walk transitions **without** executing actions. |
218
+ | `--async` | Start in the background and exit with `runId`; monitor via `spur workflow trace <run-id>`. |
219
+ | `--no-plan` | Suppress the human run-start plan preview (sync human runs only; ignored under `--json`/`--async`). |
220
+ | `--quiet` | Suppress plan and per-step progress; keep the final summary. |
221
+ | `--silent` | Suppress all routine output; errors still set a non-zero exit status. |
222
+ | `--verbose` | Include transitions and correlation diagnostics in human progress (implies `--detail full`). |
223
+ | `--detail <level>` | Human detail level: `minimal`, `invocation` (default), or `full`. |
224
+ | `--trace-file` | Append a redacted schema-versioned JSONL trace under `.spur/runs/workflow/`. |
225
+ | `--no-log` | Opt out of writing the consolidated `.spur/run/<RUNID>.log` (retained by default; propagates to `--async` workers). |
226
+ | `--steer` | Accept in-process steering commands on stdin at declared action boundaries (sync only; incompatible with `--json`/`--async`). |
227
+
228
+ `validate` and `run` exit non-zero on failure (`run` exits non-zero when the final status is not
229
+ `done`). `list` prints **workflow definition files** available on disk. For run history use `trace`:
230
+
231
+ ```bash
232
+ spur workflow list --json
233
+ spur workflow trace --last 10 --json
234
+ spur workflow trace <run-id> --json
235
+ ```
236
+
237
+ Follow a live run to terminal (human streaming mode):
238
+
239
+ ```bash
240
+ spur workflow trace <run-id> --follow # stream until terminal (default 1000ms poll)
241
+ spur workflow trace <run-id> --follow --poll 500 # poll every 500ms
242
+ spur workflow trace <run-id> --follow --output # stream .spur/run/<RUNID>.log instead of the DB timeline
243
+ ```
244
+
245
+ - **`--follow`** replays a run timeline and polls persisted state until it becomes terminal. It
246
+ requires a `run-id` (exit `2` without one) and cannot combine with `--json` (exit `2` - it is a
247
+ human streaming mode).
248
+ - **`--poll <ms>`** sets the follow polling interval (default `1000`, minimum `50`; exit `2` otherwise).
249
+ - **`--output`** swaps the follow source from the structured DB timeline to the consolidated all-in-one
250
+ log (`.spur/run/<RUNID>.log`, tail -f equivalent), streaming new lines as they land and exiting at
251
+ terminal status. It requires `--follow` and a `run-id`, is a human stream (rejects `--json`), and is
252
+ a **distinct source** — it never interleaves with the DB timeline. If the log never appears (e.g. the
253
+ run was started with `--no-log`), a clear message is printed at terminal status rather than hanging.
254
+ No `spur workflow monitor` verb exists; `--output` is the log-streaming surface.
255
+
256
+ HITL pause/resume: a run that hits a HITL action pauses; resume with `spur workflow continue [run-id]`
257
+ (`--yes` skips confirmation). A headless `hitl.confirm` persists a default `no` before pausing -
258
+ use `--answer yes|no|cancel` to inject the operator's gate answer before guard re-evaluation (0433).
259
+ `--answer` is distinct from `--yes`: `--yes` skips the CLI resume prompt, `--answer` sets the HITL
260
+ gate answer. Cancel one live/paused run with `cancel <run-id>`; bulk-finalize orphans stuck in
261
+ `running`/`pending` with `clean` (`--older-than` default 30 minutes, or `--force`).
262
+
263
+ **Schema resolution parity (0431):** `validate` and `run` both load the workflow through
264
+ `WorkflowAppService` with the same `embeddedSchemaOptions()` map the CLI injects for
265
+ `@gobing-ai/spur/schemas/...` refs. `run` pre-loads then calls the engine with the loaded def
266
+ (not bare `runFile` → node resolution). Schema errors under an embedded map never cite a
267
+ `node_modules` path. Prefer a project `agent.default` (or explicit `--vars '{"agent":…}'`) when
268
+ redirecting `agent.run` stages (ADR-047).
269
+
270
+ ### `clean` — housekeeping scopes (0429)
271
+
272
+ `spur workflow clean` is the housekeeping one-liner: it runs **both** scopes unless scoped by flag.
273
+
274
+ - **Stale-run finalization** (existing): bulk-finalizes orphaned `running`/`pending` runs as `failed`.
275
+ `--older-than <minutes>` (default 30) and `--force` (all non-terminal regardless of age) apply here only.
276
+ - **Run-log reclamation** (0429): removes retained `.spur/run/<RUNID>.log` files whose mtime is older
277
+ than `workflow.logRetentionDays` in `.spur/config.yaml` (default 30 days; integer days, not minutes).
278
+ Age is the only gate; best-effort deletes never abort the rest. Never touches
279
+ `.spur/runs/workflow/<RUNID>.jsonl` or `*-partial.md`.
280
+ - **`--logs`** scopes to log reclamation only (skips stale-run finalization). `--dry-run` applies to
281
+ both scopes (lists what would be removed, writes nothing). `--json` returns
282
+ `{ olderThanMinutes, dryRun, cleaned, logs: { retentionDays, dryRun, reclaimed, failures } }` (with
283
+ `--logs`, the reclamation object alone).
284
+ ## Behavior
285
+
286
+ This skill behaves as an **author** (choose mode → write a correct definition → prove it runs) feeding
287
+ a **pipeline** (validate → dry-run → read trace → refine). It also covers tuning existing workflows and
288
+ extending the engine with custom actions/guards. It does not execute the orchestrated *work* itself —
289
+ the workflow's actions (`shell`, custom runners) do that; this skill builds and operates the workflow.
290
+
291
+ ## Gotchas
292
+
293
+ 1. **`kind` is required for transition-flow, optional for state-machine.** A missing `kind` silently
294
+ parses as state-machine. If you authored flow intent (`nodes`/`edges`) without `kind: transition-flow`,
295
+ validation fails confusingly against the wrong schema. Always set `kind` explicitly for flows.
296
+ 2. **`$schema` must be quoted** — it starts with `@`, which YAML reserves. Unquoted is a parse error.
297
+ (Same trap as `spur rule`.)
298
+ 3. **Guard / edge declaration order matters.** The first passing guard (state-machine) or condition
299
+ (transition-flow) wins. Order the specific case before the fallback. Simple shell checks can use
300
+ `action-ok` before an unconditional retry edge; multi-condition gates prefer a **soft status-file
301
+ probe** (always exit 0) with ordered shell guards for PASS / FAIL / exhausted (see
302
+ `.spur/workflows/basic.yaml` and `task-pipeline.yaml` quality-gate hop).
303
+ 4. **`env.allow` is an allowlist.** `${env.X}` resolves only if `X` is listed under `env.allow`;
304
+ otherwise it resolves empty. A workflow that "loses" an environment value usually forgot to allow it.
305
+ 5. **Extensions are fail-closed.** Custom action/guard *modules* require `allowExtensions: true`; a
306
+ declared-but-not-allowed extension throws **before any import** — never silently dropped. Inline
307
+ `host.registerAction`/`registerGuard` need no flag; only the module loader is gated.
308
+ 6. **A failed run does not throw.** Action/guard failures come back as `WorkflowRunResult` with
309
+ `status: 'failed'`, preserving the run record. Read the trace; don't expect an exception. (Definition
310
+ errors — schema/semantic/missing-state — *do* throw: `WorkflowValidationError` / `FSMError` / `RunCollisionError`.)
311
+ 7. **Bound your loops.** A state-machine with a retry cycle needs `iterationBound` or it can run away.
312
+ The driver fails the run with `iteration-bound-exceeded` once the bound is crossed.
313
+ 8. **`onError` is library/runtime-only for now.** The TypeScript engine supports
314
+ `action.onError ?? workflow.defaultOnError ?? runOptions.onError ?? 'fail'`, but the bundled JSON
315
+ schemas used by quoted `$schema` validation do not yet include `onError` / `defaultOnError`.
316
+ Do not author those fields in normal CLI YAML unless you intentionally validate with `--no-schema`
317
+ and own the compatibility tradeoff.
318
+ 9. **Do not rely on a workspace `node_modules/@gobing-ai/spur` symlink for schema truth.**
319
+ Validate/run use the embedded map when the CLI provides it. A manual
320
+ `ln -sfn … node_modules/@gobing-ai/spur` is a session workaround, not a fix (0431).
321
+ 10. **`--answer` does not imply `--yes`.** Omitting `run-id` without `--yes` still prompts to
322
+ confirm which paused run to resume, even when `--answer yes` is set.
323
+
324
+ ## Additional Resources
325
+
326
+ - [workflows/operations.md](workflows/operations.md) — the operation procedures (validate/run/list/add/refine),
327
+ the shared find-existing-workflow and validate-and-dry-run cores, and the mode-selection gate. The
328
+ entry point for slash-command delegation.
329
+ - [workflows/authoring-workflows.md](workflows/authoring-workflows.md) — author a workflow: mode
330
+ selection in depth, per-mode real YAML shapes, built-in actions/guards, template variables, the
331
+ validate-and-dry-run core, expected-terminal-state assertion.
332
+ - [workflows/validation-and-extension.md](workflows/validation-and-extension.md) — validate semantics,
333
+ custom action/guard runners, the trust-gated extension loader, and CLI-vs-library capability gaps.
334
+ - `@gobing-ai/ts-dual-workflow-engine` README — authoritative library reference (both drivers,
335
+ RunLifecycle, persistence, the full event map, every built-in capability).
336
+ - `.spur/workflows/basic.yaml` — the canonical state-machine implement→soft-check→fixall loop
337
+ (status-file branching + `qualityGateMaxFixAttempts`); copy real shapes from here.
338
+ - `.spur/workflows/task-pipeline.yaml` — full production pipeline (precheck, quality gate, HITL,
339
+ verify, record) when you need the complete reliability pattern set.
340
+
341
+ ## Platform Notes
342
+
343
+ ### Claude Code
344
+ Run `spur workflow` via the Bash tool. During development the CLI entry is a `.ts` file that runs only
345
+ under Bun: `bun run apps/cli/src/index.ts workflow validate <file> --json`. The installed `spur` binary
346
+ works once built.
347
+
348
+ ### Codex / OpenClaw / OpenCode / Antigravity
349
+ Run `spur workflow ...` via the Bash tool; parse `--json` output programmatically. Arguments are passed
350
+ directly on the command line.
351
+
352
+ ---
353
+
354
+ **Template type**: technique
355
+ **Purpose**: Operate `spur workflow` across its full lifecycle — choose the execution mode, author, validate, run, and refine dual-mode workflows