@gobing-ai/spur 0.3.41 → 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,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.
|