Flows
A Flow plans and tracks one execution toward its Goal Steps.
Goals and Planning
A Flow is one execution toward its Goal Steps. Its initial values seed the state, and the Goals tell Argyll which outcomes to produce. Argyll follows the registered Attribute dependencies backward from those Goals to build an Execution Plan: the Steps and dependencies selected for that run.
Goals form a chain of fallback Goal sets. In the UI, the button adds a fallback to try if the current set cannot complete:
"goals": {
"steps": ["ship-order", "send-invoice"],
"else": {"steps": ["queue-for-review"]}
}
Every set in the chain must name at least one Goal in steps. Omit else when there is no fallback; an empty steps array is invalid at any link.
Every Goal in a set must complete or be skipped. Argyll pursues that set first and moves to the set in else only when the current set can no longer complete. The next set reuses every Step and Attribute that already completed, so shared dependencies and Goals repeated across sets run once. Only the work the current set needs starts, and once a set completes the later sets never run.
A Goal skipped because its Step predicate is false counts toward completion and does not itself trigger fallback. Required-input matching is different: if every Goal in a set is pruned because no required input value matches, Argyll advances to the fallback. If only some Goals are pruned this way, the set can still complete when its remaining Goals complete or are skipped.
The Execution Plan covers every Goal set. Its required inputs combine what each set needs from initial state, so every fallback is ready before the Flow starts. When Rollback on Failure is enabled, Argyll compensates succeeded Work Items from Steps with compensated handling that the winning set does not use.
Flow Execution
When a Flow starts, Argyll compiles its Execution Plan and identifies the Steps whose inputs are already available. Those Steps run in parallel within their configured limits. Each committed result may satisfy another Step’s inputs, so execution advances through the dependency graph until a Goal set completes or every Goal set becomes unreachable.
Flow Lifecycle
A Flow moves through three phases:
Active: Steps are running, events are being recorded, the Flow is progressing toward its Goals.
Terminal (completed or failed): The outcome is decided and available to callers. Either a Goal set completed or no Goal set can complete. Work that was already active continues to report its result, and compensation can continue after the outcome, preserving the complete execution history.
Deactivated: The Flow is terminal, all active and compensating work has settled, and its parent has released it. Deactivation marks the end of the Flow’s side-effect history.
A Sub-Flow reports its outcome to its parent in the same commit that settles it. The child stays active while its parent can still request rollback. When the parent deactivates, eligible children deactivate with it, and a child whose work is still draining deactivates once that work settles.
The full Flow state and terminal events report completed or failed as soon as the outcome commits. The lightweight status and query indexes continue to report active until deactivation, then publish the final status after all remaining work has settled.
Flow State
Every Flow has explicit state that you can inspect at any time:
- What Steps have executed and what status they reached
- What outputs each Step produced
- What Steps are still pending
- Why the Flow is in its current state
On completion, the Flow’s result merges only the outputs of the winning set’s Goal Steps. Outputs from other completed Steps, including abandoned Goals, remain in the execution history but are not included in result. A Flow Step maps its child Flow’s winning result back to the parent, so the fallback Goals must provide any outputs the parent requires.
Reusable Flows
A Flow Step packages a reusable set of Goals behind the Step contract. Its inputs initialize the child Flow, and its mapped outputs return child results to the parent Flow.
The child Execution Plan is computed ahead of execution from the parent Step’s declared input contract. Execution uses that fixed plan; a missing input does not trigger replanning or pull in additional Steps. Inputs actually supplied to the child become its initial state and freeze those Attribute names.
A started Flow Step always has its child Flow recorded, since both commit together.
A Flow Step may name a Space to restrict planning for its child Flow. Every configured Goal must belong to that Space. While the Flow Step holds that reference, Argyll rejects deletion of the Space or Goal and rejects selector or tag changes that would remove a Goal from the Space.