agentweaver 0.1.16 → 0.1.18
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/README.md +148 -27
- package/dist/artifacts.js +114 -3
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/flow-state.js +138 -1
- package/dist/index.js +421 -82
- package/dist/interactive/controller.js +305 -36
- package/dist/interactive/ink/index.js +24 -3
- package/dist/interactive/state.js +1 -0
- package/dist/interactive/tree.js +2 -2
- package/dist/interactive/web/index.js +179 -0
- package/dist/interactive/web/protocol.js +154 -0
- package/dist/interactive/web/server.js +575 -0
- package/dist/interactive/web/static/app.js +709 -0
- package/dist/interactive/web/static/index.html +77 -0
- package/dist/interactive/web/static/styles.css +2 -0
- package/dist/interactive/web/static/styles.input.css +469 -0
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +6 -5
- package/dist/pipeline/declarative-flows.js +39 -20
- package/dist/pipeline/flow-catalog.js +40 -14
- package/dist/pipeline/flow-specs/auto-common-guided.json +313 -0
- package/dist/pipeline/flow-specs/auto-common.json +4 -1
- package/dist/pipeline/flow-specs/auto-golang.json +27 -1
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +15 -1
- package/dist/pipeline/flow-specs/design-review.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +3 -1
- package/dist/pipeline/flow-specs/plan.json +8 -2
- package/dist/pipeline/flow-specs/playbook-init.json +199 -0
- package/dist/pipeline/flow-specs/review/review-fix.json +3 -1
- package/dist/pipeline/flow-specs/review/review-loop.json +4 -0
- package/dist/pipeline/flow-specs/review/review.json +2 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +119 -5
- package/dist/pipeline/nodes/flow-run-node.js +200 -173
- package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
- package/dist/pipeline/nodes/playbook-ensure-node.js +115 -0
- package/dist/pipeline/nodes/playbook-inventory-node.js +51 -0
- package/dist/pipeline/nodes/playbook-questions-form-node.js +166 -0
- package/dist/pipeline/nodes/playbook-write-node.js +243 -0
- package/dist/pipeline/nodes/project-guidance-node.js +69 -0
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +4 -1
- package/dist/pipeline/prompt-runtime.js +6 -2
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/spec-compiler.js +1 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +19 -0
- package/dist/pipeline/spec-validator.js +6 -0
- package/dist/pipeline/value-resolver.js +41 -2
- package/dist/playbook/practice-candidates.js +12 -0
- package/dist/playbook/repo-inventory.js +208 -0
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +31 -0
- package/dist/runtime/artifact-registry.js +3 -0
- package/dist/runtime/execution-routing.js +25 -19
- package/dist/runtime/interactive-execution-routing.js +66 -57
- package/dist/runtime/playbook.js +485 -0
- package/dist/runtime/project-guidance.js +339 -0
- package/dist/structured-artifact-schema-registry.js +8 -0
- package/dist/structured-artifact-schemas.json +235 -0
- package/dist/structured-artifacts.js +7 -1
- package/docs/declarative-workflows.md +565 -0
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/features.md +77 -0
- package/docs/playbook.md +327 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +13 -4
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
# Declarative Workflows
|
|
2
|
+
|
|
3
|
+
This document describes the declarative workflow and flow-spec format used by AgentWeaver today.
|
|
4
|
+
|
|
5
|
+
In architectural terms, flow specs are the language AgentWeaver uses for harness engineering. They are not just config files for commands. They define the workflow model that the CLI, resumable automation, and TUI all operate on.
|
|
6
|
+
|
|
7
|
+
The current implementation lives in:
|
|
8
|
+
|
|
9
|
+
- [src/pipeline/spec-types.ts](../src/pipeline/spec-types.ts)
|
|
10
|
+
- [src/pipeline/spec-loader.ts](../src/pipeline/spec-loader.ts)
|
|
11
|
+
- [src/pipeline/spec-validator.ts](../src/pipeline/spec-validator.ts)
|
|
12
|
+
- [src/pipeline/spec-compiler.ts](../src/pipeline/spec-compiler.ts)
|
|
13
|
+
- [src/pipeline/declarative-flow-runner.ts](../src/pipeline/declarative-flow-runner.ts)
|
|
14
|
+
- [src/pipeline/value-resolver.ts](../src/pipeline/value-resolver.ts)
|
|
15
|
+
|
|
16
|
+
If this document and the code disagree, the code is the source of truth.
|
|
17
|
+
|
|
18
|
+
## Why Declarative Workflows Exist
|
|
19
|
+
|
|
20
|
+
Flow specs keep orchestration declarative:
|
|
21
|
+
|
|
22
|
+
- JSON says what phases and steps should run
|
|
23
|
+
- runtime nodes in TypeScript say how each step executes
|
|
24
|
+
- executors provide integration with Codex, OpenCode, Jira, GitLab, shell commands, and related actions
|
|
25
|
+
|
|
26
|
+
That separation is the core of AgentWeaver's harness engineering approach. It keeps workflow design, runtime execution, validation, and operational control separated cleanly enough to evolve without rewriting command handlers.
|
|
27
|
+
|
|
28
|
+
Practically, this gives the project:
|
|
29
|
+
|
|
30
|
+
- a stable workflow description that can be reviewed like code
|
|
31
|
+
- reusable runtime behavior behind nodes and executors
|
|
32
|
+
- predictable artifacts and postconditions between stages
|
|
33
|
+
- a workflow graph that can be surfaced consistently in the TUI and in resumable runs
|
|
34
|
+
|
|
35
|
+
## Where Flow Specs Live
|
|
36
|
+
|
|
37
|
+
Built-in flow specs:
|
|
38
|
+
|
|
39
|
+
- `src/pipeline/flow-specs/**/*.json`
|
|
40
|
+
|
|
41
|
+
Project-local flow specs:
|
|
42
|
+
|
|
43
|
+
- `.agentweaver/.flows/**/*.json`
|
|
44
|
+
|
|
45
|
+
Discovery is recursive for both built-in and project-local flows.
|
|
46
|
+
|
|
47
|
+
Project-local flow ids are derived from the relative path inside `.agentweaver/.flows/` without the `.json` suffix. For example:
|
|
48
|
+
|
|
49
|
+
- `.agentweaver/.flows/my-team/release-check.json` -> `my-team/release-check`
|
|
50
|
+
|
|
51
|
+
Flow ids must be unique across the combined catalog. A project-local flow cannot shadow a built-in flow id.
|
|
52
|
+
|
|
53
|
+
## Load and Validation Pipeline
|
|
54
|
+
|
|
55
|
+
When a flow is loaded:
|
|
56
|
+
|
|
57
|
+
1. the JSON file is parsed
|
|
58
|
+
2. the validator checks structure and references
|
|
59
|
+
3. the compiler expands repeated phases into executable phases
|
|
60
|
+
4. the runner executes the expanded phases
|
|
61
|
+
|
|
62
|
+
Validation currently checks:
|
|
63
|
+
|
|
64
|
+
- `kind` and `version` structure
|
|
65
|
+
- known `node` ids
|
|
66
|
+
- required executors declared by node metadata
|
|
67
|
+
- required node params
|
|
68
|
+
- prompt template references
|
|
69
|
+
- artifact ref kinds
|
|
70
|
+
- artifact-list ref kinds
|
|
71
|
+
- structured artifact schema ids
|
|
72
|
+
- `ref` scope/path correctness
|
|
73
|
+
- nested `flow-run` file references when they are constant strings
|
|
74
|
+
|
|
75
|
+
## Top-Level Shape
|
|
76
|
+
|
|
77
|
+
Every flow spec has this shape:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"kind": "flow",
|
|
82
|
+
"version": 1,
|
|
83
|
+
"constants": {},
|
|
84
|
+
"phases": []
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Fields:
|
|
89
|
+
|
|
90
|
+
- `kind: string` — flow family identifier persisted into execution state
|
|
91
|
+
- `version: number` — flow format/version marker
|
|
92
|
+
- `constants?: Record<string, JsonValue>` — reusable flow-level constants available through `ref: "flow.<name>"`
|
|
93
|
+
- `phases` — ordered list of executable phases or repeat blocks
|
|
94
|
+
|
|
95
|
+
## Phases
|
|
96
|
+
|
|
97
|
+
A phase is the main user-visible stage in a declarative flow.
|
|
98
|
+
|
|
99
|
+
Shape:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"id": "plan",
|
|
104
|
+
"when": { "exists": { "ref": "params.taskKey" } },
|
|
105
|
+
"steps": []
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Fields:
|
|
110
|
+
|
|
111
|
+
- `id` — non-empty phase id
|
|
112
|
+
- `when?` — optional condition; false means the phase is skipped
|
|
113
|
+
- `steps` — ordered list of steps
|
|
114
|
+
|
|
115
|
+
For resumable flows such as `auto-golang`, phase ids are the identifiers shown in `--help-phases`, persisted in flow state, and used by restart-from-phase logic.
|
|
116
|
+
|
|
117
|
+
They are also the primary units the TUI can present to an operator when showing workflow progress.
|
|
118
|
+
|
|
119
|
+
## Repeat Blocks
|
|
120
|
+
|
|
121
|
+
The flow compiler supports repeated phase groups:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"repeat": {
|
|
126
|
+
"var": "iteration",
|
|
127
|
+
"from": 1,
|
|
128
|
+
"to": 3
|
|
129
|
+
},
|
|
130
|
+
"phases": [
|
|
131
|
+
{
|
|
132
|
+
"id": "review_{iteration}",
|
|
133
|
+
"steps": []
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
At compile time, repeated phases are expanded and receive `repeatVars`. Those values are later available via `ref: "repeat.<name>"`.
|
|
140
|
+
|
|
141
|
+
## Steps
|
|
142
|
+
|
|
143
|
+
A step is the executable unit inside a phase.
|
|
144
|
+
|
|
145
|
+
Shape:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"id": "run_codex_plan",
|
|
150
|
+
"node": "codex-prompt",
|
|
151
|
+
"when": { "exists": { "ref": "params.taskKey" } },
|
|
152
|
+
"prompt": {},
|
|
153
|
+
"params": {},
|
|
154
|
+
"expect": [],
|
|
155
|
+
"stopFlowIf": { "ref": "steps.run_codex_plan.stopFlow" },
|
|
156
|
+
"after": []
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Fields:
|
|
161
|
+
|
|
162
|
+
- `id` — stable step id within the phase
|
|
163
|
+
- `node` — runtime node kind from the node registry
|
|
164
|
+
- `when?` — optional condition; false means the step is skipped
|
|
165
|
+
- `prompt?` — declarative prompt binding for nodes that accept or require prompts
|
|
166
|
+
- `params?` — runtime parameters passed to the node after value resolution
|
|
167
|
+
- `expect?` — postconditions checked after the node completes
|
|
168
|
+
- `stopFlowIf?` — condition that can terminate the remaining flow after a successful step
|
|
169
|
+
- `after?` — post-step side effects
|
|
170
|
+
|
|
171
|
+
Node metadata controls whether a prompt is forbidden, optional, or required, and which params are mandatory.
|
|
172
|
+
|
|
173
|
+
From a harness-engineering perspective, steps are where a declarative workflow binds to concrete runtime capabilities without collapsing back into imperative scripting.
|
|
174
|
+
|
|
175
|
+
## Nodes
|
|
176
|
+
|
|
177
|
+
`node` values are references into the runtime node registry, not inline implementations.
|
|
178
|
+
|
|
179
|
+
Examples in the current codebase include:
|
|
180
|
+
|
|
181
|
+
- `jira-fetch`
|
|
182
|
+
- `codex-prompt`
|
|
183
|
+
- `opencode-prompt`
|
|
184
|
+
- `flow-run`
|
|
185
|
+
- `command-check`
|
|
186
|
+
- `build-failure-summary`
|
|
187
|
+
- `git-commit`
|
|
188
|
+
- `telegram-notifier`
|
|
189
|
+
|
|
190
|
+
See:
|
|
191
|
+
|
|
192
|
+
- [src/pipeline/node-registry.ts](../src/pipeline/node-registry.ts)
|
|
193
|
+
- [src/pipeline/nodes/](../src/pipeline/nodes)
|
|
194
|
+
|
|
195
|
+
## Prompt Binding
|
|
196
|
+
|
|
197
|
+
`prompt` describes how to assemble the final prompt text before it is passed to a prompt-capable node.
|
|
198
|
+
|
|
199
|
+
Shape:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"templateRef": "plan",
|
|
204
|
+
"vars": {
|
|
205
|
+
"jira_task_file": {
|
|
206
|
+
"artifact": {
|
|
207
|
+
"kind": "jira-task-file",
|
|
208
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"extraPrompt": { "ref": "params.extraPrompt" },
|
|
213
|
+
"format": "task-prompt"
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Supported fields:
|
|
218
|
+
|
|
219
|
+
- `templateRef` — named prompt template from the prompt registry
|
|
220
|
+
- `inlineTemplate` — inline string template instead of a named one
|
|
221
|
+
- `vars` — variables used for template interpolation
|
|
222
|
+
- `extraPrompt` — additional text appended via prompt runtime
|
|
223
|
+
- `format` — currently `plain` or `task-prompt`
|
|
224
|
+
|
|
225
|
+
At least one of `templateRef` or `inlineTemplate` must be present when `prompt` is defined.
|
|
226
|
+
|
|
227
|
+
See:
|
|
228
|
+
|
|
229
|
+
- [src/pipeline/prompt-registry.ts](../src/pipeline/prompt-registry.ts)
|
|
230
|
+
- [src/pipeline/prompt-runtime.ts](../src/pipeline/prompt-runtime.ts)
|
|
231
|
+
|
|
232
|
+
## Params
|
|
233
|
+
|
|
234
|
+
`params` are runtime inputs for the selected node.
|
|
235
|
+
|
|
236
|
+
Examples:
|
|
237
|
+
|
|
238
|
+
- `jira-fetch` may receive `jiraApiUrl` and `outputFile`
|
|
239
|
+
- `codex-prompt` may receive `labelText`, `model`, `outputFile`, or other node-specific values
|
|
240
|
+
- `flow-run` requires `fileName`
|
|
241
|
+
|
|
242
|
+
Prompt text is not part of `params`; it is assembled separately through `prompt`.
|
|
243
|
+
|
|
244
|
+
## Value Resolution
|
|
245
|
+
|
|
246
|
+
Most non-literal values in a flow spec are expressed with `ValueSpec`.
|
|
247
|
+
|
|
248
|
+
Currently supported value forms:
|
|
249
|
+
|
|
250
|
+
- `{ "const": ... }`
|
|
251
|
+
- `{ "ref": "..." }`
|
|
252
|
+
- `{ "artifact": { ... } }`
|
|
253
|
+
- `{ "artifactList": { ... } }`
|
|
254
|
+
- `{ "template": "...", "vars": { ... } }`
|
|
255
|
+
- `{ "appendPrompt": { "base": ..., "suffix": ... } }`
|
|
256
|
+
- `{ "add": [ ... ] }`
|
|
257
|
+
- `{ "concat": [ ... ] }`
|
|
258
|
+
- `{ "list": [ ... ] }`
|
|
259
|
+
|
|
260
|
+
### `const`
|
|
261
|
+
|
|
262
|
+
Returns the literal JSON value as-is.
|
|
263
|
+
|
|
264
|
+
### `ref`
|
|
265
|
+
|
|
266
|
+
Reads another runtime value by path.
|
|
267
|
+
|
|
268
|
+
Supported ref scopes are:
|
|
269
|
+
|
|
270
|
+
- `params`
|
|
271
|
+
- `flow`
|
|
272
|
+
- `context`
|
|
273
|
+
- `repeat`
|
|
274
|
+
- `steps`
|
|
275
|
+
|
|
276
|
+
Examples:
|
|
277
|
+
|
|
278
|
+
- `params.taskKey`
|
|
279
|
+
- `flow.autoReviewFixExtraPrompt`
|
|
280
|
+
- `context.cwd`
|
|
281
|
+
- `repeat.iteration`
|
|
282
|
+
- `steps.fetch_jira.outputs.outputFile`
|
|
283
|
+
|
|
284
|
+
`steps.*` refs are validated against previously available steps. A step cannot depend on a later step.
|
|
285
|
+
|
|
286
|
+
### `artifact`
|
|
287
|
+
|
|
288
|
+
Resolves the path to a single known artifact kind.
|
|
289
|
+
|
|
290
|
+
Example:
|
|
291
|
+
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"artifact": {
|
|
295
|
+
"kind": "plan-file",
|
|
296
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
This computes a path only. It does not assert that the file exists.
|
|
302
|
+
|
|
303
|
+
### `artifactList`
|
|
304
|
+
|
|
305
|
+
Resolves to a list of artifact paths for a known artifact-list kind.
|
|
306
|
+
|
|
307
|
+
Example:
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"artifactList": {
|
|
312
|
+
"kind": "plan-artifacts",
|
|
313
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### `template`
|
|
319
|
+
|
|
320
|
+
Interpolates a local string template using resolved variables.
|
|
321
|
+
|
|
322
|
+
### `appendPrompt`
|
|
323
|
+
|
|
324
|
+
Builds prompt-like text by appending `suffix` to an optional `base`.
|
|
325
|
+
|
|
326
|
+
### `add`
|
|
327
|
+
|
|
328
|
+
Resolves a list of values and adds them numerically.
|
|
329
|
+
|
|
330
|
+
### `concat`
|
|
331
|
+
|
|
332
|
+
Resolves a list of values and concatenates them as strings.
|
|
333
|
+
|
|
334
|
+
### `list`
|
|
335
|
+
|
|
336
|
+
Resolves a list of values and returns them as an array.
|
|
337
|
+
|
|
338
|
+
## Conditions
|
|
339
|
+
|
|
340
|
+
`when` and `stopFlowIf` use `ConditionSpec`.
|
|
341
|
+
|
|
342
|
+
Supported condition forms:
|
|
343
|
+
|
|
344
|
+
- `{ "ref": "..." }`
|
|
345
|
+
- `{ "not": { ... } }`
|
|
346
|
+
- `{ "all": [ ... ] }`
|
|
347
|
+
- `{ "any": [ ... ] }`
|
|
348
|
+
- `{ "equals": [valueA, valueB] }`
|
|
349
|
+
- `{ "exists": valueSpec }`
|
|
350
|
+
|
|
351
|
+
Conditions are evaluated at runtime after all referenced values have been resolved.
|
|
352
|
+
|
|
353
|
+
## Expectations
|
|
354
|
+
|
|
355
|
+
`expect` defines postconditions for a completed step.
|
|
356
|
+
|
|
357
|
+
Currently supported expectation kinds:
|
|
358
|
+
|
|
359
|
+
- `require-artifacts`
|
|
360
|
+
- `require-structured-artifacts`
|
|
361
|
+
- `require-file`
|
|
362
|
+
- `step-output`
|
|
363
|
+
|
|
364
|
+
### `require-artifacts`
|
|
365
|
+
|
|
366
|
+
Expects a resolved string array of file paths and fails if required artifacts are missing.
|
|
367
|
+
|
|
368
|
+
### `require-structured-artifacts`
|
|
369
|
+
|
|
370
|
+
Expects a list of `{ path, schemaId }` items and validates each JSON artifact against the registered structured-artifact schema.
|
|
371
|
+
|
|
372
|
+
### `require-file`
|
|
373
|
+
|
|
374
|
+
Expects a single path to exist.
|
|
375
|
+
|
|
376
|
+
### `step-output`
|
|
377
|
+
|
|
378
|
+
Checks a runtime value from execution state. It can either:
|
|
379
|
+
|
|
380
|
+
- assert truthiness of `value`
|
|
381
|
+
- compare `value` to `equals`
|
|
382
|
+
|
|
383
|
+
Important detail: `step-output` is evaluated against current execution state, not against serialized persisted auto state on disk.
|
|
384
|
+
|
|
385
|
+
## `after` Actions
|
|
386
|
+
|
|
387
|
+
`after` performs post-step side effects after a successful step.
|
|
388
|
+
|
|
389
|
+
Currently supported action:
|
|
390
|
+
|
|
391
|
+
- `set-summary-from-file`
|
|
392
|
+
|
|
393
|
+
Example:
|
|
394
|
+
|
|
395
|
+
```json
|
|
396
|
+
{
|
|
397
|
+
"kind": "set-summary-from-file",
|
|
398
|
+
"path": {
|
|
399
|
+
"artifact": {
|
|
400
|
+
"kind": "task-summary-file",
|
|
401
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
This reads the file and updates runtime summary state through `context.setSummary(...)`.
|
|
408
|
+
|
|
409
|
+
The target file does not have to be a dedicated `task-summary-file`. Any markdown artifact can be published into the runtime summary pane this way. In the built-in flows, for example:
|
|
410
|
+
|
|
411
|
+
- `bug-analyze` can publish a cached task summary markdown artifact
|
|
412
|
+
- `normalize-task-source` publishes the normalized task-context markdown artifact
|
|
413
|
+
|
|
414
|
+
From the operator's perspective, the TUI summary pane is therefore a generic runtime summary surface populated by flow specs, not a hard-coded view of one artifact kind.
|
|
415
|
+
|
|
416
|
+
## Nested Flows with `flow-run`
|
|
417
|
+
|
|
418
|
+
The `flow-run` node executes another declarative flow by file name.
|
|
419
|
+
|
|
420
|
+
Example:
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"id": "run_review_loop",
|
|
425
|
+
"node": "flow-run",
|
|
426
|
+
"params": {
|
|
427
|
+
"fileName": { "const": "review-loop.json" },
|
|
428
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Resolution rules:
|
|
434
|
+
|
|
435
|
+
- if the file name matches exactly one built-in flow spec, it is used
|
|
436
|
+
- if it matches exactly one project-local flow spec, it is used
|
|
437
|
+
- ambiguous names fail validation/runtime
|
|
438
|
+
- constant `fileName` values are validated up front
|
|
439
|
+
|
|
440
|
+
Important implementation detail: `flow-run` is not always a pure parameter passthrough. For some built-in nested flow kinds, the runtime enriches the child flow params from scope-local artifact contracts before execution. In particular:
|
|
441
|
+
|
|
442
|
+
- `design-review-flow` resolves the latest planning bundle plus optional normalized task context, Jira context, planning answers, and manual task input
|
|
443
|
+
- `plan-revise-flow` resolves the latest design-review verdict, source planning artifacts, optional normalized task context, Jira context, planning answers, and manual task input
|
|
444
|
+
- `review-flow` resolves the latest planning artifacts plus optional normalized task context, Jira context, and manual task input
|
|
445
|
+
|
|
446
|
+
This contract injection is what allows child specs to reference params such as `params.designFile`, `params.planJsonFile`, or `params.taskContextJsonFile` without each caller having to wire every artifact path manually.
|
|
447
|
+
|
|
448
|
+
## Persisted State vs Runtime State
|
|
449
|
+
|
|
450
|
+
Declarative flow execution uses two different layers of state:
|
|
451
|
+
|
|
452
|
+
- runtime execution state
|
|
453
|
+
- persisted resumable state
|
|
454
|
+
|
|
455
|
+
Runtime execution state includes:
|
|
456
|
+
|
|
457
|
+
- phase and step statuses
|
|
458
|
+
- step `value`
|
|
459
|
+
- step `outputs`
|
|
460
|
+
- repeat variables
|
|
461
|
+
- termination flags
|
|
462
|
+
|
|
463
|
+
Persisted resumable state is intentionally smaller and is used mainly for long-running resumable flows such as `auto-golang`.
|
|
464
|
+
|
|
465
|
+
Persisted state keeps:
|
|
466
|
+
|
|
467
|
+
- statuses
|
|
468
|
+
- timestamps
|
|
469
|
+
- repeat variables
|
|
470
|
+
- stop/termination markers
|
|
471
|
+
- selected launch profile
|
|
472
|
+
|
|
473
|
+
Large prompt outputs and step payloads are not serialized there.
|
|
474
|
+
|
|
475
|
+
That split matters operationally:
|
|
476
|
+
|
|
477
|
+
- runtime state is rich enough for intra-run references and step chaining
|
|
478
|
+
- persisted state is compact enough for resumable harness execution
|
|
479
|
+
- the TUI and automation logic can expose flow progress without depending on raw agent transcripts
|
|
480
|
+
|
|
481
|
+
## Minimal Example
|
|
482
|
+
|
|
483
|
+
```json
|
|
484
|
+
{
|
|
485
|
+
"kind": "flow",
|
|
486
|
+
"version": 1,
|
|
487
|
+
"constants": {
|
|
488
|
+
"summaryTitle": "Planning summary"
|
|
489
|
+
},
|
|
490
|
+
"phases": [
|
|
491
|
+
{
|
|
492
|
+
"id": "plan",
|
|
493
|
+
"steps": [
|
|
494
|
+
{
|
|
495
|
+
"id": "fetch_jira",
|
|
496
|
+
"node": "jira-fetch",
|
|
497
|
+
"params": {
|
|
498
|
+
"jiraApiUrl": { "ref": "params.jiraApiUrl" },
|
|
499
|
+
"outputFile": {
|
|
500
|
+
"artifact": {
|
|
501
|
+
"kind": "jira-task-file",
|
|
502
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
"expect": [
|
|
507
|
+
{
|
|
508
|
+
"kind": "require-file",
|
|
509
|
+
"path": {
|
|
510
|
+
"artifact": {
|
|
511
|
+
"kind": "jira-task-file",
|
|
512
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
513
|
+
}
|
|
514
|
+
},
|
|
515
|
+
"message": "Jira fetch node did not produce the Jira task file."
|
|
516
|
+
}
|
|
517
|
+
]
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
"id": "run_codex_plan",
|
|
521
|
+
"node": "codex-prompt",
|
|
522
|
+
"prompt": {
|
|
523
|
+
"templateRef": "plan",
|
|
524
|
+
"vars": {
|
|
525
|
+
"jira_task_file": {
|
|
526
|
+
"artifact": {
|
|
527
|
+
"kind": "jira-task-file",
|
|
528
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
},
|
|
532
|
+
"extraPrompt": { "ref": "params.extraPrompt" },
|
|
533
|
+
"format": "task-prompt"
|
|
534
|
+
},
|
|
535
|
+
"params": {
|
|
536
|
+
"labelText": { "const": "Running Codex planning mode" }
|
|
537
|
+
},
|
|
538
|
+
"expect": [
|
|
539
|
+
{
|
|
540
|
+
"kind": "require-artifacts",
|
|
541
|
+
"paths": {
|
|
542
|
+
"artifactList": {
|
|
543
|
+
"kind": "plan-artifacts",
|
|
544
|
+
"taskKey": { "ref": "params.taskKey" }
|
|
545
|
+
}
|
|
546
|
+
},
|
|
547
|
+
"message": "Plan mode did not produce the required artifacts."
|
|
548
|
+
}
|
|
549
|
+
]
|
|
550
|
+
}
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
]
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## Practical Guidance
|
|
558
|
+
|
|
559
|
+
- Use flow JSON to describe orchestration, not subprocess details.
|
|
560
|
+
- Put executor-specific behavior into nodes and executors, not into ad-hoc flow fields.
|
|
561
|
+
- Use `expect` to define postconditions explicitly instead of relying on implicit side effects.
|
|
562
|
+
- Prefer structured JSON artifacts for machine-readable contracts between stages.
|
|
563
|
+
- Keep nested flow file names unique if you plan to call them via `flow-run`.
|
|
564
|
+
- When changing the format, update `spec-types.ts`, validator, resolver, and this document together.
|
|
565
|
+
- When designing a new workflow, think in harness terms first: operator-visible phases, durable artifacts, explicit postconditions, and resumability boundaries.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"kind": "claude-example-flow",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "Project-local reference flow for the Claude example plugin.",
|
|
5
|
+
"phases": [
|
|
6
|
+
{
|
|
7
|
+
"id": "example",
|
|
8
|
+
"steps": [
|
|
9
|
+
{
|
|
10
|
+
"id": "run_claude_prompt",
|
|
11
|
+
"node": "llm-prompt",
|
|
12
|
+
"prompt": {
|
|
13
|
+
"inlineTemplate": "Use the current workspace. Create the JSON file `.agentweaver/.artifacts/examples/claude-example-proof.json` with exactly this shape: `{ \"status\": \"ok\", \"executor\": \"claude\", \"message\": \"<one short sentence proving the Claude example plugin executed through llm-prompt>\", \"model\": \"<the exact model name you used, or an empty string if unavailable>\" }`. Write valid JSON only to that file. After the file is written, reply with exactly `wrote .agentweaver/.artifacts/examples/claude-example-proof.json`."
|
|
14
|
+
},
|
|
15
|
+
"params": {
|
|
16
|
+
"labelText": {
|
|
17
|
+
"const": "Run Claude via llm-prompt"
|
|
18
|
+
},
|
|
19
|
+
"executor": {
|
|
20
|
+
"const": "claude"
|
|
21
|
+
},
|
|
22
|
+
"requiredArtifacts": {
|
|
23
|
+
"list": [
|
|
24
|
+
{
|
|
25
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"missingArtifactsMessage": {
|
|
30
|
+
"const": "The Claude example flow requires Claude to write the fixed proof artifact."
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"expect": [
|
|
34
|
+
{
|
|
35
|
+
"kind": "require-artifacts",
|
|
36
|
+
"paths": {
|
|
37
|
+
"list": [
|
|
38
|
+
{
|
|
39
|
+
"const": ".agentweaver/.artifacts/examples/claude-example-proof.json"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"message": "The Claude example flow must write the fixed proof artifact."
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|