stageflow 0.16.0 → 0.18.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.
- package/README.md +2 -4
- package/dist/agent/claudeTools.d.ts +1 -4
- package/dist/agent/claudeTools.js +1 -6
- package/dist/agent/fakeAgent.js +4 -5
- package/dist/agent/piAdapter.js +1 -14
- package/dist/config/cloneChain.d.ts +12 -0
- package/dist/config/cloneChain.js +322 -0
- package/dist/config/createPipeline.js +101 -21
- package/dist/config/createStage.js +7 -0
- package/dist/config/loadOutcome.d.ts +1 -0
- package/dist/config/loadPipeline.d.ts +2 -0
- package/dist/config/loadPipeline.js +34 -22
- package/dist/config/loadStage.d.ts +2 -0
- package/dist/config/loadStage.js +135 -125
- package/dist/config/migrateYaml.js +14 -3
- package/dist/config/normalizePipelineStageEntry.d.ts +5 -9
- package/dist/config/normalizePipelineStageEntry.js +133 -60
- package/dist/config/parsePreEmitChecks.js +2 -2
- package/dist/config/pipelineNeeds.d.ts +15 -2
- package/dist/config/pipelineNeeds.js +86 -4
- package/dist/config/pipelineRoute.d.ts +46 -0
- package/dist/config/pipelineRoute.js +215 -0
- package/dist/config/pipelineStageKeys.d.ts +2 -0
- package/dist/config/pipelineStageKeys.js +15 -4
- package/dist/config/printTargetYaml.js +18 -12
- package/dist/config/resolveForkEmitContext.d.ts +1 -1
- package/dist/config/resolveForkEmitContext.js +3 -26
- package/dist/config/resolvePipelineDag.d.ts +1 -3
- package/dist/config/resolvePipelineDag.js +143 -186
- package/dist/config/routeIf.d.ts +24 -0
- package/dist/config/routeIf.js +247 -0
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +5 -3
- package/dist/config/yamlDialect.d.ts +5 -8
- package/dist/config/yamlDialect.js +37 -29
- package/dist/envelope/check.d.ts +0 -2
- package/dist/envelope/check.js +1 -57
- package/dist/envelope/feedbackLoop.js +0 -3
- package/dist/envelope/forkChoice.js +1 -1
- package/dist/envelope/payloadSchema.d.ts +14 -0
- package/dist/envelope/payloadSchema.js +87 -2
- package/dist/mcp/catalogTools.js +1 -2
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/projection/projectRun.d.ts +0 -2
- package/dist/projection/projectRun.js +0 -3
- package/dist/prompt/priorEnvelope.js +1 -1
- package/dist/runstore/stageInstanceId.d.ts +1 -0
- package/dist/runstore/stageInstanceId.js +9 -0
- package/dist/runtime/cloneSchedule.d.ts +16 -33
- package/dist/runtime/cloneSchedule.js +155 -236
- package/dist/runtime/envelopeRouting.js +43 -94
- package/dist/runtime/forkGeneration.d.ts +2 -2
- package/dist/runtime/forkGeneration.js +29 -15
- package/dist/runtime/joinReadiness.d.ts +16 -0
- package/dist/runtime/joinReadiness.js +156 -0
- package/dist/runtime/pipelineScheduler.d.ts +0 -3
- package/dist/runtime/pipelineScheduler.js +81 -65
- package/dist/runtime/routeIfEval.d.ts +3 -0
- package/dist/runtime/routeIfEval.js +94 -0
- package/dist/runtime/runRetryCoordinator.js +0 -4
- package/dist/runtime/stageAttemptBootstrap.js +60 -11
- package/dist/runtime/taskInput.js +1 -13
- package/dist/tools/emitStageEnvelope.d.ts +2 -3
- package/dist/tools/emitStageEnvelope.js +1 -65
- package/dist/types/envelope.d.ts +0 -2
- package/dist/types/forkChoice.d.ts +0 -16
- package/dist/types/pipeline.d.ts +86 -27
- package/dist/types/stage.d.ts +11 -7
- package/dist/ui/assets/{index-D2Wt8hwH.css → index-DsgVjLUS.css} +1 -1
- package/dist/ui/assets/{index-XWJovnp7.js → index-DwKGaQvQ.js} +13 -12
- package/dist/ui/index.html +2 -2
- package/package.json +2 -1
- package/skills/stageflow-author/SKILL.md +4 -4
- package/skills/stageflow-author/assets/examples/branch-decision/hotfix.yaml +10 -2
- package/skills/stageflow-author/assets/examples/branch-decision/release-gate.pipeline.yaml +12 -4
- package/skills/stageflow-author/assets/examples/branch-decision/run-tests.yaml +6 -4
- package/skills/stageflow-author/assets/examples/branch-decision/ship.yaml +9 -1
- package/skills/stageflow-author/assets/examples/linear-review/draft.yaml +3 -0
- package/skills/stageflow-author/assets/examples/linear-review/publish.yaml +8 -0
- package/skills/stageflow-author/assets/examples/linear-review/review-loop.pipeline.yaml +5 -2
- package/skills/stageflow-author/assets/examples/linear-review/review.yaml +8 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/gather.yaml +3 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml +5 -2
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/send.yaml +8 -0
- package/skills/stageflow-author/assets/examples/non-sdlc-digest/summarize.yaml +8 -0
- package/skills/stageflow-author/references/catalog-mapping.md +159 -50
- package/skills/stageflow-author/references/catalog-write-conventions.md +3 -3
- package/skills/stageflow-author/references/stage-prompt-template.md +57 -17
- package/skills/stageflow-session-capture/SKILL.md +2 -2
- package/skills/stageflow-session-capture/assets/example-pipeline/example.pipeline.yaml +3 -1
- package/skills/stageflow-session-capture/assets/example-pipeline/implement.yaml +15 -0
- package/skills/stageflow-session-capture/assets/example-pipeline/research.yaml +3 -0
- package/skills/stageflow-session-capture/references/catalog-authoring.md +4 -2
- package/dist/envelope/cloneForks.d.ts +0 -2
- package/dist/envelope/cloneForks.js +0 -77
package/dist/ui/index.html
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&display=swap" />
|
|
14
14
|
<link rel="icon" type="image/svg+xml" href="/stageflow-icon.svg" />
|
|
15
15
|
<title>Stageflow</title>
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-DwKGaQvQ.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DsgVjLUS.css">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stageflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Stageflow — CLI pipeline runtime for configurable stages on Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"test": "vitest run",
|
|
38
38
|
"test:watch": "vitest",
|
|
39
39
|
"dev": "tsx src/cli.ts",
|
|
40
|
+
"dev:watch": "PI_CURSOR_SETTING_SOURCES=all STAGEFLOW_ACTIVITY_VERBOSE=1 tsx watch src/cli.ts ui",
|
|
40
41
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
41
42
|
"ui:dev": "npm run dev -w ui",
|
|
42
43
|
"ui:build": "npm run build -w ui && npm run copy:ui-dist",
|
|
@@ -37,7 +37,7 @@ Ask until you can name every step, how they sequence, any decision point, and an
|
|
|
37
37
|
|
|
38
38
|
Read [`references/catalog-mapping.md`](references/catalog-mapping.md). Apply those rules to the confirmed structure. Read [`references/stage-prompt-template.md`](references/stage-prompt-template.md) for each stage's `system_prompt`, optional `model`, `io`, `verify`, and `gate_kinds`. Apply the Anti-patterns section below while mapping. When the human needs hard advance gates, plan body `verify` and wiring `on_verify_fail`. When a review can demand changes, include an address-feedback stage before approve/ship.
|
|
39
39
|
|
|
40
|
-
**Done when** you have a pipeline id, one stage id per step, `
|
|
40
|
+
**Done when** you have a pipeline id, one stage id per step, `route` / `entry` wiring (optional `if`, `{ type: loop }`, sealed Clone Chain when the human wants one run per list item), a prompt plan per stage, and any `verify` / `on_verify_fail` / remediation stages the structure requires.
|
|
41
41
|
|
|
42
42
|
## Anti-patterns
|
|
43
43
|
|
|
@@ -45,15 +45,15 @@ Author these contracts explicitly. They come from long runs that failed after ho
|
|
|
45
45
|
|
|
46
46
|
| Always do | How |
|
|
47
47
|
|---|---|
|
|
48
|
-
| End every attempt on a tool call | Prompt: last call is `emit_stage_envelope`, or `ask_operator` while waiting on HITL.
|
|
48
|
+
| End every attempt on a tool call | Prompt: last call is `emit_stage_envelope`, or `ask_operator` while waiting on HITL. |
|
|
49
49
|
| Land required files in the attempt artifact dir | Prompt `write_stage_artifact`. Body `verify` with `type: artifact` and `when` including `after`. `ask_operator` `artifact_backed` references that same path. |
|
|
50
50
|
| Make implement stages change the checkout | Body `verify` `checkout_changes` + `path_fields`; `io.output.schema` with required checkout-relative path arrays. Exploration-only is its own stage or a failure emit. |
|
|
51
51
|
| Hand successors clean envelopes | `summary` / `payload` = outcomes and artifact pointers only. Name required `io.output.schema` fields in the prompt. |
|
|
52
52
|
| Give review blockers a place to land | Wire `review → address-feedback → approve/ship`. Put `verdict` / `blocking_findings` (or equivalent) in the review `io.output.schema`. |
|
|
53
53
|
| Bind success to the full checklist | If a plan lists N commands, success requires all of them in `commands_run` with exit 0. Cheap checks first; slow suites last or in a verify stage. Size `timeout_ms` to the work. |
|
|
54
|
-
| Use configured models on every sibling | Same configured `model` family after
|
|
54
|
+
| Use configured models on every sibling | Same configured `model` family after fan-out unless the human asks otherwise. Reliable model on publish/PR stages. |
|
|
55
55
|
| Finish publish in the accept attempt | After `artifact_backed` accept: side effects (commit/push/PR) → final artifact → emit in the same attempt. Fix emit/schema errors by re-emitting. |
|
|
56
|
-
|
|
|
56
|
+
| Author a sealed Clone Chain | One run per list item is emitter → clone child → Join. Never write `clonable`, `clone_forks`, or emit-time `skip` / `once` / `fanout`. See [YAML catalog — Clone Chain](../../docs/yaml-catalog.md#clone-chain). |
|
|
57
57
|
|
|
58
58
|
Throwaway checkout deliverables (HTML spike, scratch file): prompt builtin `write` at a checkout-relative path, `artifacts: []` on emit, path in `payload`.
|
|
59
59
|
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
id: hotfix
|
|
2
2
|
system_prompt: |
|
|
3
|
-
Take the
|
|
4
|
-
|
|
3
|
+
Take the prior envelope (payload.ready is false) and repair the work it
|
|
4
|
+
describes.
|
|
5
5
|
|
|
6
6
|
Write the repair notes via write_stage_artifact (for example hotfix.md).
|
|
7
7
|
|
|
8
8
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
9
9
|
artifacts, and a payload describing what you repaired.
|
|
10
10
|
io:
|
|
11
|
+
input:
|
|
12
|
+
schema:
|
|
13
|
+
type: object
|
|
14
|
+
required:
|
|
15
|
+
- ready
|
|
16
|
+
properties:
|
|
17
|
+
ready:
|
|
18
|
+
type: boolean
|
|
11
19
|
output:
|
|
12
20
|
schema:
|
|
13
21
|
type: object
|
|
@@ -3,14 +3,22 @@ model: anthropic/claude-sonnet-4-5
|
|
|
3
3
|
stages:
|
|
4
4
|
- id: run-tests
|
|
5
5
|
uses: ./run-tests.yaml
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
entry: true
|
|
7
|
+
route:
|
|
8
|
+
- to: ship
|
|
9
|
+
if:
|
|
10
|
+
field: ready
|
|
11
|
+
op: eq
|
|
12
|
+
value: true
|
|
13
|
+
- to: hotfix
|
|
14
|
+
if:
|
|
15
|
+
field: ready
|
|
16
|
+
op: eq
|
|
17
|
+
value: false
|
|
8
18
|
- id: hotfix
|
|
9
19
|
uses: ./hotfix.yaml
|
|
10
|
-
needs: [run-tests]
|
|
11
20
|
- id: ship
|
|
12
21
|
uses: ./ship.yaml
|
|
13
|
-
needs: [run-tests]
|
|
14
22
|
on_verify_fail:
|
|
15
23
|
mode: manual
|
|
16
24
|
retry_safety: side_effecting
|
|
@@ -4,13 +4,15 @@ system_prompt: |
|
|
|
4
4
|
|
|
5
5
|
Write the results via write_stage_artifact (for example results.md).
|
|
6
6
|
|
|
7
|
+
When you can assess readiness, emit a success envelope. Set payload.ready to
|
|
8
|
+
true or false. Do not emit a failure status to express unreadiness.
|
|
9
|
+
|
|
7
10
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
8
11
|
artifacts, and a payload the next stage can use.
|
|
9
|
-
|
|
10
|
-
On a success emit, include fork_choice naming immediate successor id(s) that
|
|
11
|
-
should run. Name only ids listed as this stage's children. select: one →
|
|
12
|
-
exactly one id: hotfix when the results fail, ship when they pass.
|
|
13
12
|
io:
|
|
13
|
+
input:
|
|
14
|
+
schema:
|
|
15
|
+
type: object
|
|
14
16
|
output:
|
|
15
17
|
schema:
|
|
16
18
|
type: object
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id: ship
|
|
2
2
|
system_prompt: |
|
|
3
|
-
Take the
|
|
3
|
+
Take the prior envelope (payload.ready is true) and produce the shippable
|
|
4
4
|
package.
|
|
5
5
|
|
|
6
6
|
Write the package notes via write_stage_artifact (for example ship.md).
|
|
@@ -8,6 +8,14 @@ system_prompt: |
|
|
|
8
8
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
9
9
|
artifacts, and a payload describing what you shipped.
|
|
10
10
|
io:
|
|
11
|
+
input:
|
|
12
|
+
schema:
|
|
13
|
+
type: object
|
|
14
|
+
required:
|
|
15
|
+
- ready
|
|
16
|
+
properties:
|
|
17
|
+
ready:
|
|
18
|
+
type: boolean
|
|
11
19
|
output:
|
|
12
20
|
schema:
|
|
13
21
|
type: object
|
|
@@ -8,6 +8,14 @@ system_prompt: |
|
|
|
8
8
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
9
9
|
artifacts, and a payload describing what you produced.
|
|
10
10
|
io:
|
|
11
|
+
input:
|
|
12
|
+
schema:
|
|
13
|
+
type: object
|
|
14
|
+
required:
|
|
15
|
+
- verdict
|
|
16
|
+
properties:
|
|
17
|
+
verdict:
|
|
18
|
+
type: string
|
|
11
19
|
output:
|
|
12
20
|
schema:
|
|
13
21
|
type: object
|
|
@@ -3,9 +3,13 @@ model: anthropic/claude-sonnet-4-5
|
|
|
3
3
|
stages:
|
|
4
4
|
- id: draft
|
|
5
5
|
uses: ./draft.yaml
|
|
6
|
+
entry: true
|
|
7
|
+
route:
|
|
8
|
+
- to: review
|
|
6
9
|
- id: review
|
|
7
10
|
uses: ./review.yaml
|
|
8
|
-
|
|
11
|
+
route:
|
|
12
|
+
- to: publish
|
|
9
13
|
on_verify_fail:
|
|
10
14
|
mode: repair
|
|
11
15
|
max_attempts: 3
|
|
@@ -13,7 +17,6 @@ stages:
|
|
|
13
17
|
include_failed_checks: true
|
|
14
18
|
- id: publish
|
|
15
19
|
uses: ./publish.yaml
|
|
16
|
-
needs: [review]
|
|
17
20
|
on_verify_fail:
|
|
18
21
|
mode: manual
|
|
19
22
|
retry_safety: side_effecting
|
|
@@ -13,6 +13,14 @@ system_prompt: |
|
|
|
13
13
|
4. Call emit_stage_envelope with an advancing success status only after the
|
|
14
14
|
operator accepts. Never emit before accept.
|
|
15
15
|
io:
|
|
16
|
+
input:
|
|
17
|
+
schema:
|
|
18
|
+
type: object
|
|
19
|
+
required:
|
|
20
|
+
- title
|
|
21
|
+
properties:
|
|
22
|
+
title:
|
|
23
|
+
type: string
|
|
16
24
|
output:
|
|
17
25
|
schema:
|
|
18
26
|
type: object
|
package/skills/stageflow-author/assets/examples/non-sdlc-digest/research-digest.pipeline.yaml
CHANGED
|
@@ -3,12 +3,15 @@ model: anthropic/claude-sonnet-4-5
|
|
|
3
3
|
stages:
|
|
4
4
|
- id: gather
|
|
5
5
|
uses: ./gather.yaml
|
|
6
|
+
entry: true
|
|
7
|
+
route:
|
|
8
|
+
- to: summarize
|
|
6
9
|
- id: summarize
|
|
7
10
|
uses: ./summarize.yaml
|
|
8
|
-
|
|
11
|
+
route:
|
|
12
|
+
- to: send
|
|
9
13
|
- id: send
|
|
10
14
|
uses: ./send.yaml
|
|
11
|
-
needs: [summarize]
|
|
12
15
|
on_verify_fail:
|
|
13
16
|
mode: manual
|
|
14
17
|
retry_safety: side_effecting
|
|
@@ -8,6 +8,14 @@ system_prompt: |
|
|
|
8
8
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
9
9
|
artifacts, and a payload describing who received the digest.
|
|
10
10
|
io:
|
|
11
|
+
input:
|
|
12
|
+
schema:
|
|
13
|
+
type: object
|
|
14
|
+
required:
|
|
15
|
+
- headline
|
|
16
|
+
properties:
|
|
17
|
+
headline:
|
|
18
|
+
type: string
|
|
11
19
|
output:
|
|
12
20
|
schema:
|
|
13
21
|
type: object
|
|
@@ -7,6 +7,14 @@ system_prompt: |
|
|
|
7
7
|
When finished, call emit_stage_envelope exactly once with status, summary,
|
|
8
8
|
artifacts, and a payload the next stage can use.
|
|
9
9
|
io:
|
|
10
|
+
input:
|
|
11
|
+
schema:
|
|
12
|
+
type: object
|
|
13
|
+
required:
|
|
14
|
+
- source_count
|
|
15
|
+
properties:
|
|
16
|
+
source_count:
|
|
17
|
+
type: integer
|
|
10
18
|
output:
|
|
11
19
|
schema:
|
|
12
20
|
type: object
|
|
@@ -16,21 +16,67 @@ Collision handling lives in [`catalog-write-conventions.md`](catalog-write-conve
|
|
|
16
16
|
|
|
17
17
|
## Sequencing
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Write **Author YAML only**:
|
|
20
|
+
|
|
21
|
+
- Wiring: `route` / `entry: true` / `{ type: loop }`
|
|
22
|
+
- Contracts: `io` / `verify` / `on_verify_fail`
|
|
23
|
+
- Every stage body has `io.input.schema` and `io.output.schema`
|
|
24
|
+
- Sequential and fan-in edges: consumer `io.input` must be a structural subset of **each** parent's `io.output`
|
|
25
|
+
|
|
26
|
+
Wiring is declared on the **source** stage. Children do not list parents. A pipeline that uses `route` must mark at least one `entry: true` root.
|
|
27
|
+
|
|
28
|
+
`route` is a list of entries. Forward entries name `to:`, optional `on:`, optional `if`. Load rejects `needs`, `fork`, `feedback_loop`, `route_select`, and `allow_none`.
|
|
20
29
|
|
|
21
30
|
| Human says | Pipeline shape |
|
|
22
31
|
|---|---|
|
|
23
|
-
| Steps in order |
|
|
24
|
-
| Steps happen together |
|
|
25
|
-
| A later step waits for two or more earlier steps |
|
|
26
|
-
| Exactly one
|
|
27
|
-
|
|
|
32
|
+
| Steps in order | First stage `entry: true`. Each source lists `route: [{ to: next }]`. |
|
|
33
|
+
| Steps happen together | Parent lists multiple `to:` with no `if`. Both run after the parent succeeds. |
|
|
34
|
+
| A later step waits for two or more earlier steps | Each parent lists `to: join`. The join does not declare parents. |
|
|
35
|
+
| Exactly one of several successors should run | Source lists every `to:` with mutually exclusive `if`s on a required payload field. Agent emits that field; it does not name successor ids. |
|
|
36
|
+
| Optional extra successor | `if` on that `to:`. Keep an ungated sibling if something should always run. |
|
|
37
|
+
| Review can send work back | Source `route` includes `{ type: loop, to: ancestor, max_replays, on_max_replays, replay_session }`. Success emit includes envelope `feedback_loop`. |
|
|
38
|
+
| One run per list item | Sealed [Clone Chain](../../../docs/yaml-catalog.md#clone-chain): emitter → clone child → Join. Emitter output has exactly one array of a named `$ref`; the clone child's entire input is that `$ref`. Emitter pipeline entry has `clone_cap` and `clone_mode`. |
|
|
28
39
|
|
|
29
|
-
|
|
40
|
+
A review, approval, or sign-off step is a gated stage: put `gate_kinds` on that stage file and follow [`stage-prompt-template.md`](stage-prompt-template.md).
|
|
30
41
|
|
|
31
|
-
|
|
42
|
+
### `on:` (skip-cascade policy, not a launch)
|
|
32
43
|
|
|
33
|
-
|
|
44
|
+
Default is succeeded-only. Omit `on:` unless you need to opt an edge out of skip-cascade.
|
|
45
|
+
|
|
46
|
+
Including `failed` or `skipped` in `on:` opts that edge out of skip-cascade. It does **not** launch a child from a skipped or failed parent.
|
|
47
|
+
|
|
48
|
+
- Single-parent: launch still requires a **succeeded** parent. A skipped parent skip-cascades children whose `on` does **not** include `skipped`. Including `skipped` only prevents cascade; the child stays pending.
|
|
49
|
+
- Multi-parent Join (two or more parents each listing `to:` the same child): never skip-cascaded from one parent. Wait until every parent is terminal. Runs if at least one parent succeeded (skipped siblings do not block). Stays pending if any parent failed (even if `on` lists `failed`). Force-skipped if every parent skipped.
|
|
50
|
+
|
|
51
|
+
For exclusive branching after a check, emit **success** with a required discriminator in `io.output.schema` and gate successors with `if`. `on: [failed]` does not mean “run hotfix when tests fail” — that child will not launch.
|
|
52
|
+
|
|
53
|
+
### `if` (runtime gate after success)
|
|
54
|
+
|
|
55
|
+
Evaluated after the source **succeeds**, against that source's output payload only.
|
|
56
|
+
|
|
57
|
+
Leaf `{ field, op, value }` or composition `{ all: [...] }` | `{ any: [...] }` | `{ not: {...} }`.
|
|
58
|
+
|
|
59
|
+
Operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `not_in`. Type-strict (`1` is not `"1"`).
|
|
60
|
+
|
|
61
|
+
`field` is a dot-separated path; every segment must be a **required** object property in the source `io.output.schema`.
|
|
62
|
+
|
|
63
|
+
Two matching `if`s both fire (not first-match-wins).
|
|
64
|
+
|
|
65
|
+
When every forward `to:` on a stage has `if`, validate warns `pipeline.route_all_gated` (`ok: true`; `--strict` does not promote). That is acceptable for exclusive branches.
|
|
66
|
+
|
|
67
|
+
`if` is illegal on `{ type: loop }`, or combined with `on` other than succeeded-only.
|
|
68
|
+
|
|
69
|
+
The completing agent does **not** pick which successors run. Do not emit `fork_choice`.
|
|
70
|
+
|
|
71
|
+
### Loops
|
|
72
|
+
|
|
73
|
+
A review that can send work back to an ancestor is a `{ type: loop }` entry **inside** `route` on the source (the reviewer). Required fields: `type: loop`, `to` (earlier ancestor), `max_replays`, `on_max_replays` (`require_continue` | `wait_for_human`), `replay_session` (`resume` | `new_session`).
|
|
74
|
+
|
|
75
|
+
The **envelope** field on emit is still `feedback_loop` (`continue` / `send_back`). Catalog YAML does not use a `feedback_loop:` key.
|
|
76
|
+
|
|
77
|
+
Optional `replay_safe: false` on stages that must not be replayed (e.g. one-shot submit).
|
|
78
|
+
|
|
79
|
+
Forward-only “review → address-feedback → approve” is still the right map when the human wants a separate fix stage rather than send-back.
|
|
34
80
|
|
|
35
81
|
## Review then fix then approve
|
|
36
82
|
|
|
@@ -40,7 +86,7 @@ When the human wants a review that can demand changes, then a later approve/ship
|
|
|
40
86
|
… → review → address-feedback → approve
|
|
41
87
|
```
|
|
42
88
|
|
|
43
|
-
Do not wire approve/ship as the immediate child of review
|
|
89
|
+
Do not wire approve/ship as the immediate child of review when blockers are expected. The address-feedback stage is the only post-review editor; the approve stage is the backstop. When they want send-back to an earlier stage instead, put `{ type: loop }` on the reviewer's `route`.
|
|
44
90
|
|
|
45
91
|
## Verify and on_verify_fail
|
|
46
92
|
|
|
@@ -56,22 +102,21 @@ Put `verify` on the **stage body** (the `uses:` file or inline entry). Put `on_v
|
|
|
56
102
|
|
|
57
103
|
`on_verify_fail` requires at least one after-phase `verify` item. Check `id` values must be unique within the stage. Check discriminator is `type:` (gate widgets still use `kind:`). Wire these for writer stages and final gates; prompts alone do not enforce them.
|
|
58
104
|
|
|
59
|
-
##
|
|
105
|
+
## Clone Chain
|
|
106
|
+
|
|
107
|
+
A Clone Chain is emitter → clone child → Join. The emitter output has exactly one array of a named `$ref`; the clone child's entire input is that same `$ref`. Put `clone_cap` (integer ≥ 1) and `clone_mode` (`parallel` | `sequential`) on the **emitter pipeline entry**, not on the stage body. N=1 still mints `{child}~1`.
|
|
60
108
|
|
|
61
|
-
|
|
109
|
+
An empty Clone Array or a length above the Clone Cap fails the **emitter emit** — it does not skip the chain or truncate. Gate a zero-item path before the emitter. Both inbound chain edges are sealed: no extra routes, no `if`. The Join may Loop only to a stage before the emitter; the emitter, clone child, and Join are not Loop targets; the clone child cannot Loop or `send_back`.
|
|
62
110
|
|
|
63
|
-
|
|
111
|
+
See [YAML catalog — Clone Chain](../../../docs/yaml-catalog.md#clone-chain) and [`clone-chain-smallest.pipeline.yaml`](../../../tests/fixtures/pipelines/clone-chain-smallest.pipeline.yaml).
|
|
64
112
|
|
|
65
|
-
|
|
66
|
-
- That successor must have at least one child (a join / address-feedback / collect stage). It cannot be a DAG leaf.
|
|
67
|
-
- Parent success emit uses `clone_forks` for that successor (not `fork_choice`). Each clone assignment is a full envelope; validate assignments with `io.input.schema` on the clonable stage body.
|
|
68
|
-
- Join stages that wait on the clonable parent read clone-list `priorEnvelopes`, not `priorEnvelopesByStage`.
|
|
113
|
+
## Rejected clone fields
|
|
69
114
|
|
|
70
|
-
|
|
115
|
+
Do not author `clonable`, `clone_actions`, or envelope `clone_forks`. Do not put `clone_cap` / `clone_mode` on a stage that is not a Clone Chain emitter.
|
|
71
116
|
|
|
72
117
|
## Models
|
|
73
118
|
|
|
74
|
-
Confirm providers before writing. After
|
|
119
|
+
Confirm providers before writing. After fan-out, give every sibling the same configured `model` unless the human asks for different ones. Prefer a reliable configured model on side-effecting final stages.
|
|
75
120
|
|
|
76
121
|
## Worked examples
|
|
77
122
|
|
|
@@ -85,12 +130,23 @@ model: anthropic/claude-sonnet-4-5
|
|
|
85
130
|
stages:
|
|
86
131
|
- id: draft
|
|
87
132
|
uses: ./draft.yaml
|
|
133
|
+
entry: true
|
|
134
|
+
route:
|
|
135
|
+
- to: review
|
|
88
136
|
- id: review
|
|
89
137
|
uses: ./review.yaml
|
|
90
|
-
|
|
138
|
+
route:
|
|
139
|
+
- to: publish
|
|
140
|
+
on_verify_fail:
|
|
141
|
+
mode: repair
|
|
142
|
+
max_attempts: 3
|
|
143
|
+
retry_safety: idempotent
|
|
144
|
+
include_failed_checks: true
|
|
91
145
|
- id: publish
|
|
92
146
|
uses: ./publish.yaml
|
|
93
|
-
|
|
147
|
+
on_verify_fail:
|
|
148
|
+
mode: manual
|
|
149
|
+
retry_safety: side_effecting
|
|
94
150
|
```
|
|
95
151
|
|
|
96
152
|
`review` carries `gate_kinds: [artifact_backed]` and emit-phase `verify` `type: gate`. Full set: [`../assets/examples/linear-review/`](../assets/examples/linear-review/).
|
|
@@ -103,55 +159,78 @@ When review can emit blockers and a later stage approves or ships, insert addres
|
|
|
103
159
|
stages:
|
|
104
160
|
- id: implement
|
|
105
161
|
uses: ./implement.yaml
|
|
162
|
+
entry: true
|
|
163
|
+
route:
|
|
164
|
+
- to: review
|
|
106
165
|
- id: review
|
|
107
166
|
uses: ./review.yaml
|
|
108
|
-
|
|
167
|
+
route:
|
|
168
|
+
- to: address-feedback
|
|
109
169
|
- id: address-feedback
|
|
110
170
|
uses: ./address-feedback.yaml
|
|
111
|
-
|
|
171
|
+
route:
|
|
172
|
+
- to: approve
|
|
112
173
|
- id: approve
|
|
113
174
|
uses: ./approve.yaml
|
|
114
|
-
needs: [address-feedback]
|
|
115
175
|
```
|
|
116
176
|
|
|
117
|
-
Do not
|
|
177
|
+
Do not wire approve/ship as the immediate child of review when blockers are expected.
|
|
118
178
|
|
|
119
|
-
### Release gate (
|
|
179
|
+
### Release gate (exclusive via `if`)
|
|
120
180
|
|
|
121
|
-
|
|
181
|
+
`run-tests` emits **success** with required `ready` boolean. Catalog `if` picks the successor. A failure emit would leave both children unlaunched.
|
|
122
182
|
|
|
123
183
|
```yaml
|
|
124
184
|
id: release-gate
|
|
185
|
+
model: anthropic/claude-sonnet-4-5
|
|
125
186
|
stages:
|
|
126
187
|
- id: run-tests
|
|
127
188
|
uses: ./run-tests.yaml
|
|
128
|
-
|
|
129
|
-
|
|
189
|
+
entry: true
|
|
190
|
+
route:
|
|
191
|
+
- to: ship
|
|
192
|
+
if:
|
|
193
|
+
field: ready
|
|
194
|
+
op: eq
|
|
195
|
+
value: true
|
|
196
|
+
- to: hotfix
|
|
197
|
+
if:
|
|
198
|
+
field: ready
|
|
199
|
+
op: eq
|
|
200
|
+
value: false
|
|
130
201
|
- id: hotfix
|
|
131
202
|
uses: ./hotfix.yaml
|
|
132
|
-
needs: [run-tests]
|
|
133
203
|
- id: ship
|
|
134
204
|
uses: ./ship.yaml
|
|
135
|
-
|
|
205
|
+
on_verify_fail:
|
|
206
|
+
mode: manual
|
|
207
|
+
retry_safety: side_effecting
|
|
136
208
|
```
|
|
137
209
|
|
|
138
210
|
Full set: [`../assets/examples/branch-decision/`](../assets/examples/branch-decision/).
|
|
139
211
|
|
|
140
212
|
### Research digest (linear, non-software)
|
|
141
213
|
|
|
142
|
-
Weekly gather → summarize → send. Same `
|
|
214
|
+
Weekly gather → summarize → send. Same `entry` + `route` chain as the review loop; ids and prompts stay in that domain.
|
|
143
215
|
|
|
144
216
|
```yaml
|
|
145
217
|
id: research-digest
|
|
218
|
+
model: anthropic/claude-sonnet-4-5
|
|
146
219
|
stages:
|
|
147
220
|
- id: gather
|
|
148
221
|
uses: ./gather.yaml
|
|
222
|
+
entry: true
|
|
223
|
+
route:
|
|
224
|
+
- to: summarize
|
|
149
225
|
- id: summarize
|
|
150
226
|
uses: ./summarize.yaml
|
|
151
|
-
|
|
227
|
+
route:
|
|
228
|
+
- to: send
|
|
152
229
|
- id: send
|
|
153
230
|
uses: ./send.yaml
|
|
154
|
-
|
|
231
|
+
on_verify_fail:
|
|
232
|
+
mode: manual
|
|
233
|
+
retry_safety: side_effecting
|
|
155
234
|
```
|
|
156
235
|
|
|
157
236
|
Full set: [`../assets/examples/non-sdlc-digest/`](../assets/examples/non-sdlc-digest/).
|
|
@@ -164,15 +243,17 @@ Full set: [`../assets/examples/non-sdlc-digest/`](../assets/examples/non-sdlc-di
|
|
|
164
243
|
stages:
|
|
165
244
|
- id: intake
|
|
166
245
|
uses: ./intake.yaml
|
|
246
|
+
entry: true
|
|
247
|
+
route:
|
|
248
|
+
- to: collect-quotes
|
|
249
|
+
- to: collect-notes
|
|
167
250
|
- id: collect-quotes
|
|
168
251
|
uses: ./collect-quotes.yaml
|
|
169
|
-
needs: [intake]
|
|
170
252
|
- id: collect-notes
|
|
171
253
|
uses: ./collect-notes.yaml
|
|
172
|
-
needs: [intake]
|
|
173
254
|
```
|
|
174
255
|
|
|
175
|
-
|
|
256
|
+
Both run after intake succeeds. No `if`.
|
|
176
257
|
|
|
177
258
|
### Diamond join
|
|
178
259
|
|
|
@@ -182,37 +263,65 @@ No `fork` field. Both siblings run.
|
|
|
182
263
|
stages:
|
|
183
264
|
- id: clarify
|
|
184
265
|
uses: ./clarify.yaml
|
|
266
|
+
entry: true
|
|
267
|
+
route:
|
|
268
|
+
- to: research
|
|
269
|
+
- to: validation
|
|
185
270
|
- id: research
|
|
186
271
|
uses: ./research.yaml
|
|
187
|
-
|
|
272
|
+
route:
|
|
273
|
+
- to: synthesize
|
|
188
274
|
- id: validation
|
|
189
275
|
uses: ./validation.yaml
|
|
190
|
-
|
|
276
|
+
route:
|
|
277
|
+
- to: synthesize
|
|
191
278
|
- id: synthesize
|
|
192
279
|
uses: ./synthesize.yaml
|
|
193
|
-
needs:
|
|
194
|
-
- research
|
|
195
|
-
- validation
|
|
196
280
|
```
|
|
197
281
|
|
|
198
|
-
`
|
|
282
|
+
The join reads `priorEnvelopesByStage`, not a list of sibling envelopes. A skipped sibling does not block. A failed parent leaves the join pending.
|
|
199
283
|
|
|
200
|
-
###
|
|
284
|
+
### Optional / subset fan-out
|
|
201
285
|
|
|
202
|
-
"Email, post, or both
|
|
286
|
+
"Email, post, or both": list both `to:` with no `if` (both run). To skip a channel, add `if` on that `to:` and put the discriminator in `io.output.schema`. Do not emit `fork_choice`.
|
|
203
287
|
|
|
204
288
|
```yaml
|
|
205
289
|
stages:
|
|
206
290
|
- id: choose-channels
|
|
207
291
|
uses: ./choose-channels.yaml
|
|
208
|
-
|
|
209
|
-
|
|
292
|
+
entry: true
|
|
293
|
+
route:
|
|
294
|
+
- to: email
|
|
295
|
+
- to: post
|
|
210
296
|
- id: email
|
|
211
297
|
uses: ./email.yaml
|
|
212
|
-
needs: [choose-channels]
|
|
213
298
|
- id: post
|
|
214
299
|
uses: ./post.yaml
|
|
215
|
-
needs: [choose-channels]
|
|
216
300
|
```
|
|
217
301
|
|
|
218
|
-
|
|
302
|
+
To skip a channel, add `if` on that `to:` (keep an ungated sibling if the other channel should always run).
|
|
303
|
+
|
|
304
|
+
### Review send-back (loop)
|
|
305
|
+
|
|
306
|
+
```yaml
|
|
307
|
+
stages:
|
|
308
|
+
- id: implement
|
|
309
|
+
uses: ./implement.yaml
|
|
310
|
+
entry: true
|
|
311
|
+
route:
|
|
312
|
+
- to: review
|
|
313
|
+
- id: review
|
|
314
|
+
uses: ./review.yaml
|
|
315
|
+
route:
|
|
316
|
+
- to: submit
|
|
317
|
+
- type: loop
|
|
318
|
+
to: implement
|
|
319
|
+
max_replays: 2
|
|
320
|
+
on_max_replays: require_continue
|
|
321
|
+
replay_session: resume
|
|
322
|
+
- id: submit
|
|
323
|
+
uses: ./submit.yaml
|
|
324
|
+
replay_safe: false
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Success emit from `review` includes envelope `feedback_loop`: `{ action: continue }` or `{ action: send_back, target: implement }`.
|
|
@@ -17,10 +17,10 @@ One directory (or the project root) holds:
|
|
|
17
17
|
|
|
18
18
|
| File | Required fields |
|
|
19
19
|
|---|---|
|
|
20
|
-
| `<pipeline-id>.pipeline.yaml` | `id` matching the filename stem; `stages:` object entries |
|
|
21
|
-
| `<stage-id>.yaml` | `id`, `system_prompt`; `model` when not inherited; `io`
|
|
20
|
+
| `<pipeline-id>.pipeline.yaml` | `id` matching the filename stem; `stages:` array of object entries |
|
|
21
|
+
| `<stage-id>.yaml` | `id`, `system_prompt`; `model` when not inherited; required `io.input.schema` and `io.output.schema`; `verify` / `gate_kinds` when the step needs them |
|
|
22
22
|
|
|
23
|
-
Each pipeline stage entry has `id` and `uses: ./<id>.yaml` (path relative to the pipeline file).
|
|
23
|
+
Each pipeline stage entry has `id` and `uses: ./<id>.yaml` (path relative to the pipeline file). At least one root marks `entry: true`. Sources list forward `route: [{ to: <id> }, …]`. Optional `on:` is skip-cascade policy (default succeeded-only); it does not launch from skipped/failed. Optional `if` gates a successor after the source succeeds (predicate on required `io.output.schema` fields). A review that can send work back adds `{ type: loop, to, max_replays, on_max_replays, replay_session }` inside `route`. A Clone Chain emitter puts `clone_cap` and `clone_mode` on that **pipeline entry**, never on the reusable stage body. Put `on_verify_fail` on the pipeline entry when after-phase `verify` should repair or wait for an operator. Filename stem matches `id`. Optional pipeline-root `model` fills stages that omit `model`. Sequencing rules: [`catalog-mapping.md`](catalog-mapping.md). Catalog load rejects `needs`, `fork`, and `feedback_loop` as YAML keys.
|
|
24
24
|
|
|
25
25
|
## Collisions
|
|
26
26
|
|