Real pipelines are rarely linear. Some steps should run only when a preceding check returns a specific value; others should be skipped entirely based on the deployment environment. Aether models these conditional paths directly in the DAG structure through three complementary mechanisms:Documentation Index
Fetch the complete documentation index at: https://mintlify.com/BabySid/aether/llms.txt
Use this file to discover all available pages before exploring further.
when expressions that guard individual task nodes, continueOn policies that let pipelines survive non-fatal failures, and phaseConditions that let you remap what an executor’s exit code means. Together they give you precise control over execution flow without requiring imperative branching logic in a host program.
The when Field
The when field on a DAG task node is a boolean expression. If it evaluates to false after all of the task’s dependencies complete, the engine sets the task to PhaseSkipped without dispatching it. Downstream nodes that depend on the skipped task are evaluated normally — they check their own when condition and proceed if it passes.
check completes with status: "ok", path-ok runs and path-fail is skipped. Both nodes depend on check, so they both evaluate their when guard at the same moment. The engine dispatches whichever guard returns true and marks the other PhaseSkipped.
Expression Context
when expressions can reference:
- Task outputs:
tasks.<node-name>.outputs.parameters.<param>— the output parameter value of a completed upstream task - Task phase:
tasks.<node-name>.phase— the phase string (e.g."Succeeded","Failed") - Task exit code:
tasks.<node-name>.code— the integer exit code from the executor - Workflow arguments:
inputs.parameters.<name>— values passed at submit time - System variables:
system.os,system.arch— injected by a configuredvars.Source
PhaseSkipped is set exclusively by the engine when a when condition evaluates to false. It cannot be returned by executors and cannot be set via phaseConditions. This distinction is intentional — skipped means “conditionally excluded”, not “failed silently”.OS and Platform Branching
A common use ofwhen is selecting platform-specific execution paths using system variables injected via a vars.Source:
detect-os reads system.os from the engine’s variable source and emits it as an output parameter. The two downstream nodes use that value in their when guards, so exactly one branch runs on any given host.
Failure Propagation with continueOn
By default, a task failure causes the engine to stop scheduling new tasks in that DAG scope and mark the DAG itself as failed. The continueOn field overrides this behavior at two granularities.
Task-Level continueOn
Placed on a task node, continueOn tells the engine that even if this node reaches a non-success phase, its downstream dependents should still be evaluated and potentially dispatched:
step-b fails. Without continueOn, step-c would never run. With continueOn: {failed: true} on step-b, step-c is unblocked and dispatched normally.
DAG-Level continueOn
The continueOn field on the DAG template body prevents the DAG container from transitioning to a failure phase when child task nodes fail:
| Field | Phase guarded |
|---|---|
failed | PhaseFailed — business-level failure from the executor |
error | PhaseError — system-level error (crash, OOM, network) |
timeout | PhaseTimeout — task deadline exceeded |
Combining when and continueOn
when and continueOn work together. A task node can have both: when guards whether it runs at all, while continueOn controls how its outcome affects downstream nodes. A common pattern is a “cleanup” node that runs after either success or failure:
risky-step has continueOn: {failed: true}, it unblocks cleanup regardless of outcome. The when expression explicitly matches both phases, so cleanup runs in either case.
Overriding Phase Mapping with phaseConditions
Executors return an integer ExecCode. The engine maps that code to a Phase by default:
| ExecCode | Default Phase |
|---|---|
0 | Succeeded |
1 | Suspended |
2 | Failed |
3 | Error |
4 | Timeout |
phaseConditions lets you override this mapping with custom boolean expressions. It can be placed on a named task template or on a DAG task node (call site):
succeeded, failed, and error expressions in order. The phase of the first expression that returns true is applied. If none match, the default code-to-phase mapping is used.
phaseConditions is evaluated after the executor returns, before any retry or hook logic runs. Use it to normalize exit codes from external processes or container images that use non-standard codes to signal business outcomes.Skipped vs. Cancelled
Two phases look superficially similar but have distinct semantics:PhaseSkipped
Set by the engine when a
when condition evaluates to false. The task was intentionally excluded from this execution. Skipped tasks are not retried and do not trigger failure hooks.PhaseCancelled
Set by the engine when
Engine.Cancel() is called by the caller. The task was stopped mid-execution. Cancelled tasks are not retried, and the workflow-level onCancel hook fires.phaseConditions — they are exclusively engine-managed states. This separation keeps the phase state machine coherent and prevents executors from expressing engine-level concerns.