Skip to main content

Workflow

A workflow is the top-level configuration file that tells Loom what to run, in what order, and under what conditions. Every loom run begins by reading a single workflow file — making it the single source of truth for your entire CI/CD pipeline.

Why workflows matter

One file defines your full execution graph — stages, jobs, steps, variables, and provider configuration — in a single declarative YAML document. This gives you:

  • One file to review when something breaks or changes.
  • One file to validate before committing (loom check).
  • One file to diff when debugging behavior changes between runs.

Unlike pipeline systems that scatter configuration across multiple files and hidden defaults, a Loom workflow keeps every decision visible and auditable in one place.

Workflow file location

SettingValue
Default path.loom/workflow.yml
Override--workflow <path> flag on any loom command
Schema versionv1 (the only supported version)

Anatomy of a workflow

A workflow file is a YAML mapping with a fixed set of root-level keys:

KeyRequiredPurpose
versionYesSchema version — must be the exact string "v1"
stagesYesOrdered list of stage names that define execution phases
variablesNoWorkflow-level environment variables (defaults for all jobs)
defaultNoDefault job settings inherited by all jobs via deep merge
includeNoList of local template files to include ({local: .loom/templates/name.yml})
workflowNoWorkflow-level rules — currently supports rules with {if: ...} conditions

Any other top-level key that matches the job name pattern (^[a-z][a-z0-9_-]{0,63}$) is treated as a job definition. Template jobs (names starting with .) are used for inheritance via extends but are not executed directly.

Minimal example

version: v1
stages: [ci]

check:
stage: ci
target: linux
script:
- echo "hello from Loom"

This defines one stage (ci) and one job (check) that runs a single shell command.

Multi-stage example

version: v1
stages: [build, test, deploy]

variables:
APP_ENV: "staging"

default:
target: linux

compile:
stage: build
script:
- make build

unit-tests:
stage: test
image: golang:1.22
script:
- go test ./...

integration:
stage: test
needs: [compile]
image: golang:1.22
script:
- go test -tags=integration ./...

ship:
stage: deploy
script:
- make deploy

Loom runs all build jobs before test jobs, and all test jobs before deploy jobs. Within a stage, jobs without needs dependencies execute alphabetically by name. The integration job also waits for compile to finish because of its explicit needs dependency.

The workflow lifecycle

A workflow passes through three phases, each answering a different question:

  loom check           loom compile          loom run --local
┌───────────┐ ┌─────────────┐ ┌────────────────┐
│ "Is this │ yes │ "What will │ ok │ "What │
│ valid?" │──────► │ Loom run?" │─────► │ happened?" │
└───────────┘ └─────────────┘ └────────────────┘
Schema + Graph IR Runtime logs
static (compiled JSON + receipt
validation representation)
PhaseCommandQuestion it answersOutput
Validateloom checkIs this workflow valid?Pass/fail with error paths like WF_SCHEMA_V1 /my-job/target: ...
Compileloom compileWhat will Loom execute?Graph IR — a JSON representation of stages, nodes, edges, and resolved variables
Executeloom run --localWhat happened during execution?Runtime logs under .loom/.runtime/logs/<run_id>/ and a receipt under .loom/.runtime/receipts/

Start with loom check — it is the fastest feedback loop. Run it before every commit to catch schema errors, missing keys, and invalid references without waiting for execution.

Naming rules

The schema enforces strict naming conventions to keep workflows machine-parseable and consistent:

EntityPatternMax lengthExample
Stage name^[a-z][a-z0-9_-]{0,31}$32 charsci, build-assets, deploy_prod
Job name^[a-z][a-z0-9_-]{0,63}$64 charsunit-tests, lint_go
Template job^\.[a-z][a-z0-9_-]{0,63}$65 chars (including .).base-job
Variable key^[A-Z_][A-Z0-9_]*$No hard limitAPP_ENV, CI_DEBUG

Common pitfalls

loom check fails with "unknown field" or "schema validation error"

  • Cause: Your YAML uses keys that are not in the workflow schema v1, or values have the wrong type.
  • Fix: Compare your YAML to the root-level key table above. Variable values must be quoted strings — "3" not 3. Job keys must come from the allowed set: stage, target, script, extends, needs, image, runner_pool, variables, secrets, invariant, cache, services.

Includes or templates don't resolve

  • Cause: Template files are outside .loom/templates/ or use .. path traversal.
  • Fix: Ensure include.local paths point to files under .loom/templates/ with a .yml or .yaml extension. See Includes & templates.

Jobs run in an unexpected order

  • Cause: Misunderstanding stage ordering or the needs dependency mechanism.
  • Fix: Loom executes stages in the order declared in stages:. Within a stage, jobs without needs dependencies are ordered alphabetically by name. Use explicit needs to declare cross-job dependencies. Run loom compile to inspect the resolved execution graph. See Stages, jobs, and steps.