The workflow document

What a workflow is made of — nodes, edges and ports, workflow variables, the canvas organisation the engine ignores, validation and the activation gate, and how a revision is numbered.

A workflow is a versioned JSON document in the v0-draft schema, plus a set of trigger records that live outside it. This page is what that document contains and what the canvas in Cockpit is editing when you drag a node.

You do not need Execution modes first, but it explains why the save-then-build step exists.

The graph

A workflow is a directed graph.

Nodes are the steps. Each node on the canvas is an instance of a node type from the palette: it has an id that is unique within the workflow, a pinned node version, and its own configuration. The id matters beyond the canvas — it is what expressions use to read that node's output, so a node named fetch is referenced as ${{ nodes.fetch.outputs.response }}.

Edges connect one node's output port to the next node's input. A connection must leave an output and arrive at an input; the canvas refuses output-to-output and input-to-input drags rather than making a connection that could never run.

Ports carry meaning. A node declares its ports, and there are three kinds:

  • A default port is the normal continuation — the HTTP node's response, a transform's out.
  • Branch ports are alternatives, and exactly one of them fires per execution: true / false on a condition, one named case on a switch, item and done on an iterator.
  • An error port is the exception path. It carries a node's expected failures, and — when the node sets onError: "route" — the failures that survived its retries too.

A node that always ends the run, like Stop and Error, declares an output that is never emitted, and cannot be dropped into the middle of an existing connection.

The node instance in the document names the node type by namespace:slug, pins its version, and carries its own config alongside the engine's per-step settings:

workflow.json
{
  "id": "fetch-orders",
  "nodeSlug": "revenexx:http-request",
  "nodeVersion": "1.1.0",
  "config": {
    "method": "GET",
    "url": "${{ vars.erpBaseUrl }}/orders"
  },
  "retry": { "maxAttempts": 5, "backoffSeconds": 2, "strategy": "exponential" },
  "timeoutSeconds": 120,
  "onError": "route"
}

Pinning the version is what stops a new release of a node silently changing a running workflow. See Node configuration for the config half and Failure handling for retry, onError and timeoutSeconds.

Variables

Variables are workflow-level values, declared once and referenced from node configuration as ${{ vars.<key> }}. Each one has a type (string, number, boolean, object, array), a value, and an optional description. Keys are identifiers — letters, digits and underscores, not starting with a digit.

Use them for everything that differs between installations of the same graph: the SFTP folder, the base URL, the column a supplier's product id lands in. The BMECAT template is the model — nine variables, set once after install, and no node configuration to touch.

Open them from Variables on the canvas toolbar.

A variable with no value resolves to nothing, silently. Nothing warns you at save time, so a workflow whose upstream call quietly went to /orders instead of https://erp.example.com/orders looks like a data problem rather than a configuration one. Give every variable a value.

Canvas organisation the engine ignores

Four things in the document exist for the people reading the workflow, not for the engine:

  • Node groups — a labelled frame around a set of nodes, for the stage of the flow they belong to.
  • Sticky notes — free text on the canvas.
  • Tags — labels on the workflow itself, for finding it in a long list.
  • An icon — how the workflow is shown in that list.

They are saved with the workflow and they bump the revision like any other edit, but they change nothing about execution. A per-node note behaves the same way: it shows as a small marker on the card, never reaches the engine, and is the cheapest way to explain to the next person why a mapping is the way it is.

Validation and the activation gate

You can save a workflow in any state. You cannot activate or run one whose nodes have unfilled required settings.

An incomplete workflow shows a banner above the canvas naming how many settings are missing in how many nodes, one line per node, using the node's canvas name rather than an identifier. Following a line opens that node's settings and centres its card. The affected cards are outlined and badged with their own count. The Activate control is disabled and says how many settings remain, and the keyboard shortcut for activation is refused the same way.

Two details are easy to trip over:

  • The markers reflect the last save, not what you are typing. Fixing a field clears the marker when you save, not as you type.
  • Saving an already active workflow into an incomplete state is allowed, but it asks first and saves the workflow paused so it cannot fire in that state. Cancelling saves nothing and leaves your edit in the editor.

Revisions: what a save does

Saving does three things: it validates the graph, it bumps the workflow's revision, and it queues the build that turns the graph into a runnable bundle.

Revisions are plain increasing numbers on the workflow. Revision 1 is the first save; every subsequent save is the next number, and the previous revision is archived rather than overwritten. There is no branching and no naming — a revision is a snapshot of the graph at one save, and the one that runs now is the current one.

Until the queued build reports ready, runs are rejected — see Execution modes.

A newly created workflow — including one installed from a template — is paused. Nothing fires until you activate it deliberately, so you can read and adjust the whole flow first.

Reading the history and restoring an earlier revision is covered in Revisions and audit. Deleting a workflow deletes its revision history permanently.

Where to go next

  • Node catalog — every node you can place, and what it produces.
  • Node configuration — the inspector, the field types, and testing a single node.
  • Expressions — wiring one node's output into the next node's config.
  • Triggers — what makes the workflow you just built actually start.
Was this page helpful?