@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,133 @@
1
+ ---
2
+ name: spur-cli-team
3
+ description: "spur-cli noun reference: operate `spur team` as the team coordination surface - assign agents to tasks, inspect grouped status, materialize and tear down team rosters, and start/stop supervised agent processes. The lifecycle layer over `spur agent` specs."
4
+ see_also:
5
+ - spur-cli
6
+ ---
7
+
8
+ # spur team - team coordination and supervision
9
+
10
+ `spur team` is the CLI for **coordinating team agent assignments and supervision**. It sits above
11
+ `spur agent` specs: `up` / `down` materialize and tear down rosters, `start` / `stop` manage
12
+ supervised processes (requiring `spur serve`), `assign` wires tasks to agents, and `status` reports
13
+ the live picture.
14
+
15
+ This is a **companion reference**, not an orchestrator. It documents *what each verb is and how to
16
+ use it well*.
17
+
18
+ ## Verb map
19
+
20
+ | Verb | Purpose | Key flags |
21
+ | ---- | ------- | --------- |
22
+ | `assign <task-id> <agent-id>` | Set the assignee on a task file | - |
23
+ | `status` | List agent specs and their run status; `--by-team` groups by team | `--by-team` `--server <url>` `--json` |
24
+ | `up <team>` | Materialize a team roster into specs; best-effort start | `--check` `--server <url>` `--json` |
25
+ | `down <team>` | Tear down a team: stop members; `--purge` removes generated specs | `--purge` `--server <url>` `--json` |
26
+ | `start <agent-id>` | Start a supervised agent process (requires `spur serve`) | `--server <url>` `--json` |
27
+ | `stop <agent-id>` | Stop a supervised agent process (requires `spur serve`) | `--server <url>` `--json` |
28
+
29
+ All verbs accept `--json` for machine consumption. `--server <url>` (default:
30
+ `http://localhost:3000/api`) targets the supervisor API started by `spur serve`. **Exit codes:** `0`
31
+ success, `1` error, `2` invalid usage.
32
+
33
+ ## `assign` - wire a task to an agent
34
+
35
+ ```bash
36
+ spur team assign 0040 worker-1
37
+ ```
38
+
39
+ Sets the `assignee` field on the task file `<task-id>` to `<agent-id>`. This is the traceability edge
40
+ between the task corpus and the team roster - it records *who* is responsible, not *what* they run.
41
+
42
+ ## `status` - agent specs and run state
43
+
44
+ ```bash
45
+ spur team status # flat list
46
+ spur team status --by-team # grouped by team:<id> membership
47
+ spur team status --json # machine-readable
48
+ ```
49
+
50
+ Lists agent specs and their live run status. When `spur serve` is reachable, enriches each spec with
51
+ the supervisor's process status (`running` / `stopped` / etc.); otherwise falls back to local spec
52
+ metadata. `--by-team` groups specs by their `agent.team.<id>` tag.
53
+
54
+ ### Flags
55
+
56
+ | Flag | Purpose |
57
+ |------|---------|
58
+ | `--by-team` | Group specs by their `agent.team.<id>` membership (0258 R4). |
59
+ | `--server <url>` | Server API URL for live run status (default: `http://localhost:3000/api`). |
60
+ | `--json` | Output machine-readable JSON. |
61
+
62
+ ## `up` - materialize a team roster
63
+
64
+ ```bash
65
+ spur team up alpha # materialize + best-effort start
66
+ spur team up alpha --check # dry-run: show add/prune diff, no writes
67
+ spur team up alpha --json
68
+ ```
69
+
70
+ Materializes a team roster (defined by specs sharing `agent.team.<team>`) into `.spur/agents/`
71
+ specs - adding missing specs and pruning stale `spur:generated` ones. When `spur serve` is
72
+ reachable, best-effort starts each member. `--check` is a dry-run that shows the add/prune diff
73
+ without writing.
74
+
75
+ ### Flags
76
+
77
+ | Flag | Purpose |
78
+ |------|---------|
79
+ | `--check` | Dry-run: show the add/prune diff without writing. |
80
+ | `--server <url>` | Server API URL (default: `http://localhost:3000/api`). |
81
+ | `--json` | Output machine-readable JSON. |
82
+
83
+ ## `down` - tear down a team
84
+
85
+ ```bash
86
+ spur team down alpha # stop members
87
+ spur team down alpha --purge # also delete spur:generated specs
88
+ spur team down alpha --json
89
+ ```
90
+
91
+ Stops all members of `<team>` via the supervisor. `--purge` also deletes specs marked `spur:generated`
92
+ (never manual or `ref:` specs) - use it to fully clean up a materialized roster.
93
+
94
+ ### Flags
95
+
96
+ | Flag | Purpose |
97
+ |------|---------|
98
+ | `--purge` | Also delete `spur:generated` specs (never manual / `ref:`). |
99
+ | `--server <url>` | Server API URL (default: `http://localhost:3000/api`). |
100
+ | `--json` | Output machine-readable JSON. |
101
+
102
+ ## `start` / `stop` - supervised process control
103
+
104
+ ```bash
105
+ spur team start worker-1 # start supervised process
106
+ spur team stop worker-1 # stop supervised process
107
+ spur team start worker-1 --json
108
+ ```
109
+
110
+ Start or stop a supervised agent process. **Requires `spur serve`** to be running - these verbs go
111
+ through the server's supervisor API (`POST /api/team/start`, `POST /api/team/stop`), not local
112
+ process spawning. The started process runs `spur agent loop --agent <id>` under supervision.
113
+
114
+ ### Flags
115
+
116
+ | Flag | Purpose |
117
+ |------|---------|
118
+ | `--server <url>` | Server API URL (default: `http://localhost:3000/api`). |
119
+ | `--json` | Output machine-readable JSON. |
120
+
121
+ ## What this skill is NOT
122
+
123
+ - **Not the agent runner.** `start` launches `spur agent loop` under supervision; the loop's
124
+ execution primitives are documented in **[agent.md](agent.md)**.
125
+ - **Not the message transport.** Team agents communicate via `spur message`; see
126
+ **[message.md](message.md)**.
127
+
128
+ ## See also
129
+
130
+ - **`spur agent` (see [agent.md](agent.md))** - the execution primitives `team start` supervises.
131
+ - **`spur message` (see [message.md](message.md))** - the durable inbox team members drain.
132
+ - **`spur serve` (see [serve.md](serve.md))** - the local server `start`/`stop`/`status` require.
133
+ - **`sp:spur-cli`** SKILL.md - the facade that routes to this reference.
@@ -0,0 +1,226 @@
1
+ ---
2
+ name: authoring-workflows
3
+ description: Author a workflow — mode selection in depth, per-mode real YAML shapes, built-in actions and guards, template variables, and the validate-and-dry-run verification core.
4
+ see_also:
5
+ - spur-cli
6
+ - operations
7
+ ---
8
+
9
+ # Authoring Workflows
10
+
11
+ How to write a workflow definition that validates and runs. Start with mode, then the schema shape for
12
+ that mode, then the actions/guards and template vars, then prove it with validate-and-dry-run.
13
+
14
+ ## Mode selection in depth
15
+
16
+ The two kinds are not interchangeable. They differ at the schema level:
17
+
18
+ | | `state-machine` | `transition-flow` |
19
+ | --- | --- | --- |
20
+ | Unit of progress | a **state** the run currently occupies | a **node** the run advances through |
21
+ | Where work happens | `state.onEnter` / `state.onExit` action lists | `node.action` (one action per node) |
22
+ | How the next step is chosen | top-level `transitions[]`, each `{from, to, guard?}`; first guard that passes wins | `edges[]`, each `{from, to, condition?}`; first condition that passes wins; an edge with no condition is unconditional |
23
+ | Looping | first-class — point a transition back to an earlier state | possible but the model is DAG-forward; loops read awkwardly |
24
+ | Node types | none | `type: action \| gate \| parallel \| decision` |
25
+ | Terminal | `terminalStates: [...]` | `terminalNodes: [...]` |
26
+ | `kind` | optional (default) | **required**: `kind: transition-flow` |
27
+
28
+ **Decide by the dominant shape of the process:**
29
+
30
+ - A **loop with retries** — implement → check → fix → check until pass — is a state-machine. One thing
31
+ is active; a guard decides whether to advance or loop back.
32
+ - A **pipeline** — read → validate → transform → write, possibly with a gate or fan-out — is a
33
+ transition-flow. Each node does one thing and hands off along an edge.
34
+ - When genuinely torn, choose **state-machine** (simpler, the default kind) and record why.
35
+
36
+ ## Per-mode shapes
37
+
38
+ Copy these real shapes; do not reconstruct from memory. Both quote `$schema` (leading `@` is reserved).
39
+
40
+ ### State-machine
41
+
42
+ ```yaml
43
+ $schema: "@gobing-ai/ts-dual-workflow-engine/schemas/state-machine-workflow.schema.json"
44
+ kind: state-machine # optional, but include it for legibility
45
+ name: approval
46
+ description: Implement → check → fix until the check passes or the bound is exhausted
47
+ iterationBound: 2 # bounds any loop; required when a transition points backward
48
+ initialState: implement
49
+ terminalStates: [done, failed]
50
+ failureStates: [failed] # optional; ⊆ terminalStates → status failed (0425)
51
+ vars:
52
+ reviewer: robin # ${vars.reviewer}
53
+ env:
54
+ allow: [APP_ENV] # only allow-listed names resolve via ${env.APP_ENV}
55
+ states:
56
+ - id: implement
57
+ description: Implement the requested task
58
+ onEnter:
59
+ - kind: note
60
+ options:
61
+ message: "Implementing task: ${task}"
62
+ - id: check
63
+ onEnter:
64
+ - kind: shell
65
+ options:
66
+ command: bun run check
67
+ - id: fix
68
+ onEnter:
69
+ - kind: note
70
+ options:
71
+ message: "Please fix the issues found"
72
+ - id: done
73
+ - id: failed
74
+ transitions:
75
+ - from: implement
76
+ to: check
77
+ # Declaration order matters: the action-ok guard is tried first, so a passing
78
+ # check short-circuits to done before the unconditional fix edge is considered.
79
+ - from: check
80
+ to: done
81
+ guard: { kind: action-ok }
82
+ - from: check
83
+ to: fix
84
+ - from: fix
85
+ to: check
86
+ ```
87
+
88
+ Required keys: `name`, `initialState`, `states`, `transitions`. Each state needs an `id`; `onEnter`/
89
+ `onExit` are optional action lists. Each transition needs `from`/`to`; `guard` and `trigger` are
90
+ optional (a transition with no guard is unconditional).
91
+
92
+ ### Transition-flow
93
+
94
+ ```yaml
95
+ $schema: "@gobing-ai/ts-dual-workflow-engine/schemas/transition-flow-workflow.schema.json"
96
+ kind: transition-flow # REQUIRED — a missing kind parses as state-machine
97
+ name: import-file
98
+ description: Read → validate → done pipeline
99
+ initialNode: read
100
+ terminalNodes: [done]
101
+ vars:
102
+ file: events.jsonl # ${vars.file}
103
+ nodes:
104
+ - id: read
105
+ type: action
106
+ action:
107
+ kind: note
108
+ options:
109
+ message: "reading ${vars.file}"
110
+ - id: validate
111
+ type: gate
112
+ - id: done
113
+ edges:
114
+ - from: read
115
+ to: validate
116
+ - from: validate
117
+ to: done
118
+ condition: { kind: always }
119
+ ```
120
+
121
+ Required keys: `kind` (`transition-flow`), `name`, `initialNode`, `nodes`, `edges`. Each node needs an
122
+ `id`; `type` (`action`/`gate`/`parallel`/`decision`) and `action` are optional. Each edge needs
123
+ `from`/`to`; `condition` is optional (no condition = unconditional edge).
124
+
125
+ ## Built-in actions and guards
126
+
127
+ The default host (`createDefaultWorkflowEngineHost()`) registers these. Anything else needs a custom
128
+ runner (see [validation-and-extension.md](validation-and-extension.md)).
129
+
130
+ | Capability | Kind | Use |
131
+ | ---------- | ---- | --- |
132
+ | Action | `note` | Record a message in the run's result data; the safe no-op for shaping/dry-running |
133
+ | Action | `shell` | Run a shell command via the runtime `ProcessExecutor`; the action "succeeds" or "fails" by exit code |
134
+ | Guard | `always` | Unconditional pass — the default edge condition / fallback transition |
135
+ | Guard | `action-ok` | Pass iff the prior action on this state/node succeeded — useful for a single hard shell check |
136
+
137
+ Order matters for both guards and conditions: **the first that passes wins.** Put the discriminating
138
+ guard before the unconditional fallback (`always` / no-guard edge). For multi-condition gates (doctor
139
+ + task check, quality gate + attempt cap), prefer a **soft probe** shell that writes PASS|FAIL and
140
+ always exits 0, then branch with ordered status-file guards — see shipped `basic.yaml` /
141
+ `task-pipeline.yaml` (more reliable than `action-ok` alone when more than one condition decides the edge).
142
+
143
+ ## Template variables
144
+
145
+ Actions receive resolved templates. Available substitutions:
146
+
147
+ | Template | Source |
148
+ | -------- | ------ |
149
+ | `${vars.NAME}` | Workflow `vars` merged with per-run `vars` (run overrides win) |
150
+ | `${env.NAME}` | Environment values **explicitly listed in `env.allow`** (else empty) |
151
+ | `${runId}` / `${run}` | Current run id |
152
+ | `${workflow}` / `${task}` | Workflow name |
153
+ | `${state}` / `${node}` | Current state or node id |
154
+ | `${iteration}` | Current transition count |
155
+ | `${runtime}` | Execution mode (`state-machine` or `transition-flow`) |
156
+
157
+ `env.allow` is an allowlist: a `${env.X}` whose `X` is not listed resolves to empty, not an error — a
158
+ common silent surprise. Add the name to `env.allow` for it to resolve.
159
+
160
+ ### Shell commands take vars by name, never by template
161
+
162
+ **In a `shell` command — action *or* transition guard — reference a var as `$NAME`, not
163
+ `${vars.NAME}`.**
164
+
165
+ | Where | Spelling | Why |
166
+ | ----- | -------- | --- |
167
+ | `shell` action `command:` | `$NAME` | Value arrives as process env |
168
+ | `shell` guard `command:` | `$NAME` | Same |
169
+ | Everything else (`agent.run` `input:`, `note` `message:`, `description:`, paths in non-shell options) | `${vars.NAME}` | Engine template resolution; never shell-interpreted |
170
+
171
+ `${vars.NAME}` in a shell command is resolved by the engine **into the command string** before the
172
+ shell runs, so any backtick, `$(…)`, or quote in the value is parsed as shell code. That was a live
173
+ arbitrary-execution defect in both actions (task 0432) and guards (task 0435) — and in a guard it is
174
+ especially quiet, because the injected side effect fires while the comparison still returns an
175
+ ordinary boolean. Spur's runners hand resolved vars to the subprocess as environment instead, and a
176
+ shell variable expansion is never re-parsed for metacharacters, so `$NAME` is always data.
177
+
178
+ ```yaml
179
+ # WRONG — value becomes part of the command
180
+ command: 'test "${vars.profile}" = auto'
181
+ # RIGHT — value arrives as env
182
+ command: 'test "$profile" = auto'
183
+ ```
184
+
185
+ This only works where Spur's runners are registered (`registerSpurBuiltins`, and the lifecycle
186
+ adapter's host). A bare `createDefaultWorkflowEngineHost()` keeps the engine's env-less runners,
187
+ where `$NAME` would expand to empty — register the Spur runners on any new host.
188
+
189
+ ## Error policy (`onError`)
190
+
191
+ `onError` is a current **library/runtime capability**, not a normal quoted-`$schema` YAML authoring
192
+ field. The TypeScript schema accepts it and the drivers resolve it at three levels with precedence
193
+ `action.onError ?? workflow.defaultOnError ?? runOptions.onError ?? 'fail'`, but the bundled JSON
194
+ schemas used by `spur workflow validate <file> --json` when `$schema` is present do not yet list
195
+ `onError` / `defaultOnError`.
196
+
197
+ - **`fail`** — the run halts immediately with `status: 'failed'` on the first action error.
198
+ - **`continue`** — logs a non-fatal warning and advances to the next guard/edge evaluation. A node
199
+ with no outbound edges that fails under `continue` still terminates as `done`.
200
+
201
+ For CLI-authored YAML, keep the default fail-fast behavior and model best-effort behavior explicitly
202
+ with guards/branches until the JSON schemas catch up. Use YAML-level `onError` only when you
203
+ intentionally validate with `--no-schema` and own the compatibility tradeoff.
204
+
205
+ ## The validate-and-dry-run core
206
+
207
+ Authoring is not done until the workflow is proven. The core (full steps in
208
+ [operations.md](operations.md#sub-procedure-validate-and-dry-run)):
209
+
210
+ 1. `spur workflow validate <file> --json` — schema + semantic. Fix until clean.
211
+ 2. `spur workflow run <file> --run-id dryrun-<unique> --json` — **`status` is authoritative for
212
+ pass/fail** (`done` success / `failed` failure); then assert `finalState === <expected>`.
213
+ Use a fresh `--run-id` (duplicates raise `RunCollisionError`).
214
+ 3. Read the trace; on a stall or wrong terminal, fix the specific guard/target/bound and re-run.
215
+
216
+ A `shell` action runs for real during the dry-run — keep it idempotent and side-effect-light while
217
+ verifying shape, or stand in a `note` action until the path is proven, then swap the real command in.
218
+
219
+ ## Authoring checklist
220
+
221
+ - [ ] Mode chosen deliberately (loop → state-machine; pipeline → transition-flow); recorded the reason.
222
+ - [ ] `kind: transition-flow` set for flows; `$schema` quoted.
223
+ - [ ] Initial + terminal states/nodes declared; every transition/edge target exists.
224
+ - [ ] Guards/conditions ordered so the specific case precedes the fallback.
225
+ - [ ] `iterationBound` set for any loop; `env.allow` lists every `${env.X}` used.
226
+ - [ ] Validates clean AND dry-run reaches the expected terminal state.
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: operations
3
+ description: Named operation procedures (validate/run/list/trace/continue/cancel/clean/add/refine), the mode-selection gate, and the shared find-existing-workflow and validate-and-dry-run cores that back the spur workflow slash commands.
4
+ see_also:
5
+ - spur-cli
6
+ ---
7
+
8
+ # Operations
9
+
10
+ The skill's operations as discrete procedures. The deterministic ones (`validate`, `run`, `list`,
11
+ `trace`, `continue`, `cancel`, `clean`) are direct CLI verbs — documented briefly here for completeness,
12
+ but you run them straight (no slash command). The agent-driven ones (`add`, `refine`) convert fuzzy
13
+ intent into a reliable sequence and are what the slash commands delegate to; their full steps live below.
14
+
15
+ A workflow you have not watched run is a workflow you do not trust. So both `add` and `refine` end in
16
+ the same verification core ([validate-and-dry-run](#sub-procedure-validate-and-dry-run)) — that shared
17
+ core is why a tuned workflow is re-checked exactly like a freshly authored one. `add` and `refine` also
18
+ share the [find-existing-workflow](#sub-procedure-find-existing-workflow) core so the workflow catalog
19
+ never diverges no matter which operation touches it. `add` additionally runs the
20
+ [mode-selection gate](#sub-procedure-mode-selection-gate) — the one decision unique to this skill.
21
+
22
+ ## Workflow location convention
23
+
24
+ Authored workflows default to a project-local directory, grouped by purpose:
25
+
26
+ ```
27
+ .spur/workflows/<name>.yaml # project workflows (the convention)
28
+ ```
29
+
30
+ A `--file <path>` argument overrides the default. Keep one workflow per file, named for what it does
31
+ (`approval.yaml`, `import-file.yaml`), not for its mode. The canonical example
32
+ (`.spur/workflows/basic.yaml`) lives here; copy real schema shapes from it rather than from a
33
+ half-remembered snippet.
34
+
35
+ ## Sub-procedure: mode-selection gate
36
+
37
+ The decision unique to workflows — run this **before authoring anything new**. The two kinds use
38
+ different schemas and a different mental model; switching later is a rewrite. Inputs: the described
39
+ process (one or two sentences). Steps:
40
+
41
+ 1. **Classify the process shape** against the discriminators (SKILL.md → "Choose the execution mode
42
+ first"):
43
+
44
+ | Signal in the description | → mode |
45
+ | ------------------------- | ------ |
46
+ | "loop until", "retry", "keep checking", one thing active at a time, can go back a step | **state-machine** |
47
+ | "then", "pipeline", "for each", fan-out, gate/decision, action-per-step, mostly forward | **transition-flow** |
48
+ | Genuinely ambiguous | **state-machine** (the simpler default) — and say so |
49
+
50
+ 2. **Honor an explicit `--kind`** — if the caller passed `--kind`, use it; skip to step 4 and just
51
+ record the rationale for the record.
52
+ 3. **Recommend + confirm** — surface the recommended mode, the **reason** (which discriminator
53
+ decided it), and the **rejected alternative** (what the other mode would have implied). Require
54
+ confirmation before authoring. This is the human-in-the-loop gate; do not silently pick a mode the
55
+ user did not see.
56
+ 4. **Lock the mode** — for transition-flow, the YAML **must** set `kind: transition-flow` (a missing
57
+ `kind` parses as state-machine and fails confusingly). For state-machine, `kind` is optional but
58
+ include it for legibility.
59
+
60
+ Output contract: `{ mode, reason, rejectedAlternative }` + the confirmed mode to author in.
61
+
62
+ ## Sub-procedure: find-existing-workflow
63
+
64
+ Reconciliation core — run this **before authoring anything**. Authoring without checking the existing
65
+ workflows breeds redundant, diverged definitions (two near-identical approval flows, an import flow
66
+ re-implemented under a new name). Inputs: the clarified process intent. Steps:
67
+
68
+ 1. **Enumerate existing workflows** — list `.spur/workflows/*.yaml` (and any `--file`-adjacent
69
+ directory); read each one's `name`, `kind`, and the states/nodes it defines so matches are found by
70
+ *substance*, not just by filename.
71
+ 2. **Classify the strongest match** against the new intent:
72
+
73
+ | Match | Meaning | Action |
74
+ | ----- | ------- | ------ |
75
+ | Same process, same shape | A workflow already does this | **STOP — do not add.** It exists; if behavior is off, hand to [refine](#refine). |
76
+ | Same process, extra steps needed | An existing flow is close but missing a state/node/branch | **EXTEND** via [refine](#refine) — add to the existing flow, don't fork it. |
77
+ | Adjacent / overlapping concern | A related flow exists but the new intent is distinct | **ADD new** — the genuinely new branch. |
78
+ | No real match | New process | **ADD new.** |
79
+
80
+ 3. **Recommend + confirm** — report the strongest match, the classification, and the recommended
81
+ action (extend-via-refine / add-new). Require confirmation before authoring. Never silently
82
+ duplicate an existing workflow, and never silently edit one the user did not name.
83
+
84
+ Output contract: `{ match: workflow-name|none, classification, recommendation, evidence }` + the
85
+ confirmed action to take.
86
+
87
+ ## Sub-procedure: validate-and-dry-run
88
+
89
+ The shared verification core. Inputs: a workflow file path + the expected terminal state. Steps:
90
+
91
+ 1. **Validate** — `spur workflow validate <file> --json`. Runs the structural Zod schema **and**
92
+ semantic invariants (referenced states/nodes exist, terminal reachable, `${...}` templates resolve).
93
+ On error, surface root-cause + fix (see [validate](#validate--list-direct-cli)); stop until clean.
94
+ The most common errors are an unquoted `$schema` (`@` is YAML-reserved) and a missing
95
+ `kind: transition-flow` on a flow definition.
96
+ 2. **Dry-run** — `spur workflow run <file> --dry-run --run-id dryrun-<unique> --json`. Use a throwaway, unique
97
+ `--run-id` (a duplicate raises `RunCollisionError`). **`status` is authoritative for pass/fail**
98
+ (`done` = success, `failed` = failure; CLI exit is non-zero unless `status === 'done'`). Then
99
+ assert `finalState === <expected>` to confirm *which* terminal was reached. A `status: 'failed'`
100
+ (including a declared failure terminal such as `failed`/`cancelled`) or a wrong success
101
+ `finalState` means the workflow does not behave as intended — read the trace.
102
+ 3. **Read the trace** — confirm the run entered the intended states/nodes and took the intended
103
+ transitions/edges. A run that stalls short of the expected terminal points at a guard/condition that
104
+ never passed, a mistyped target, or an exhausted `iterationBound`. Fix the **specific** definition
105
+ flaw, never restructure to mask it.
106
+ 4. **Report** — `{ valid, ranToExpectedTerminal, tracePath }`. The workflow is verified only when the
107
+ definition validates AND the dry-run reaches the expected terminal state.
108
+
109
+ > A `shell` action runs real commands during the dry-run. Keep authored-workflow shell actions
110
+ > idempotent and side-effect-light, or stub them with a `note` action while verifying shape, then
111
+ > swap the real command in once the path is proven. Never point a dry-run at a destructive command.
112
+
113
+ ## validate / list / trace / continue / cancel / clean (direct CLI)
114
+
115
+ Deterministic single-verb CLI calls. Run them straight; the skill interprets results when asked.
116
+
117
+ - `spur workflow validate <file> [--no-schema] --json` — structural schema + semantic check. Classify
118
+ any error as **schema** (violates the state-machine/transition-flow JSON schema — often an unquoted
119
+ `$schema`, or a flow missing `kind: transition-flow`) vs. **semantic** (a transition references a
120
+ state that doesn't exist, a terminal state is unreachable, a `${vars.x}` with no matching var, an
121
+ `${env.X}` not in `env.allow`). The `validate-and-dry-run` core calls this as step 1. `--no-schema`
122
+ skips only the `$schema` ref resolution, keeping the structural + semantic checks.
123
+ - `spur workflow list --json` — available **workflow YAML definition files** on disk (not run history).
124
+ - `spur workflow trace [run-id] [--workflow <n>] [--status <s>] [--since <iso>] [--last <n>] --json` —
125
+ persisted run history (list filters) or a single-run timeline when `run-id` is given. Use this to
126
+ inspect prior outcomes; do **not** use `list` for that.
127
+ - `spur workflow continue [run-id] [--yes] --json` — resume a paused HITL run (omit id → most recent
128
+ paused).
129
+ - `spur workflow cancel <run-id> --json` — mark one non-terminal run failed (SIGTERM async worker
130
+ process group when live).
131
+ - `spur workflow clean [--older-than <min>] [--force] [--dry-run] --json` — bulk-finalize stale
132
+ `running`/`pending` runs (default age threshold 30 minutes; `--force` ignores age).
133
+
134
+ ## run (direct CLI — dry-run / execution / async)
135
+
136
+ `spur workflow run` is a direct CLI verb; there is no slash command for it. The skill drives it as the
137
+ dry-run step of the harness loop, and operators run it directly to execute a real workflow. Procedure:
138
+
139
+ 1. `spur workflow run <file> [--run-id <id>] [--vars <json>] [--dry-run] [--async] [--no-plan] --json`.
140
+ 2. Sync path: **`status` is authoritative for pass/fail** (`done` | `failed` | `paused` | …).
141
+ Exit code is non-zero unless `status === 'done'`. Read `finalState` only to identify which
142
+ terminal was reached (e.g. `failed` vs `cancelled` after a failure-terminal finalize). Do not
143
+ treat `status: 'done'` + a failure-named `finalState` as success — declared `failureStates`
144
+ finalize as `status: 'failed'` (0425).
145
+ 3. `--dry-run`: walk transitions without executing actions (preferred for the authoring harness loop).
146
+ 4. `--async`: spawn a detached worker, exit immediately with `runId`; monitor via
147
+ `spur workflow trace <run-id>`. Cancel with `spur workflow cancel <run-id>`.
148
+ 5. On `failed`, read the run trace (states/nodes entered, transitions taken) to locate the offending
149
+ step — a failed action, a declared failure terminal, a guard with no passing transition, or an
150
+ exhausted `iterationBound`.
151
+ 6. A failed run is data, not an exception — the run record is preserved. Fix the definition (for the
152
+ dry-run loop) or the environment/action (for a real run), then re-run with a fresh `--run-id`.
153
+
154
+ Output contract (sync): `status` (authoritative pass/fail) + `finalState` + parsed trace + the
155
+ offending-step diagnosis on failure. Async: `{ runId, status: 'started', workflowName }`.
156
+
157
+ ## add
158
+
159
+ Turn a described process into a validated, dry-run-verified workflow in the right mode. Procedure:
160
+
161
+ 1. **Clarify intent** — restate the process as one or two sentences: the steps, the success terminal,
162
+ the loop/branch points. If ambiguous (which step retries? what ends it?), state the interpretation
163
+ taken.
164
+ 2. **Mode-selection gate** — run [mode-selection gate](#sub-procedure-mode-selection-gate). This is
165
+ mandatory and gating: surface the recommended mode with its reason and the rejected alternative,
166
+ and **confirm before authoring**. Honor an explicit `--kind`.
167
+ 3. **Reconcile against existing workflows** — run [find-existing-workflow](#sub-procedure-find-existing-workflow).
168
+ If the process is already covered, **stop and hand to refine (or extend the existing flow) on
169
+ confirmation** — do not author a redundant workflow. Only the "no real match" / "add-new" branch
170
+ proceeds to author below.
171
+ 4. **Author the YAML** — use the **real schema shape** for the chosen mode
172
+ ([authoring-workflows.md → Per-mode shapes](authoring-workflows.md#per-mode-shapes)). Set `name`,
173
+ `description` (the WHY), the initial + terminal states/nodes, the steps with their actions, the
174
+ transitions/edges with guards/conditions in the right declaration order, `iterationBound` for any
175
+ loop, `env.allow` for any `${env.X}`, and a quoted `$schema`. For transition-flow, set
176
+ `kind: transition-flow`.
177
+ 5. **Place the file** — default `.spur/workflows/<name>.yaml` (a `--file` arg overrides), named for
178
+ what the workflow does.
179
+ 6. **Verify** — run the [validate-and-dry-run core](#sub-procedure-validate-and-dry-run) with the
180
+ expected terminal state. Not done until the definition validates AND the dry-run reaches it.
181
+
182
+ Output contract: YAML workflow content + chosen mode + reason + destination path + validate result +
183
+ dry-run result (status, finalState, expected). Done only when validate passes AND the dry-run reaches
184
+ the expected terminal state.
185
+
186
+ ## refine
187
+
188
+ Adjust an existing workflow with the smallest change that meets the intent. Procedure:
189
+
190
+ 1. **Locate the target** — if a workflow file is named, load it. If the user describes a *process*
191
+ instead ("the approval flow never reaches done"), run
192
+ [find-existing-workflow](#sub-procedure-find-existing-workflow) to resolve which file they mean
193
+ before editing. Read its current shape and mode.
194
+ 2. **Identify the dimension** from `--intent`:
195
+ - stuck run (never reaches terminal) → a guard/condition that never passes, a wrong transition
196
+ target, or an exhausted `iterationBound`
197
+ - missing step → add a state/node + its transition/edge in the correct declaration order
198
+ - runaway loop → set or raise `iterationBound`
199
+ - missing variable/env → add to `vars` or `env.allow`
200
+ See [authoring-workflows.md](authoring-workflows.md) for each mechanism's real shape. **Do not
201
+ switch mode** in a refine — a mode change is a rewrite; hand it back to `add`.
202
+ 3. **Apply the smallest change.** Preserve declaration order semantics (the first passing
203
+ guard/condition wins). Add a one-line rationale comment for any non-obvious choice such as an
204
+ `iterationBound`. No drive-by restructuring.
205
+ 4. **Preview if `--dry-run`** — emit a unified diff of the YAML change and stop (no write). This is a
206
+ skill-level output; the CLI has no dry-run for edits.
207
+ 5. **Verify** — run the [validate-and-dry-run core](#sub-procedure-validate-and-dry-run). A refine that
208
+ fixes a stuck run must prove it: the run that previously stalled now reaches the expected terminal.
209
+
210
+ Output contract: diff of the change + validate result + dry-run result (status, finalState, expected).
211
+ With `--dry-run`, the diff only.