Concepts

Workflows

A workflow is a DAG of nodes and edges, executed by DirectFlow — parallel where possible, deterministic always.


Anatomy of a definition

A definition is plain JSON validated by zod schemas from @directos/shared — the same contract the API, the editor and the SDK all use:

workflow definition
{
  "nodes": [
    {
      "id": "n1",
      "type": "trigger.manual",
      "name": "Start",
      "position": { "x": 0, "y": 0 },
      "params": {}
    },
    {
      "id": "n2",
      "type": "http.request",
      "name": "Fetch orders",
      "position": { "x": 280, "y": 0 },
      "params": { "url": "https://api.example.com/orders" },
      "settings": { "retries": 2, "timeoutMs": 10000 }
    }
  ],
  "edges": [{ "id": "e1", "source": "n1", "target": "n2" }]
}
FieldMeaning
node.typeNode type id, e.g. http.request — must exist in the registry.
node.nameDisplay name, unique per workflow — referenced by {{$node["Name"]}} expressions.
node.paramsValues for the node’s declared parameters; strings may contain expressions.
node.settingsPer-node reliability: retries, retryDelayMs, timeoutMs, continueOnError.
edge.sourceHandleWhich output handle of the source the edge listens to. Defaults to main.

Scheduling and parallelism

A node becomes ready when all of its incoming edges are settled. Ready nodes run concurrently up to maxConcurrency — independent branches parallelize automatically, and a merge node waits for all of its inputs. There is no step list to maintain: the graph is the schedule.

Branching by output handle

Executors emit data per output handle. The condition node, for example, returns:

ts
return { outputs: { true: item, false: undefined } };

An edge listening on a handle that produced undefined is settled-inactive; a node whose incoming edges are all inactive is skipped, and skips propagate transitively. Use null for “active, with an empty payload”. One mechanism covers if/else, switch and future multi-way routers.

Retries, timeouts, failure policy

  • Retries — retries attempts with retryDelayMs between them, per node.
  • Timeouts — timeoutMs holds even for executors that ignore the abort signal: the engine races the executor against it.
  • continueOnError — converts a failure into { error } data on the main handle so downstream nodes can react instead of the run failing.

Cancellation is first-class: aborting an execution aborts in-flight nodes and marks the run canceled.

Validation

Duplicate ids or names, unknown node types, dangling edges and cycles are rejected before anything runs.

Execution events

Every run streams execution.started, node.started / finished / failed / skipped / log and execution.finished through a callback. The API forwards them to the WebSocket room execution:{id} and persists the final snapshot — this is what powers live node status in DirectStudio and the events API.