Skip to main content

WORKFLOWS

A workflow is a YAML file that orchestrates the execution of model methods and other workflows. Workflows live in the workflows/ directory within a Swamp repository.

File Structure

workflows/
  workflow-e182b5c7-41e7-4c9a-a9f8-455b7bb5ce12.yaml
  workflow-d14de37a-b931-4363-97e9-fe9ec9637b60.yaml

The filename is workflow-{uuid}.yaml.

Top-Level Fields

id: d14de37a-b931-4363-97e9-fe9ec9637b60
name: deploy-pipeline
description: A multi-stage deployment pipeline
trigger:
  schedule: "0 3 * * *"
tags:
  team: platform
inputs:
  type: object
  properties:
    region:
      type: string
      default: us-east-1
  required:
    - region
jobs:
  - name: build
    steps:
      - name: compile
        task:
          type: model_method
          modelIdOrName: builder
          methodName: run
version: 1
reports:
  require:
    - summary
  skip:
    - debug-report

id

Unique identifier for the workflow.

Property Value
Type string (UUID v4)
Required Yes
Default Auto-generated on create
Format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

name

Human-readable name for the workflow.

Property Value
Type string
Required Yes
Default None

Constraints:

  • Minimum 1 character.
  • Must be unique within the repository.
  • Must not contain .., \, or null bytes (path traversal protection).
  • / is only allowed in scoped names matching @[a-z0-9_-]+/[a-z0-9_-]+(\/[a-z0-9_-]+)* (e.g., @team/deploy-pipeline).

description

Human-readable description of the workflow's purpose.

Property Value
Type string
Required No
Default None

trigger

Scheduling configuration for automatic execution.

Property Value
Type object
Required No
Default None

trigger.schedule

Cron expression for recurring execution.

Property Value
Type string
Required No
Format Standard cron (5 fields): minute hour dom month dow

Validated at parse time using the Croner library. Invalid expressions cause a schema validation error.

trigger:
  schedule: "0 3 * * *" # Daily at 3:00 AM
trigger:
  schedule: "*/15 * * * *" # Every 15 minutes
trigger:
  schedule: "0 3,12 * * *" # 3:00 AM and 12:00 PM daily

trigger.inputs

Baseline input values supplied to trigger-fired runs. Trigger-fired runs (scheduled and webhook) have no --input flag, so trigger.inputs provides the values at fire time.

Property Value
Type Record<string, unknown>
Required No
Default None

This is a free values map — the runtime values to inject — distinct from the workflow's inputs block, which is the JSON Schema describing allowed inputs.

trigger:
  schedule: "0 3 * * *"
  inputs:
    projectId: "a6b254a2-0b57-4d0f-bf8b-fef767ab119e"

Values merge as caller inputs > trigger.inputs > schema defaults — the same merge as --input on swamp workflow run. A scheduled run has no caller, so trigger.inputs is the baseline. A webhook run extracts no inputs from its payload (the body is used only for signature verification), so it also takes its baseline from trigger.inputs. The merged values pass through the same coercion, default application, and validation as every other run.

trigger.inputs lets a workflow declare required inputs rather than relying on the schema default, which would apply to every caller. It applies only to trigger-fired runs; a manual swamp workflow run supplies inputs explicitly and is unaffected. See Webhook Triggers for webhook-fired runs.

tags

Key-value labels attached to the workflow.

Property Value
Type Record<string, string>
Required No
Default {}
tags:
  team: platform
  env: production

inputs

JSON Schema definition for structured inputs provided at runtime. Uses the same InputsSchema format as model definition inputs.

Property Value
Type InputsSchema
Required No
Default None
inputs:
  type: object
  properties:
    environments:
      type: array
      description: Target environments
    region:
      type: string
      default: us-east-1
  required:
    - environments

Input values are available in CEL expressions as inputs.* within step task inputs and forEach expressions.

jobs

Ordered list of jobs to execute.

Property Value
Type Job[]
Required Yes
Minimum 1

See Job below.

version

Workflow version number.

Property Value
Type integer
Required No
Default 1

Must be a positive integer.

concurrency

Maximum number of jobs that execute in parallel at each dependency level.

Property Value
Type integer
Required No
Default None

Must be a non-negative integer. When unset or 0, parallelism is unbounded. Jobs and steps can override this value. See Concurrency Resolution Order.

concurrency: 4

target

Default target for all steps. Inherited by jobs and steps unless overridden. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

Mutually exclusive with labels.

labels

Default labels for all steps. Inherited by jobs and steps unless overridden. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type Record<string, string>
Required No
Default None

Mutually exclusive with target.

platform

Default platform for all steps. Inherited by jobs and steps unless overridden. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

queueTimeout

Default queueTimeout for all steps. Inherited by jobs and steps unless overridden. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type number (seconds)
Required No
Default None

affinity

When true, all remote steps in the workflow run on the same worker node. The dispatch service picks a worker for the first placed step via normal target/labels/platform matching, then pins all subsequent placed steps to that same worker for the duration of the workflow run. Inherited by jobs unless overridden. See Workflow Placement — Affinity for behavior details, failure semantics, and the concurrency trade-off.

Property Value
Type boolean
Required No
Default false

Affinity requires placement (target, labels, or platform) to have any effect — without placement, steps run locally and affinity is a no-op (a validation warning is emitted). Mutually exclusive with step-level target overrides within the affinity scope: if a step sets its own target, it opts out of the affinity group.

name: gpu-pipeline
labels:
  gpu: "true"
affinity: true

jobs:
  - name: train
    steps:
      - name: prepare-data
        task:
          type: model_method
          modelIdOrName: preprocessor
          methodName: run
      - name: fit-model
        task:
          type: model_method
          modelIdOrName: trainer
          methodName: run
        dependsOn:
          - step: prepare-data
            condition:
              type: succeeded

Both prepare-data and fit-model run on the same GPU worker — the first step selects the worker, and the second is pinned to it.

reports

Post-execution report selection.

Property Value
Type ReportSelection
Required No
Default None

Uses the same format as model definition reports.

reports:
  require:
    - summary
    - name: deployment-report
      methods:
        - apply
  skip:
    - debug-report

Required reports must resolve or the workflow run fails. The resolution rules are the same as for model definition reports — an unresolvable name logs a warning, writes an error artifact, and counts as a report failure.

swamp workflow resume executes workflow-scope and step-scope reports, including reports.require. Previously, resumed workflows skipped all reports.


Webhook Triggers

A workflow can be triggered by an external HTTP webhook in addition to a trigger.schedule cron. Webhook endpoints are registered on the worker, not in the workflow file, with the --webhook flag of swamp serve:

swamp serve --webhook /hooks/github:my-workflow:$WEBHOOK_SECRET

The flag value is <route>:<workflow>:<secret>. The route must start with /; the secret is everything after the second colon, so it may itself contain colons.

Request contract

A registered route accepts POST requests. Each request must carry an X-Hub-Signature-256 header whose value is sha256=<hex>, where <hex> is the HMAC-SHA256 of the raw request body keyed by the shared secret (the GitHub webhook scheme).

Status Condition
200 Valid signature — the run is queued: { "status": "queued" }
401 Missing or invalid X-Hub-Signature-256 signature
413 Request body exceeds 10 MB
503 The run queue is full (maximum 100 queued runs)

A queued run executes through the same path as scheduled and CLI runs.

Inputs

The request body is used only for signature verification — no inputs are extracted from the payload. A webhook-fired run takes its baseline input values from trigger.inputs, exactly like a scheduled run.


Job

A job groups related steps within a workflow. Jobs with no dependencies on each other execute in parallel.

jobs:
  - name: build
    description: Compile and test
    steps:
      - name: compile
        task:
          type: model_method
          modelIdOrName: builder
          methodName: run
    dependsOn: []
    weight: 0

name

Job name, unique within the workflow.

Property Value
Type string
Required Yes
Minimum 1 char

description

Human-readable description of the job.

Property Value
Type string
Required No
Default None

steps

Ordered list of steps to execute within the job.

Property Value
Type Step[]
Required Yes
Minimum 1

See Step below.

dependsOn

Dependencies on other jobs with trigger conditions.

Property Value
Type JobDependency[]
Required No
Default []

Each element specifies which job to depend on and under what condition:

dependsOn:
  - job: build
    condition:
      type: succeeded

See Trigger Conditions for the full condition schema.

weight

Numeric weight for deterministic ordering of jobs at the same dependency level.

Property Value
Type number
Required No
Default 0

Lower weights execute first. Jobs with the same weight and dependency level are ordered alphabetically by name.

concurrency

Maximum number of steps that execute in parallel at each dependency level within this job. Overrides the workflow-level concurrency.

Property Value
Type integer
Required No
Default None

Must be a non-negative integer. When unset or 0, falls back to the workflow-level value. See Concurrency Resolution Order.

target

Default target for all steps in this job. Overrides the workflow-level target. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

Mutually exclusive with labels.

labels

Default labels for all steps in this job. Overrides the workflow-level labels. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type Record<string, string>
Required No
Default None

Mutually exclusive with target. An explicit labels: {} clears inherited labels — steps in this job run locally unless they set their own placement.

platform

Default platform for all steps in this job. Overrides the workflow-level platform. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

queueTimeout

Default queueTimeout for all steps in this job. Overrides the workflow-level queueTimeout. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type number (seconds)
Required No
Default None

affinity

When true, all remote steps in this job run on the same worker node. Overrides the workflow-level affinity. See Workflow Placement — Affinity for behavior details and failure semantics.

Property Value
Type boolean
Required No
Default None

When unset, falls back to the workflow-level affinity. Set to false explicitly to opt a job out of a workflow-wide affinity group.


Step

A step is a single unit of work within a job. Steps with no dependencies on each other execute in parallel.

steps:
  - name: deploy-env
    description: Deploy to environment
    task:
      type: model_method
      modelIdOrName: deployer
      methodName: apply
    forEach:
      item: env
      in: "${{ inputs.environments }}"
    dependsOn:
      - step: compile
        condition:
          type: succeeded
    weight: 0
    dataOutputOverrides:
      - specName: result
        lifetime: 30d
        garbageCollection: 5
        tags:
          stage: deploy
        vary:
          - environment
    allowFailure: false

name

Step name, unique within the job.

Property Value
Type string
Required Yes
Minimum 1 char

When forEach is used and the step name contains ${{ }} expressions, the name is evaluated with the iteration context to produce unique names per iteration.

description

Human-readable description of the step.

Property Value
Type string
Required No
Default None

task

The work to execute. See Step Task below.

Property Value
Type StepTask
Required Yes

forEach

Iteration configuration. When set, the step expands into one execution per element.

Property Value
Type ForEach
Required No
Default None

See ForEach below.

dependsOn

Dependencies on other steps within the same job.

Property Value
Type StepDependency[]
Required No
Default []
dependsOn:
  - step: compile
    condition:
      type: succeeded

See Trigger Conditions for the full condition schema.

weight

Numeric weight for deterministic ordering of steps at the same dependency level.

Property Value
Type number
Required No
Default 0

Lower weights execute first. Steps with the same weight and dependency level are ordered alphabetically by name.

dataOutputOverrides

Overrides for data output specifications produced by the step's task.

Property Value
Type DataOutputOverride[]
Required No
Default None

See DataOutputOverride below.

allowFailure

When true, a step failure does not fail the job. Subsequent steps with succeeded conditions against this step will not trigger, but completed and always conditions will.

Property Value
Type boolean
Required No
Default false

guard

A CEL expression evaluated before the step executes. When the expression evaluates to a truthy value, the step is skipped. When it evaluates to a falsy value (or is absent), the step executes normally.

Property Value
Type string (CEL expression)
Required No
Default None

The expression is wrapped in ${{ }} and has access to the same context as step task.inputs: inputs, data, model, self, env, vault, file, run. When forEach is active, the iteration variable (self.{item}) is available — the guard evaluates once per iteration, so individual iterations can be skipped independently.

guard: "${{ data.latest('deployer', 'result') }}"

A CEL evaluation error in the guard expression fails the step.

A guarded step that is skipped emits a step_skipped event with reason: "guarded", distinct from reason: "dependency" when a step is skipped due to an unmet dependency condition. Console output shows the skip reason and the guard expression that triggered it:

skipped (guarded) · guard: data.latest("checker", "result").attributes.exitCode == 0

In --json output, the structured step_skipped line includes reason, guardExpression, and guardResult fields:

{
  "type": "step_skipped",
  "step": "deploy-env",
  "reason": "guarded",
  "guardExpression": "data.latest(\"checker\", \"result\").attributes.exitCode == 0",
  "guardResult": true
}

At debug log level, guard evaluation is logged for every guarded step — both when the guard causes a skip and when it evaluates falsy and the step proceeds.

See the CEL Expressions reference for the full expression language. For goal-oriented usage, see Make Workflows Idempotent.

concurrency

Maximum number of steps that execute in parallel at this step's dependency level within the job. Overrides job-level and workflow-level concurrency.

Property Value
Type integer
Required No
Default None

Must be a non-negative integer. When unset or 0, falls back to the job-level value. See Concurrency Resolution Order.

target

Dispatch this step to a specific remote worker by name or instance UUID. Overrides any target inherited from the job or workflow. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

Mutually exclusive with labels.

labels

Dispatch this step to any connected remote worker whose labels are a superset of this selector. Overrides any labels inherited from the job or workflow. An explicit labels: {} clears inherited labels — the step runs locally unless it has other placement fields. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type Record<string, string>
Required No
Default None

Mutually exclusive with target.

platform

Dispatch this step to a worker running the specified operating system. Overrides any platform inherited from the job or workflow. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type string
Required No
Default None

queueTimeout

Override the server's default queue timeout for this step. Overrides any queueTimeout inherited from the job or workflow. See Workflow Placement for the inheritance chain and scheduling behavior.

Property Value
Type number (seconds)
Required No
Default None

Step Task

A step task defines the work a step executes. Four task types are available.

Model Method (model_method)

Invokes a method on a model definition. Two mutually exclusive field sets identify the target model.

modelIdOrName variant

Targets an existing definition by name or UUID.

task:
  type: model_method
  modelIdOrName: deployer
  methodName: apply
  inputs:
    target: "${{ inputs.region }}"
Field Type Required Description
type "model_method" Yes Task type discriminator
modelIdOrName string Yes Model definition name or UUID
methodName string Yes Method to invoke
inputs Record<string, unknown> | string No Input values for the method (record or expression)
globalArgs Record<string, unknown> | string No Global arguments for the model definition

modelType + modelName variant

Targets a model type directly. When no definition with the given name exists, one is created automatically in .swamp/auto-definitions/. inputs values are split between global arguments and method arguments using the type's schemas — method arguments take precedence on ambiguous keys.

task:
  type: model_method
  modelType: "@swamp/aws/ec2/vpc"
  modelName: my-vpc
  methodName: create
  inputs:
    region: us-east-1
    cidr: "10.0.0.0/16"
Field Type Required Description
type "model_method" Yes Task type discriminator
modelType string Yes Model type identifier
modelName string Yes Name for the created definition
methodName string Yes Method to invoke
inputs Record<string, unknown> | string No Input values for the method (record or expression)
globalArgs Record<string, unknown> | string No Global arguments for the model definition

modelName supports CEL template expressions in forEach steps:

- name: scan-${{ self.host }}
  forEach: { item: host, in: "${{ inputs.hosts }}" }
  task:
    type: model_method
    modelType: "@swamp/cve/dirtyfrag"
    modelName: fleet-scanner
    methodName: scanFleet
    inputs:
      host: ${{ self.host }}

Variant constraints

A step must contain exactly one of these field sets. Validation rejects:

  • Both modelIdOrName and modelType present
  • modelType without modelName
  • Neither modelIdOrName nor modelType present

inputs

inputs accepts two forms. The record form is a map of key-value pairs where individual values may contain ${{ }} CEL expressions:

inputs:
  target: "${{ inputs.region }}"
  retries: 3

The expression form is a single ${{ }} CEL expression that evaluates to a record at runtime:

inputs: "${{ self.item.implementation.inputs }}"

The expression must evaluate to a map — the runtime passes the resolved key-value pairs as input values. The two forms are mutually exclusive for a given task.

Both forms are supported on model_method and workflow task types.

globalArgs

globalArgs sets global arguments on the target model definition. It accepts the same two forms as inputs — a literal record or a single expression. Available on model_method tasks only.

task:
  type: model_method
  modelIdOrName: scanner
  methodName: run
  inputs:
    target: "${{ self.host }}"
  globalArgs:
    region: "${{ inputs.region }}"

When using the modelType + modelName variant without globalArgs, keys in inputs are split between global arguments and method arguments using the type's schemas. Setting globalArgs explicitly separates the two.

forEach with whole-field expressions

The expression form is particularly useful in forEach steps where each iteration item carries its own input record. Instead of mapping individual keys, pass the record through wholesale:

steps:
  - name: run-${{ self.task.name }}
    forEach:
      item: task
      in: "${{ inputs.tasks }}"
    task:
      type: model_method
      modelType: "${{ self.task.modelType }}"
      modelName: "${{ self.task.name }}"
      methodName: run
      inputs: "${{ self.task.inputs }}"
      globalArgs: "${{ self.task.globalArgs }}"

Given workflow inputs like:

tasks:
  - name: scan-us
    modelType: "@swamp/scanner"
    inputs: { region: us-east-1, depth: full }
    globalArgs: { pool: 4 }
  - name: scan-eu
    modelType: "@swamp/scanner"
    inputs: { region: eu-west-1, depth: quick }
    globalArgs: { pool: 2 }

Each iteration expands self.task to the current element, resolving inputs and globalArgs to the nested records without enumerating every key.

Workflow (workflow)

Invokes another workflow as a nested execution.

task:
  type: workflow
  workflowIdOrName: notification-workflow
  inputs:
    channel: "#deployments"
Field Type Required Description
type "workflow" Yes Task type discriminator
workflowIdOrName string Yes Workflow name or UUID
inputs Record<string, unknown> | string No Input values passed to the workflow (record or expression)

Nested workflows have a maximum depth of 10. Cyclic references (workflow A invoking workflow B which invokes workflow A) are detected and rejected.

Manual Approval (manual_approval)

Suspends the workflow run and waits for an out-of-band approval decision before downstream steps execute.

task:
  type: manual_approval
  prompt: "Staging verified. Approve production rollout?"
  timeout: 3600
Field Type Required Description
type "manual_approval" Yes Task type discriminator
prompt string Yes Message shown to the approver. Must be non-empty.
timeout number No Approval window in seconds. Must be greater than 0.

When timeout is set, an approval submitted after the window has elapsed is rejected with an Approval timed out error and the gate remains unapproved. An expired gate also no longer appears in swamp workflow approvals. When timeout is omitted, the gate waits indefinitely.

The suspend, approve, reject, and resume lifecycle is described in Manual Approval Lifecycle. For the step-by-step procedure, see the how-to guide Gate a Workflow with Manual Approval.

Assert (assert)

Evaluates a CEL expression and records whether it passed or failed. Assert steps run after data-producing steps and verify that the collected state meets expectations.

task:
  type: assert
  expr: data.latest("server-check", "result").attributes.exitCode == 0
  message: "Server exited cleanly"
  severity: high
Field Type Required Description
type "assert" Yes Task type discriminator
expr string (CEL expression) Yes Expression to evaluate. Truthy result = passed; falsy = failed.
message string Yes Human-readable message. Supports ${{ }} expression interpolation.
severity "low" | "medium" | "high" No Controls the --fail-on threshold. Defaults to "high" if omitted.

expr is a raw CEL expression — do not wrap it in ${{ }}. The expression has access to the full step expression context (data, inputs, self, model, env, vault, file), including model.method() calls for checking live state.

message supports ${{ }} interpolation. If an interpolated expression inside the message fails to evaluate, the expression text is left as-is.

message: >-
  Expected at least 3 instances, got
  ${{ size(data.latest("fleet", "nodes").attributes.instances) }}

Severity and --fail-on

Each assert carries a severity. The --fail-on flag on swamp workflow run sets the threshold — only failures at or above the threshold cause the workflow run to fail. Failures below the threshold are recorded but do not affect the exit code.

Assert severity --fail-on low --fail-on medium --fail-on high
low Fails run Recorded only Recorded only
medium Fails run Fails run Recorded only
high Fails run Fails run Fails run

The default --fail-on value is low — any failed assertion fails the run.

A failed assert step is treated as an allowed failure when either the step has allowFailure: true or its severity is below the --fail-on threshold.

Assert result

Each assert step produces an assertResult on its step run record:

{
  "passed": true,
  "expr": "data.latest(\"server-check\", \"result\").attributes.exitCode == 0",
  "message": "Server exited cleanly",
  "severity": "high"
}
Field Type Description
passed boolean Whether the expression evaluated to truthy.
expr string The original CEL expression.
message string The resolved message (after interpolation).
severity string The severity level (low, medium, or high).

assertResult is visible in --json output from swamp workflow run and in swamp workflow history get --json.

JUnit XML output

The --junit flag on swamp workflow run emits assert results as JUnit XML. Each assert step becomes a <testcase>; non-assert steps are omitted. Passing assertions are self-closing elements; failures include the resolved message and the raw CEL expression.

<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="infra-verify" tests="3" failures="2" time="0.1">
  <testsuite name="verify" tests="3" failures="2" time="0.0">
    <testcase name="check-healthy" classname="infra-verify.verify" time="0.0"/>
    <testcase name="check-count" classname="infra-verify.verify" time="0.0">
      <failure message="Expected count of 3 in output" type="AssertionFailure">
severity: medium
expr: data.latest("server-check", "result").attributes.stdout.contains(...)
      </failure>
    </testcase>
  </testsuite>
</testsuites>

Use --out <file> to write the XML to a file instead of stdout. --out requires --junit. --junit and --json cannot be combined.

For the step-by-step procedure, see the how-to guide Verify Infrastructure with Assert Steps.


ForEach

Expands a step into multiple executions, one per element in the evaluated collection.

forEach:
  item: env
  in: "${{ inputs.environments }}"
Field Type Required Description
item string Yes Variable name bound to each element
in string Yes CEL expression evaluating to a list or map

When iterating over a list, self.{item} is set to each element.

When iterating over a map, self.{item} is set to an object with key and value fields for each entry.

Expanded steps inherit the original step's dependencies. If the step name contains ${{ }} expressions, they are evaluated with the iteration context to produce unique step names. Otherwise, the iteration value or index is appended as a suffix (e.g., deploy-env-staging, deploy-env-production).

The iteration variable (self.{item}) resolves in modelIdOrName, methodName, step name, and task inputs — not just in inputs. This enables forEach steps to target different model instances per iteration without requiring a nested workflow:

steps:
  - name: summary-${{ self.region }}
    forEach:
      item: region
      in: "${{ inputs.regions }}"
    task:
      type: model_method
      modelIdOrName: aws-alarms-${{ self.region }}
      methodName: get_summary
      inputs:
        historyHours: 24

Each iteration resolves self.region to the current element, producing steps like summary-us-east-1 that target aws-alarms-us-east-1, summary-eu-west-1 that target aws-alarms-eu-west-1, and so on.


Trigger Conditions

Trigger conditions control when a job or step executes relative to its dependencies. They are specified in the condition field of dependsOn entries.

Leaf Conditions

Type Evaluates to true when
always Always (unconditional)
succeeded The dependency succeeded
failed The dependency failed
completed The dependency completed (succeeded or failed)
skipped The dependency was skipped
dependsOn:
  - job: build
    condition:
      type: succeeded

Composite Conditions

Leaf conditions can be composed with boolean logic.

and — all child conditions must be true. Requires at least 2 conditions.

condition:
  type: and
  conditions:
    - type: succeeded
    - type: not
      condition:
        type: skipped

or — any child condition must be true. Requires at least 2 conditions.

condition:
  type: or
  conditions:
    - type: succeeded
    - type: failed

not — inverts a single condition.

condition:
  type: not
  condition:
    type: failed

Composite conditions nest recursively.


DataOutputOverride

Overrides data output specifications for data produced by a step's task.

Field Type Required Description
specName string Yes Output spec name to override
lifetime Lifetime No Override data retention
garbageCollection GarbageCollectionPolicy No Override version retention
tags Record<string, string> No Additional tags to merge with output tags
vary string[] No Input key names to vary by (composite data names)

Lifetime

How long data is retained.

Value Description
Duration string 1h, 5m, 10d, 2w, 1mo, 10y
ephemeral Deleted when the process ends
infinite Never automatically deleted
job Lives until the job completes
workflow Lives until the workflow completes

Duration format: {number}{unit} where unit is h (hours), m (minutes), d (days), w (weeks), mo (months), or y (years). Zero durations (e.g., 0h) are normalized to workflow.

GarbageCollectionPolicy

How many versions to retain.

Value Description
integer Keep N most recent versions
Duration string Keep versions created within the duration
dataOutputOverrides:
  - specName: result
    lifetime: 30d
    garbageCollection: 5
    tags:
      stage: deploy
    vary:
      - environment

CEL Expressions

String values in step task inputs, modelIdOrName, methodName, step name, and forEach.in fields support CEL expressions using the ${{ }} wrapper.

task:
  type: model_method
  modelIdOrName: deployer
  methodName: apply
  inputs:
    region: "${{ inputs.region }}"
    artifact: "${{ model.builder.resource.result.result.attributes.path }}"
    secret: "${{ vault.get('infra', 'deploy-key') }}"

Context Variables

Variable Description
self The current model definition: self.name, self.tags.*, self.globalArguments.*
model All models: model.<name>.definition.*, model.<name>.resource.<spec>.<instance>.attributes.*
inputs Workflow or model runtime inputs: inputs.<property>
env Process environment variables: env.<VAR_NAME>
vault Secrets: vault.get('<vault>', '<key>')
data Versioned data: data.latest(...), data.version(...), data.findBySpec(...), data.query(...)
file File contents: file.contents('<model>', '<spec>')

When forEach is active, the iteration variable is available as self.{item}. For example, with forEach: { item: "env", in: [...] }, each iteration sets self.env to the current element.

After a step completes, its model's execution data and output data are available to subsequent steps through the model context. For example, model.builder.execution.status and model.builder.resource.result.result.attributes.*.

See the CEL Expressions reference for the full expression language.


Execution Order

Jobs and steps are sorted topologically using Kahn's algorithm with weighted tie-breaking.

  1. Dependency level — nodes are grouped into levels based on the dependency graph. Level 0 has no dependencies, level 1 depends only on level 0, etc.
  2. Weight — within the same level, lower weights execute first.
  3. Name — within the same level and weight, names are sorted alphabetically for determinism.

Nodes at the same level with no mutual dependencies execute in parallel.

Cyclic dependencies are detected and produce a validation error with the cycle path (e.g., job-a -> job-b -> job-a).


Manual Approval Lifecycle

A manual_approval step pauses execution until an approval decision is recorded. While the gate is pending, the run holds at the gate and no downstream step starts.

Run and step statuses

When a run reaches a manual_approval step, the workflow run status becomes suspended and the gate step status becomes waiting_approval. Steps that ran before the gate keep their terminal status (succeeded); steps after the gate stay pending.

Status Applies to Meaning
suspended Run The run is paused at a manual_approval step.
waiting_approval Step The gate is awaiting an approval decision.

An approval transitions the gate step to succeeded. A rejection transitions the gate step to failed and the run to failed; downstream steps remain pending.


CLI Commands

Workflow management commands for the Swamp CLI.

swamp workflow create <name>

Create a new workflow file.

Argument Required Description
name Yes Workflow name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

swamp workflow run <name>

Execute a workflow. The command blocks the calling process until the run reaches a terminal state — succeeded, failed, or cancelled — or until the run suspends at a manual_approval gate. There is no async or detached mode on the CLI; on swamp serve, HA mode auto-detects when the datastore supports a control plane and detaches runs from the client connection automatically (see Serve Flags). The exit code reflects the run outcome (0 for success, non-zero otherwise). To abort a blocking run, press Ctrl+C (SIGINT) or send SIGTERM — see Execution Cancellation.

Argument Required Description
name Yes Workflow name.
Flag Description
--repo-dir Path to the Swamp repository.
--input Set an input value (key=value). Repeatable.
--input-file YAML file of input values.
--stdin Read input values from standard input.
--tag Tag the run (key=value). Repeatable.
--skip-checks Skip all checks.
--skip-check Skip a check by name. Repeatable.
--skip-check-label Skip checks matching a label. Repeatable.
--skip-reports Skip all reports.
--skip-report Skip a report by name. Repeatable.
--skip-report-label Skip reports matching a label. Repeatable.
--report Run a specific report by name. Repeatable.
--report-label Run reports matching a label. Repeatable.
--timeout Maximum run duration.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.
--fail-on Assert severity threshold (low, medium, high). Default: low. Not supported with --server.
--junit Output assert results as JUnit XML instead of normal log output.
--out Write JUnit XML to a file instead of stdout. Requires --junit.
--last-evaluated Reuse the previously evaluated workflow and definitions. See below.

--last-evaluated

When set, swamp workflow run skips the full CEL evaluation pass and loads the previously evaluated workflow from .swamp/workflows-evaluated/. This avoids re-reading model definitions from disk and re-evaluating expressions that have not changed.

Deferred data expressions (data.query(), data.findByTag(), data.latest(), data.version(), data.listVersions(), data.findBySpec()) inside step task.inputs are still resolved at step execution time. The engine builds a lightweight expression context containing only the data and env namespaces, which is sufficient because the only unevaluated expressions remaining are data function calls that reference upstream step outputs.

swamp workflow get <name>

Show a workflow definition.

Argument Required Description
workflow_id_or_name Yes Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--graph Render the workflow's dependency graph as ASCII art. Shows a job-level DAG when jobs have inter-job dependencies, and step-level DAGs per job when steps have inter-step dependencies.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

When --graph is passed, the output includes box-drawing diagrams with proper edge routing for fan-out/fan-in patterns. Step graphs label the task type (model, workflow, approval, assert). A single job with no step dependencies omits the step graph.

Workflow: diamond-pipeline (5 jobs, 5 steps)

Jobs:
┌────────┐
│ fetch  ├───────┐
└────┬───┘       │
     ▼           ▼
┌────────┐  ┌─────────┐
│validate│  │transform│
└────┬───┘  └────┬────┘
     ▼           │
┌────────┐       │
│ merge  │◄──────┘
└────┬───┘
     ▼
┌────────┐
│ report │
└────────┘

In --json output, each workflow includes a trigger field when a trigger is configured:

{
  "id": "d14de37a-b931-4363-97e9-fe9ec9637b60",
  "name": "deploy-pipeline",
  "description": "A multi-stage deployment pipeline",
  "trigger": {
    "schedule": "0 3 * * *",
    "inputs": {
      "projectId": "a6b254a2-0b57-4d0f-bf8b-fef767ab119e"
    }
  },
  "tags": {
    "team": "platform"
  },
  "jobs": ["..."],
  "version": 1
}

trigger is omitted when the workflow has no trigger configured.

swamp workflow search [query]

Search workflows.

Argument Required Description
query No Search query.
Flag Description
--repo-dir Path to the Swamp repository.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

In --json output, each result item includes a trigger field when a trigger is configured:

[
  {
    "id": "d14de37a-b931-4363-97e9-fe9ec9637b60",
    "name": "deploy-pipeline",
    "description": "A multi-stage deployment pipeline",
    "trigger": {
      "schedule": "0 3 * * *"
    },
    "version": 1
  },
  {
    "id": "e182b5c7-41e7-4c9a-a9f8-455b7bb5ce12",
    "name": "nightly-report",
    "description": "Generate nightly reports",
    "version": 1
  }
]

trigger is omitted on workflows with no trigger configured (second item above).

swamp workflow edit [name]

Open a workflow in $EDITOR.

Argument Required Description
workflow_id_or_name No Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

swamp workflow delete <name>

Delete a workflow and its run history.

Argument Required Description
workflow_id_or_name Yes Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
-y, --yes Skip confirmation prompt (--force / -f also accepted).
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

swamp workflow validate [name]

Validate a workflow's schema, dependencies, and method resolution.

Argument Required Description
workflow_id_or_name No Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

Omitting the name validates all workflows.

swamp workflow evaluate [name]

Test CEL expressions in a workflow without executing it.

Argument Required Description
workflow_id_or_name No Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--all Evaluate all workflows.
--input Set an input value (key=value). Repeatable.
--input-file YAML file of input values.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

swamp workflow schema get

Print the YAML schema for workflow files.

Flag Description
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

swamp workflow cancel [name]

Cancel a running workflow.

Argument Required Description
workflow_id_or_name No Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--all Cancel all locally-owned running workflows. Serve-owned runs are skipped with a warning. Not supported with --server.
--run Target a specific run ID. Required with --server.
--reason Cancellation reason for the audit trail.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)

swamp workflow trigger set <name>

Set a trigger override for a workflow in serve.yaml. Each call writes the complete override entry — it replaces the previous override, not a partial merge.

Argument Required Description
name Yes Workflow name.
Flag Description
--schedule Cron expression for the trigger schedule (required).
--input Input value (key=value). Repeatable.
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)
$ swamp workflow trigger set nightly-report --schedule "0 3 * * *"
Set trigger override for "nightly-report": schedule "0 3 * * *"
$ swamp workflow trigger set nightly-report --schedule "0 3 * * *" --input env=production
Set trigger override for "nightly-report": schedule "0 3 * * *"
  inputs: "env=production"

swamp workflow trigger get <name>

Show the effective trigger for a workflow. Displays the built-in trigger (from the workflow YAML), the override (from serve.yaml), and the effective (merged) trigger.

Argument Required Description
name Yes Workflow name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)
$ swamp workflow trigger get nightly-report
Trigger for "nightly-report":
  built-in:
    schedule: "0 0 * * *"
  override (serve.yaml):
    schedule: "0 3 * * *"
    input "env": "production"
  effective:
    schedule: "0 3 * * *" ("override")
    input "env": "production" ("override")

In --json output:

{
  "workflowName": "nightly-report",
  "builtIn": {
    "schedule": "0 0 * * *",
    "inputs": {}
  },
  "override": {
    "schedule": "0 3 * * *",
    "inputs": {
      "env": "production"
    }
  },
  "effective": {
    "schedule": "0 3 * * *",
    "inputs": {
      "env": "production"
    }
  }
}

swamp workflow trigger remove <name>

Remove a trigger override for a workflow from serve.yaml. The workflow reverts to its built-in trigger (if any).

Argument Required Description
name Yes Workflow name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Run against a remote swamp serve instance (env: SWAMP_SERVE_URL)
--token Server token in <name>.<secret> format; only with --server (overrides stored credentials and SWAMP_SERVER_TOKEN)
$ swamp workflow trigger remove nightly-report
Removed trigger override for "nightly-report"

Approval decision record

When a gate is approved or rejected, an approvalDecision is written to the gate's step run record.

Field Type Description
approved boolean true for an approval, false for a rejection.
reason string The --reason text, when provided. Omitted otherwise.
decidedBy string The authenticated identity that made the decision.
decidedAt string ISO 8601 timestamp of the decision.

Commands

Command Effect
swamp workflow approvals Lists runs suspended at a gate and still within their approval window, with the workflow, step, and prompt. Runs whose timeout has elapsed are omitted — they can no longer be approved.
swamp workflow approve <workflow> <step> Records an approval on the gate. Accepts --reason <text>. Does not run downstream steps.
swamp workflow reject <workflow> <step> Records a rejection and marks the run failed. Accepts --reason <text>.
swamp workflow resume <workflow> Resumes a suspended or failed run, skipping already-completed steps. Accepts --from <step> to re-enter at a specific step — see Resume from a specific step. Accepts override inputs via --input, --input-file, or --stdin — see Resume inputs. Accepts --timeout — see Resume timeout.

All four commands accept --server and --token to target a remote swamp serve instance.

approve and reject check the approve action on the workflow resource, not run. A user with only run cannot approve or reject a gate unless run implicitly permits approve (which it does by default — see Run implies approve). To enforce separation of duties, deny approve on runners and grant it to a dedicated approver role.

approve records the decision but does not execute downstream work; resume performs the execution. Without --from, resuming a run whose gate has not been approved fails with an error naming the step to approve first. With --from, resume can also re-enter a failed run at any step — see Resume from a specific step. See Understanding Workflow Suspension for why approval and resume are separate operations.

Resume inputs

swamp workflow resume accepts override inputs through three flags:

Flag Source
--input <key=value> A single key set on the command line. The value may be a scalar or JSON. Repeatable.
--input-file <file> A YAML file of override inputs.
--stdin Override inputs read as piped data from standard input.

--input-file and --stdin cannot be combined. --input may accompany either.

Override inputs deep-merge over the original run inputs. On a key collision the resume value wins; keys not present in the original run are added. Nested objects merge key by key rather than replacing the whole object.

The run record records the names of the keys supplied at resume in a resumeInputs list. It does not record their values. A secret minted during the gate — such as a freshly issued auth key — is therefore usable at resume without being written to the run record. See Understanding Workflow Suspension for why resume inputs are audited this way, and Gate a Workflow with Manual Approval for the auth-key task.

swamp workflow resume deploy-with-gate --input authKey=tskey-abc123

Resume timeout

swamp workflow resume accepts --timeout to set a maximum run duration, matching the same flag on swamp workflow run. The value is bare seconds (30, 1800) or a duration string (30s, 5m, 1h). When omitted, the resumed run executes unbounded.

swamp workflow resume deploy-with-gate --timeout 5m

Resume from a specific step

swamp workflow resume accepts --from <step> to re-enter a workflow's DAG at a named step. This works with both suspended runs (after approval) and failed runs (after fixing the cause of failure).

Flag Description
--from <step> Step template name to resume from, as written in the YAML file.

The --from value is the step's template name — the name field as it appears in the workflow definition, before any forEach expansion. For a forEach step named deploy-${{ self.env }}, pass the template deploy-${{ self.env }}, not an expanded name like deploy-staging.

Execution behaviour

Steps that completed successfully before the failure are not re-run — this prevents repeating irreversible side effects. The --from step and all steps downstream of it in the dependency graph are eligible for execution.

For forEach steps, the platform re-expands all iterations from the template. Each iteration's guard expression decides whether it executes or is skipped. This means completed iterations are skipped (their guard sees existing data) while the failed iteration re-runs.

swamp workflow resume provision-stack --from deploy-$\{\{ self.env \}\}

Combining with guards

--from and guard work together for safe recovery:

  1. A workflow run fails at step 3 of 5.
  2. You fix the underlying problem.
  3. You resume with --from targeting step 3.
  4. Steps 1 and 2 are not re-run (already completed).
  5. Step 3 re-runs because its guard sees no completion data for the failed attempt.
  6. Steps 4 and 5 proceed as normal.

For a goal-oriented walkthrough, see Make Workflows Idempotent — Recover a failed run.


Execution Cancellation

A running workflow can be cancelled via swamp workflow cancel. Cancellation terminates in-flight steps cooperatively and marks the run as cancelled — a terminal status alongside succeeded and failed.

cancelled status

Status Applies to Meaning
cancelled Run The run was cancelled before completing.
cancelled Step The step was cancelled before completing.

Steps that completed before the cancel signal keep their terminal status (succeeded or failed). Steps that were running or pending at the time of cancellation transition to cancelled.

Commands

Command Effect
swamp workflow cancel <workflow> Cancel the latest running run of the named workflow.
swamp workflow cancel <workflow> --run <run-id> Cancel a specific run by ID.
swamp workflow cancel --all Cancel all locally-owned running runs. Serve-owned runs are skipped with a warning.
swamp workflow cancel <workflow> --reason <text> Cancel with an audit-trail reason recorded on the run.

Cancellation with --server

When cancelling via --server, the cancel endpoint distinguishes two outcomes:

  • cancelled — the run was confirmed stopped (deregistered within the grace period).
  • cancellation_requested — the abort signal was delivered but the run is still active. The run may stop on its own once the signal is processed.

The bulk cancel endpoint (POST /api/v1/cancel) always returns cancellation_requested, since it delivers abort signals without waiting for confirmation. See the REST API cancel endpoints for the full response schemas.

Locally-owned vs. serve-owned runs

swamp workflow cancel --all only cancels runs owned by the local process. Runs owned by a swamp serve instance are skipped with a warning — this prevents a local --all from inadvertently stopping server-managed workloads.

To cancel a serve-owned run, target the server directly with --server and --run:

swamp workflow cancel my-workflow --server wss://swamp.example.com --run 3f8a2b1c

--all is not supported with --server. To cancel all runs on a server, use the bulk cancel REST endpoint.

Signal-based cancellation

Pressing Ctrl+C (SIGINT) or sending SIGTERM during swamp workflow run cancels the running workflow. The CLI intercepts the signal, sends a cancel request, waits for in-flight steps to terminate cooperatively, and exits with a non-zero status.

Examples

$ swamp workflow cancel my-workflow
$ swamp workflow cancel my-workflow --run 3f8a2b1c
$ swamp workflow cancel --all
$ swamp workflow cancel my-workflow --reason 'No longer needed'
$ swamp workflow cancel my-workflow --server wss://swamp.example.com --run 3f8a2b1c

Concurrency Resolution Order

When steps within a job execute in parallel, the effective concurrency limit is resolved from the most specific level:

  1. Step concurrency — if multiple steps at the same dependency level specify concurrency, the minimum value across those steps is used.
  2. Job concurrency
  3. Workflow concurrency
  4. Unbounded

The first non-zero value at each level wins.

Job-level parallelism follows the same pattern: workflow concurrency is applied across jobs at the same dependency level.

SWAMP_MAX_CONCURRENT_STEPS

Environment variable that sets a host-level ceiling on all concurrency values. When set to a positive integer, the effective concurrency at every level is capped to this value regardless of what the workflow, job, or step specifies. When unset or not a positive integer, no host-level cap is applied.

SWAMP_MAX_CONCURRENT_STEPS=4

Validation

swamp workflow validate checks a workflow against its schema:

$ swamp workflow validate multi-stage
Validating: multi-stage
  ✓ Schema validation
  ✓ Unique job names
  ✓ Unique step names in job 'build'
  ✓ Unique step names in job 'deploy'
  ✓ Unique step names in job 'notify'
  ✓ Valid job dependency references
  ✓ Valid step dependency references in job 'build'
  ✓ Valid step dependency references in job 'deploy'
  ✓ Valid step dependency references in job 'notify'
  ✓ No cyclic job dependencies
  ✓ No cyclic step dependencies in job 'build'
  ✓ No cyclic step dependencies in job 'deploy'
  ✓ No cyclic step dependencies in job 'notify'
Summary: 13/13 validations passed
Result: PASSED

Omit the name to validate all workflows in the repository:

$ swamp workflow validate
Validating all workflows...

multi-stage
  ✓ Schema validation
  ...
Summary: 1/1 workflows passed
Overall: PASSED

Validation rules:

  • id must be a valid UUID v4.
  • name must be at least 1 character, unique within the repository, with no path traversal sequences.
  • version must be a positive integer.
  • concurrency must be a non-negative integer when present (at workflow, job, or step level).
  • tags values must be strings.
  • trigger.schedule must be a valid cron expression.
  • jobs must contain at least one job.
  • Job names must be unique within the workflow.
  • Step names must be unique within each job.
  • Each job must contain at least one step.
  • Job dependency references must name existing jobs.
  • Step dependency references must name existing steps within the same job.
  • No cyclic dependencies among jobs.
  • No cyclic dependencies among steps within each job.
  • ${{ inputs.* }} expressions in model definition globalArguments must reference inputs declared in the workflow's inputs block.
  • Unknown keys on workflows, jobs, and steps are rejected. A typo produces a did-you-mean suggestion naming the closest valid key.
  • Placement fields (target, labels, platform, queueTimeout) are valid at the workflow, job, and step level. See Workflow Placement for the inheritance chain and scheduling behavior.
  • affinity is valid at the workflow and job level. A validation warning is emitted when affinity: true is set but no placement field (target, labels, or platform) is effective — affinity without placement is a no-op.

Unknown-key rejection applies at both swamp workflow validate and load time (swamp workflow run, swamp workflow evaluate). Workflow files that previously loaded with unrecognised keys now fail. Run swamp doctor workflows to identify affected files in a repository.


Complete Example

id: d14de37a-b931-4363-97e9-fe9ec9637b60
name: multi-stage
description: A multi-stage deployment pipeline
trigger:
  schedule: "0 3 * * *"
tags:
  team: platform
  env: production
inputs:
  type: object
  properties:
    environments:
      type: array
      description: Target environments
    region:
      type: string
      default: us-east-1
  required:
    - environments
labels:
  pool: gke
platform: linux
jobs:
  - name: build
    description: Compile and test
    weight: 0
    steps:
      - name: compile
        description: Build the artifacts
        task:
          type: model_method
          modelIdOrName: builder
          methodName: run
          inputs:
            target: "${{ inputs.region }}"
        weight: 0
        allowFailure: false
      - name: test
        description: Run tests
        task:
          type: model_method
          modelIdOrName: test-runner
          methodName: execute
        dependsOn:
          - step: compile
            condition:
              type: succeeded
        weight: 1
        allowFailure: false
  - name: deploy
    description: Deploy to each environment
    dependsOn:
      - job: build
        condition:
          type: succeeded
    weight: 10
    concurrency: 2
    steps:
      - name: deploy-env
        description: Deploy to environment
        guard: "${{ data.latest('deployer', 'result') }}"
        task:
          type: model_method
          modelIdOrName: deployer
          methodName: apply
        forEach:
          item: env
          in: "${{ inputs.environments }}"
        dataOutputOverrides:
          - specName: result
            lifetime: 30d
            garbageCollection: 5
            tags:
              stage: deploy
            vary:
              - environment
  - name: notify
    description: Send notifications
    labels: {}
    dependsOn:
      - job: deploy
        condition:
          type: completed
    weight: 20
    steps:
      - name: send-notification
        task:
          type: workflow
          workflowIdOrName: notification-workflow
          inputs:
            channel: "#deployments"
        allowFailure: true
version: 1
reports:
  require:
    - name: deployment-report
      methods:
        - apply
    - summary
  skip:
    - debug-report

History

Commands for inspecting past workflow runs.

swamp workflow history get <name>

Show the latest run for a workflow.

Argument Required Description
workflow_id_or_name Yes Workflow ID or name.
Flag Description
--repo-dir Path to the Swamp repository.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

swamp workflow history search [query]

Search past workflow runs.

Argument Required Description
query No Search query.
Flag Description
--filter <expression> Filter results with a CEL expression over run metadata.
--repo-dir Path to the Swamp repository.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

--filter

The --filter flag accepts a CEL expression evaluated against each run's metadata. Only runs where the expression evaluates to a truthy value are returned.

Available fields:

Field Type Description
workflowName string Name of the workflow.
status string Run status (succeeded, failed, cancelled, …).
startedAt string ISO 8601 timestamp (lexicographic comparison works).
completedAt string ISO 8601 timestamp.
duration double Run duration in milliseconds.
inputs.* map<string,dyn> Input values supplied to the run.
tags.* map<string,dyn> Tags on the run.
instanceId string Instance UUID of the run.
triggerSource string What triggered the run.
failedStep string Name of the step that failed (if any).
failureReason string Failure reason text (if any).

Missing map keys (e.g. inputs.commit when no commit input was supplied) return false rather than throwing an error.

# Filter by input value
swamp workflow history search --filter 'inputs.commit == "b3ff3a8a"'

# Filter by status
swamp workflow history search --filter 'status == "failed"'

# Combine with a query and filter by input
swamp workflow history search verify-reviews --filter 'inputs.branch == "main"'

# Filter by duration (runs longer than 60 seconds)
swamp workflow history search --filter 'duration > 60000'

See the CEL Expressions reference for the full expression language. The same complexity limits as grant conditions apply: 1024 character maximum, AST depth 24, comprehension nesting 2, cost budget 500.

swamp workflow run search [query]

Search workflow runs with additional filtering options.

Argument Required Description
query No Search query.
Flag Description
--repo-dir Path to the Swamp repository.
--since <duration> Only runs started within duration (1h, 1d, 7d, 1w, 1mo).
--status <status> Filter by run status (pending, running, succeeded, failed).
--workflow <name> Filter by workflow name.
--tag <tag> Filter by tag (KEY=VALUE). Repeatable.
--limit <n> Maximum results (default: 50).
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

swamp workflow history logs <run_id_or_workflow>

Show logs for a specific workflow run.

Argument Required Description
run_id_or_workflow Yes Run ID or workflow name.
Flag Description
--repo-dir Path to the Swamp repository.
--tail <n> Show only the last N lines.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.