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

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.


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

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. See Workflow Placement for scheduling behavior and interaction with non-placed steps.

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. See Workflow Placement for scheduling behavior and interaction with non-placed steps.

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

Mutually exclusive with target.


Step Task

A step task defines the work a step executes. Three 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.


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.

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; 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.
--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.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

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.

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.

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.
-f, --force Skip confirmation prompt.

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.

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.

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 running workflows.
--run Target a specific run ID.
--reason Cancellation reason for the audit trail.

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 run after approval, skipping already-completed steps. 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 records the decision but does not execute downstream work; resume performs the execution. Resuming a run whose gate has not been approved fails with an error naming the step to approve first. 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

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 running workflow runs in the repository.
swamp workflow cancel <workflow> --reason <text> Cancel with an audit-trail reason recorded on the run.

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'

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.

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
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
        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
    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
--repo-dir Path to the Swamp repository.
--server Target a remote swamp serve instance.
--token Authentication token for the remote server.

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.