Skip to main content
Version: v5.7.0

4.2 Store, browse, run

Included from Basic tier

After this you can: try a workflow locally, store it on the server, browse the stored catalog, and run it with runs create workflow.

Before you start — tick each one:

  • Lesson 4.1 — Anatomy and the step kinds (opschain learn 4.1)
  • Lesson 3.1 — Your first change (opschain learn 3.1)

In the GUI: the Workflows tab on a project page is the stored catalog; running one opens the Run form, and the run page shows the orchestration with one row per step.

Lesson 4.1 taught you to read a definition. This lesson takes the Environment Start workflow from there through the whole loop: rehearse it on your own machine, import it into the server's versioned catalog, find it again, and run it — with a plan first — so that by the end you have one workflow run on the server and know where its spawned changes went.

1. Try it locally first​

Workflows have a local lane too. Files live in .opschain/workflows/, carry an identity header workflow: <code> (any non-blank code — the same contract the server stores, so hyphenated codes like patch-infrastructure work unchanged in both lanes), and run by code:

opschain workflows list --local
opschain runs create workflow env_start --env dev --plan --local
opschain runs create workflow env_start --env dev --local
2026-10-12T11:20:04Z Start database pending -> queued
2026-10-12T11:20:04Z Start database queued -> running
[Start database/database:start/start] starting postgres
2026-10-12T11:20:35Z Start database running -> success
2026-10-12T11:20:35Z Confirm before the app tier pending -> waiting
…
2026-10-12T11:21:16Z App tier running -> success

run 01a14210-…-example success (1m12s)

A local workflow run executes its change steps as nested local runs, attached to your terminal like any lesson 2.1 run, and the wait step prompts you right there, as lesson 2.3 showed — the quick way to prove the orchestration before promoting it to the server.

2. Store it on the server​

The server keeps workflows in a versioned, per-project catalog. The way in is workflows import — and the common case is the file you already have: the flat definition from section 1, exactly as it sits in .opschain/workflows/, no wrapping required:

opschain workflows import acme -f .opschain/workflows/env-start.yaml
created workflow acme/env_start (version 1)

The file is stored verbatim as the workflow's definition. Its identity comes from the file itself — the code from the workflow: header, the display name from name: — and when a bare steps:-only file carries neither, the code defaults to the filename stem and the name follows the code. It imports published; --code, --name and --draft override any of this from the command line:

opschain workflows import acme -f .opschain/workflows/env-start.yaml --code env_start_v2 --draft

Either way the import is validated by the server's own authoring machinery — a published (draft: false) workflow must be runnable to save; a draft may be saved incomplete. Re-importing an existing code without --update is refused by name; with it, the import mints the next version rather than editing history — versions that have run are immutable:

opschain workflows import acme -f .opschain/workflows/env-start.yaml --update
updated workflow acme/env_start — minted version 2 from .opschain/workflows/env-start.yaml

Import also accepts the envelope format that workflows export writes — the identity on top, the definition nested under definition: — so an exported backup round-trips without edits:

opschain workflows export acme/env_start --out env-start.yaml
exported workflow acme/env_start to env-start.yaml
# env-start.yaml
workflow: env_start
name: Environment Start
draft: false
definition: |
name: Environment Start
steps:
- type: change
name: Start database
target: /projects/acme/environments/dev/assets/database
action: database:start

That export is your backup and change-control format; lesson 8.2 builds the discipline on it.

3. Browse the stored catalog​

opschain workflows list --project acme
opschain workflows show acme/env_start
workflow: acme/env_start
id: 01a14212-…-example
name: Environment Start
description: Starts all assets in dependency order
draft: false
archived: false
latest version: 2

--definition prints the latest version's authored YAML instead of the summary — ready to redirect to a file:

opschain workflows show acme/env_start --definition

4. Plan it, then run it​

Preview before running: --plan sends the same payload the run would and prints the step tree in two tiers, creating nothing. Tier 1 — concrete: will-run/will-skip verdicts (when: conditions evaluated over your overrides and inputs) and fan-out expansions rendered per element with their resolved names, targets and actions. Tier 2 — symbolic: ? markers for anything only execution can decide — output-dependent spans render as their expression with the producing step named:

opschain runs create workflow acme/env_start --override env=dev --plan
plan: workflow env_start on acme — advisory, re-evaluated at step entry
✔ Start database → /projects/acme/environments/dev/assets/database · database:start
✔ Confirm before the app tier
✔ App tier
├─ ✔ Start SAP → /projects/acme/environments/dev/assets/sap · sap:start
└─ ✔ Start Web → /projects/acme/environments/dev/assets/web · web:start

A − marker means will-skip (with the reason), ? means symbolic — decided only at step entry.

--plan takes the same -i inputs, so input-driven when: conditions preview concretely. Then run:

opschain runs create workflow acme/env_start --follow
created workflow 01a14220-…-example (env_start on acme) — pending
run 01a14220-…-example pending
run 01a14220-…-example pending → running
run 01a14220-…-example running → waiting

The run is created from the latest published version; --version N pins an explicit one (including a draft, for testing). --override k=v passes property overrides, -i key=value supplies the workflow's typed inputs (repeat the flag; a repeated key builds a list; an unknown name, missing required input or type/enum mismatch is refused before the run exists), and --skip-step <name> skips steps by their workflow step names.

That waiting is the wait step: answer it exactly as lesson 3.2 did (runs show <run-id> -o json for the step id, then runs continue <run-id> --step <step-id>), and --follow carries on to success.

5. Where the work went​

A workflow run's change steps spawn real changes — they appear in opschain runs list in their own right, with their own logs and their own retries:

opschain runs list
ID KIND ACTION TARGET STATUS CREATED DURATION
01a14226-…-example change web:start acme/environments/dev/assets/web success 2026-10-12T11:31:02Z 33.6s
01a14226-…-example change sap:start acme/environments/dev/assets/sap success 2026-10-12T11:31:02Z 40.0s
01a14221-…-example change database:start acme/environments/dev/assets/database success 2026-10-12T11:30:11Z 31.2s
01a14220-…-example workflow env_start acme success 2026-10-12T11:30:10Z 3m05s

opschain runs show <workflow-run-id> shows the orchestration tree, and opschain logs <workflow-run-id> plays back every spawned run's lines interleaved, labelled with the nested step's path under its workflow step. Cancel with opschain runs cancel <run-id>; pause and release the orchestration between steps with opschain runs pause|resume <run-id> (a spawned change already running finishes first). What happens when a step fails — retries, on_error:, compensation — is lesson 4.3, a lab you run yourself.

Check yourself​

  • Import your definition twice: what does the second import print without --update, and with it? Then run it and count: how many rows does runs list gain for a workflow with three change steps, and which row is the workflow run itself?
  • Does opschain workflows show acme/<workflow> list version 1, and does the run you created from it report success? The Academy's workflow-run exercise reads api:workflows:create, api:workflow_runs:create and api:workflow_runs:success on your project — created as the everyday operator you signed in as (a run executes as its creator; the bootstrap admin's every act is break-glass).
  • Verified version: opschain academy runs the workflow-run exercise against this lesson.

What you learned​

  • A workflow runs locally by code from .opschain/workflows/, attached to your terminal, before it ever reaches a server.
  • workflows import <project> -f <file> stores the flat file verbatim as version 1; --update mints the next version, never rewriting one that has run; export writes the envelope that round-trips.
  • workflows list --project and show [--definition] are the catalog reads.
  • runs create workflow <project>/<code> [--plan] [-i …] --follow runs the latest published version; each change step is a real change in runs list, and the workflow run's id plays back all their logs.

Next: lesson 4.3 — Error semantics (opschain learn 4.3), or back to your track (opschain learn).