@workflow-manager/runner 0.7.0 → 0.9.0

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.
@@ -0,0 +1,308 @@
1
+ ---
2
+ name: workflow-author
3
+ description: >
4
+ Author repeatable wfm workflows from a task description, validate them, run
5
+ them, and narrate progress as the workflow executes. Load this skill when a
6
+ user describes a multi-step task that should run the same way every time —
7
+ turn it into a wfm workflow file, validate it, and then drive `wfm run`
8
+ while translating status polls and approval gates into plain-language
9
+ updates for the user.
10
+ type: core
11
+ library: "@workflow-manager/runner"
12
+ sources:
13
+ - "navio/workflow-manager:src/parser.ts"
14
+ - "navio/workflow-manager:src/types.ts"
15
+ - "navio/workflow-manager:src/engine.ts"
16
+ - "navio/workflow-manager:src/index.ts"
17
+ - "navio/workflow-manager:src/sessionFile.ts"
18
+ - "navio/workflow-manager:doc/guide/workflow-schema.md"
19
+ - "navio/workflow-manager:doc/guide/runner-api.md"
20
+ ---
21
+
22
+ # workflow-author
23
+
24
+ Turn a natural-language task description into a `wfm` workflow file: a static, reviewable, re-runnable artifact instead of a one-off chat session. This skill is the authoring + operating counterpart to `workflow-manager-cli` — read that skill for the general command reference; this one is about *deciding what to build* and *narrating a run to a human*.
25
+
26
+ ## 1. When to use
27
+
28
+ Use this skill when the user has a task that:
29
+
30
+ - has more than one meaningful step, with a clear order or dependency between steps
31
+ - should produce the **same shape of result** every time it runs — not a bespoke plan improvised fresh each session
32
+ - benefits from an explicit quality gate (an objective check, a human sign-off, or both) before moving on
33
+ - is worth sharing: a teammate, a CI job, or a future session should be able to run it unchanged
34
+
35
+ Do **not** reach for a workflow file for a single ad-hoc question, a one-shot investigation, or a task whose steps genuinely can't be known in advance. Ad-hoc orchestration (just doing the work directly) is cheaper than authoring a workflow when there is nothing to repeat. The signal to watch for: the user says some version of "every time we do X" or "we need a repeatable way to Y."
36
+
37
+ ## 2. The authoring loop
38
+
39
+ Follow this sequence; do not skip validation.
40
+
41
+ 1. **Elicit the task and success criteria.** Ask (or infer from context) what "done" looks like for the overall task, and for each step you expect to need. Concrete, checkable criteria beat vague ones — "the change satisfies the objective and includes tests" is checkable; "does a good job" is not.
42
+ 2. **Decompose into chronological steps.** Every step gets a stable, kebab-case `key` (`implement-fix`, not `Step 1`). Wire `dependsOn` to express strict order — the engine resolves dependencies deterministically and rejects cycles, so an explicit `dependsOn: [previous-step]` is safer than relying on array order.
43
+ 3. **Choose a quality gate per step.** For each step's `validation` (or an `approval` step's `approvalSpec.validation`), pick one:
44
+ - `mode: agent` with concrete `criteria` — an objective, checkable condition a second agent call can verify against the step's output (tests pass, files changed match scope, no TODOs left). Prefer this whenever the check can be phrased as a fact about the artifact.
45
+ - a dedicated `kind: approval` step — a human judgment call (does this look right, is this the right tradeoff, are we comfortable shipping this). Use for genuinely subjective or high-stakes decisions.
46
+ - `mode: external` — an outside system resolves the step (a webhook, a deploy pipeline finishing).
47
+ - `mode: none` — mechanical steps with no interesting failure mode (formatting, a fixed notification).
48
+ 4. **Write the workflow.** Prefer the Markdown frontmatter format — humans (and you, later) can read the body notes alongside the machine-readable frontmatter; use JSON only for machine-generated definitions. Start from a scaffold:
49
+ ```bash
50
+ wfm scaffold --template agent-validated my-flow.md
51
+ ```
52
+ This drops a working three-step example (agent-validated task → approval → finalize) that you edit in place rather than writing from a blank file.
53
+ 5. **Validate, and keep validating.** `wfm validate my-flow.md` — fix every reported line, one at a time, until it prints `Validation OK`. Never hand a workflow to the user (or run it) with unresolved validation errors.
54
+ 6. **Dry-run adapter-heavy workflows with mocks.** If steps use real adapters (`pi-agent`, `claude-code`, `opencode`, `acp`), set `taskSpec.payload.mockResult: success` (or `retry` / `rollback` / `fail` to test routing) and `taskSpec.adapterKey: mock` temporarily, or `wfm doctor my-flow.md` to check host requirements without executing. This confirms dependency wiring and approval gating before spending a real adapter call.
55
+ 7. **Done.** The file *is* the reusable artifact — no further "session state" to preserve. Re-running it later reproduces the same step sequence.
56
+
57
+ ## 3. Schema cheat-sheet
58
+
59
+ Everything here matches `src/types.ts` on this branch — do not invent fields.
60
+
61
+ **Top level** (required: `key`, `title`, `steps`):
62
+
63
+ ```yaml
64
+ key: my-workflow # stable external identifier
65
+ title: My Workflow # default run objective
66
+ description: optional summary
67
+ objectives: [optional, run-level, objectives]
68
+ defaultRetryPolicy: { maxAttempts: 2 }
69
+ skills: # named skills resolvable by taskSpec.init.skills
70
+ my-skill:
71
+ source: ./skills/my-skill/SKILL.md # must match skills/**/SKILL.md under the workflow dir
72
+ steps: [ ... ]
73
+ ```
74
+
75
+ **Step** (required: `key`, `kind`):
76
+
77
+ ```yaml
78
+ - key: my-step # stable, kebab-case
79
+ kind: task # task | approval | system
80
+ title: optional display title
81
+ objective: optional step-level objective
82
+ dependsOn: [other-step-key]
83
+ timeoutSec: optional
84
+ retryPolicy: { maxAttempts: 2 }
85
+ validation: # gates confirmation for THIS step's own record
86
+ mode: none | human | external | agent
87
+ required: true
88
+ autoConfirm: false
89
+ agent: # only when mode: agent
90
+ adapterKey: pi-agent | mock | opencode | codex | claude-code | acp # default: this step's adapter
91
+ criteria: "plain-language acceptance criteria the validator checks against"
92
+ init: { model, skills, mcps, systemPrompts, context }
93
+ payload: { mockResult: success } # lets mock drive the validator in tests
94
+ taskSpec: # required when kind: task
95
+ adapterKey: pi-agent | mock | opencode | codex | claude-code | acp # omit -> pi-agent
96
+ init:
97
+ model: openrouter/anthropic/claude-sonnet-4
98
+ skills: [skill-name]
99
+ mcps: [mcp://endpoint]
100
+ systemPrompts: [Focus on X]
101
+ context: { any: json }
102
+ payload:
103
+ mockResult: success | retry | rollback | restart | yield | fail # mock adapter only
104
+ approvalSpec: # required when kind: approval
105
+ autoApprove: false
106
+ validation: { mode: human, required: true, autoConfirm: false }
107
+ ```
108
+
109
+ **Critical gotcha** (verified on this branch, `src/parser.ts`): the parser fills an *unset* step-level `validation` with `{ mode: "none", required: false, autoConfirm: true }` by default — **even on `approval` steps**. `canConfirm` in `src/engine.ts` checks `step.validation?.autoConfirm` *before* `step.approvalSpec?.validation?.autoConfirm`. If you only set `approvalSpec.validation` and leave the step's own top-level `validation` unset, the default `autoConfirm: true` wins and the gate **silently auto-approves** instead of waiting for a human. Always set both `validation` and `approvalSpec.validation` on an approval step with matching `mode`/`required`/`autoConfirm` — see the worked example below.
110
+
111
+ **Validation rules the CLI enforces:** unique step keys; every `dependsOn` references an existing step; no dependency cycles; `kind` is `task | approval | system`; `taskSpec.adapterKey` (if set) is one of the supported adapters; `validation.mode` is `none | human | external | agent`; `mode: agent` is **not allowed** on approval steps (`approvalSpec.validation`).
112
+
113
+ **Agent validation routing:** a validator agent's verdict becomes a QA action — `PROCEED` (continue), `RETRY_CURRENT` (rerun this step with feedback), `ROLLBACK_PREVIOUS` (rerun an earlier step), or `RESTART_ALL` (restart the run) — bounded by the step's `retryPolicy.maxAttempts`.
114
+
115
+ ## 4. Running and narrating (the agent-as-UI protocol)
116
+
117
+ Once a workflow validates, you are the UI for the run: start it detached, poll its state, and turn each transition into a short update instead of dumping raw JSON at the user.
118
+
119
+ **Start it detached, with a session file:**
120
+
121
+ ```bash
122
+ wfm run my-flow.md --session-file .wfm/session.json &
123
+ ```
124
+
125
+ The session file is written the moment the attach API is listening — `{ baseUrl, attachToken, runId, pid, startedAt }` — and rewritten with `endedAt` + `status` when the run finishes. It is never deleted, so it doubles as your "is this still running" signal. Every attach command below accepts `--session-file .wfm/session.json` instead of separate `--url`/`--token`.
126
+
127
+ **Poll on a cadence and narrate transitions**, not raw payloads:
128
+
129
+ ```bash
130
+ wfm status --session-file .wfm/session.json
131
+ ```
132
+
133
+ Read `status` and `currentStepKey` off the JSON, and translate: `"running"` + `currentStepKey: "implement-fix"` becomes something like *"step 1/3 (implement-fix) is running, attempt 1..."*. Don't re-poll faster than the work can plausibly progress — a few seconds between polls is usually plenty; back off further once a step has been running a while.
134
+
135
+ If you're dry-running with `adapterKey: mock`, expect steps to resolve near-instantly: your very first `status` poll may already show several steps succeeded (or the run parked at an approval gate) with no intermediate "running" beat to narrate. That's expected — narrate what you actually observe rather than assuming a step-by-step cadence.
136
+
137
+ **Use `events` for incremental detail** between polls instead of re-reading the whole snapshot:
138
+
139
+ ```bash
140
+ wfm events --session-file .wfm/session.json --since 4
141
+ ```
142
+
143
+ Track the last `nextSequence` you saw and pass it back as `--since` next time. Add `--include-logs` only when you actually want `agent.stdout`/`agent.stderr` chunks inline.
144
+
145
+ **Use `logs` when the user asks what a step is doing right now:**
146
+
147
+ ```bash
148
+ wfm logs --session-file .wfm/session.json --step implement-fix --limit 50
149
+ ```
150
+
151
+ **Detect and handle `waitingForApproval`.** When `status`'s top-level `status` is `"waiting_for_approval"`, the JSON includes a `waitingForApproval` object with `stepKey`, `reason`, and a `preview` (`summary` plus `items` describing what's being reviewed, including dependency outputs). Summarize that preview for the user in plain language. Then either:
152
+
153
+ - relay the decision the user gives you, or
154
+ - if the user has explicitly delegated authority for this gate ("auto-approve the review steps," "you decide"), decide yourself and act:
155
+
156
+ ```bash
157
+ wfm approve --session-file .wfm/session.json --step review-gate --note "why you approved"
158
+ wfm cancel --session-file .wfm/session.json --step review-gate --note "why you're stopping the run"
159
+ ```
160
+
161
+ Never approve on the user's behalf without either their live input or a standing delegation they gave you for that specific gate — it is a QA checkpoint, not decoration.
162
+
163
+ **On terminal status, report the outcome** by reading `endedAt` and `status` back from the session file (the run process has exited by then, so the attach API is gone — the session file is the only source left):
164
+
165
+ ```bash
166
+ cat .wfm/session.json # { ..., "endedAt": "...", "status": "succeeded" }
167
+ ```
168
+
169
+ **Exit codes** (for the `wfm run` process itself, if you're waiting on it directly rather than polling): `0` — run succeeded; `2` — run finished but not successfully (failed, cancelled, or ended waiting); `1` — validation or runtime error before/during execution, not a normal terminal status.
170
+
171
+ ## 5. Repeatability rules
172
+
173
+ - Never rename or remove a published workflow's step keys — other automation and history may reference them. Add new steps or a new workflow `key`/version instead of mutating shape in place.
174
+ - `key` (workflow) and step `key`s are stable external identifiers; change them only deliberately, and treat it as a breaking change for anything that depends on them.
175
+ - Keep `taskSpec.payload` deterministic — avoid embedding timestamps, random IDs, or environment-specific paths that would make two runs diverge for reasons unrelated to the actual task.
176
+ - Prefer `validation.mode: agent` criteria that a validator can check as a fact about the output (tests pass, a file exists, a diff touches only expected paths) over criteria that require taste. Save taste calls for `approval` steps.
177
+
178
+ ## 6. Install/share
179
+
180
+ ```bash
181
+ wfm skill install workflow-author # this skill -> ./.claude/skills/
182
+ wfm skill install workflow-author --agent opencode # -> ./.opencode/skill/
183
+ wfm skill install workflow-author --global # -> ~/.claude/skills/
184
+ ```
185
+
186
+ To share the workflow *file* itself (not this skill) with teammates, use the remote registry — `wfm publish my-flow.md` / `wfm pull owner/slug`; see the `workflow-manager-cli` skill and `doc/guide/` for the full registry contract.
187
+
188
+ ## Worked example
189
+
190
+ A repeatable "fix a flaky test" workflow: an agent-validated implementation step, a human sign-off gate, then a finalize step. Validated on this branch with `wfm validate` (`Validation OK`) and executed end-to-end with the mock adapter.
191
+
192
+ ```yaml
193
+ ---
194
+ key: fix-flaky-login-test
195
+ title: Fix Flaky Login Test
196
+ description: Diagnose and fix an intermittently failing login test, with a human sign-off before landing the fix
197
+ objectives:
198
+ - the login test passes reliably and the fix is reviewed before merge
199
+ defaultRetryPolicy:
200
+ maxAttempts: 2
201
+ steps:
202
+ - key: implement-fix
203
+ kind: task
204
+ objective: Reproduce the flake in tests/login.test.ts, diagnose the root cause, and fix it
205
+ dependsOn: []
206
+ retryPolicy:
207
+ maxAttempts: 2
208
+ validation:
209
+ mode: agent
210
+ required: true
211
+ autoConfirm: false
212
+ agent:
213
+ criteria: >-
214
+ tests/login.test.ts passes 20 consecutive local runs, the fix
215
+ addresses a root cause (not a retry/sleep workaround), and no
216
+ unrelated files changed.
217
+ init:
218
+ model: openrouter/anthropic/claude-sonnet-4
219
+ systemPrompts:
220
+ - Check the diff against the criteria; call out any retry/sleep workaround explicitly
221
+ taskSpec:
222
+ adapterKey: mock
223
+ init:
224
+ context:
225
+ repo: example/webapp
226
+ skills: [debugging, testing]
227
+ systemPrompts: [Find the root cause before writing a fix; add a regression test]
228
+ payload:
229
+ mockResult: success
230
+ - key: review-gate
231
+ kind: approval
232
+ objective: Human sign-off on the fix before it merges
233
+ dependsOn: [implement-fix]
234
+ # validation must be set here too, not just under approvalSpec — an unset
235
+ # step.validation defaults to autoConfirm: true, which would silently skip
236
+ # this gate. See the schema cheat-sheet above.
237
+ validation:
238
+ mode: human
239
+ required: true
240
+ autoConfirm: false
241
+ approvalSpec:
242
+ autoApprove: false
243
+ validation:
244
+ mode: human
245
+ required: true
246
+ autoConfirm: false
247
+ - key: finalize
248
+ kind: task
249
+ objective: Open a PR with the fix, the regression test, and a summary of the root cause
250
+ dependsOn: [review-gate]
251
+ validation:
252
+ mode: none
253
+ required: false
254
+ autoConfirm: true
255
+ taskSpec:
256
+ adapterKey: mock
257
+ init:
258
+ systemPrompts: [Open a PR summarizing the root cause, the fix, and the new regression test]
259
+ payload:
260
+ mockResult: success
261
+ ---
262
+
263
+ # Fix Flaky Login Test
264
+
265
+ Repeatable workflow for chasing down a flaky test: implement a fix (agent-validated
266
+ against explicit, checkable criteria), get a human sign-off, then finalize.
267
+ ```
268
+
269
+ ### Simulated narration transcript
270
+
271
+ ```
272
+ $ wfm run fix-flaky-login-test.md --session-file .wfm/session.json &
273
+ Attach API: http://127.0.0.1:43121 (token b354...)
274
+
275
+ [agent] Started the workflow in the background — I'll check in as it progresses.
276
+
277
+ $ wfm status --session-file .wfm/session.json
278
+ {"status":"running","currentStepKey":"implement-fix", ...}
279
+
280
+ [agent] step 1/3 (implement-fix) is running, attempt 1 — reproducing the flake and writing a fix.
281
+
282
+ $ wfm status --session-file .wfm/session.json
283
+ {"status":"waiting_for_approval","currentStepKey":"review-gate",
284
+ "waitingForApproval":{"stepKey":"review-gate",
285
+ "reason":"confirmation required for review-gate",
286
+ "preview":{"summary":"Approve this gate to continue after implement-fix.",
287
+ "items":[{"title":"Dependency implement-fix","status":"succeeded",
288
+ "summary":"Reproduce the flake in tests/login.test.ts, diagnose the root cause, and fix it"}]}}}
289
+
290
+ [agent] implement-fix passed agent validation (tests green, real root-cause fix,
291
+ no unrelated files touched) and is now waiting on you: review-gate wants a
292
+ human sign-off before finalize runs. Want me to look at the diff summary, or
293
+ are you approving as-is?
294
+
295
+ [user] approve it
296
+
297
+ $ wfm approve --session-file .wfm/session.json --step review-gate --note "Fix looks correct, root cause addressed"
298
+ approved review-gate
299
+
300
+ [agent] Approved review-gate. finalize is running now (opening the PR)...
301
+
302
+ $ cat .wfm/session.json
303
+ { ..., "endedAt": "2026-07-11T13:35:40.756Z", "status": "succeeded" }
304
+
305
+ [agent] Done — the workflow succeeded. implement-fix and finalize both ran
306
+ clean, and your sign-off on review-gate is recorded in the run's approval
307
+ audit trail.
308
+ ```