Skip to content

Automation Model

A Task is the complete automation definition in Nonbl. It is a directed graph of Nodes connected through their Ports. A Task can contain one or more Execution Paths, each starting from a Trigger.


A Node is the visual element on the canvas. An Operation is the functional behavior that the Node performs at runtime.

Every Node has exactly one Operation. The Operation defines what happens when the Node executes.

Each Node has a number shown on the canvas. This number identifies the Node in the editor but does not determine execution order. The runtime order within an Execution Path is determined by Dependencies.


A Port is a named Input or Output on a Node.

  • Input Ports receive data from other Nodes through Connections.
  • Output Ports provide data to other Nodes through Connections.

Some Operations have a fixed set of Ports. Others allow adding Ports dynamically.

Some Ports are marked as mandatory and must be connected for the Task to compile. Others are optional.


A Connection is the visible line between an Output Port on one Node and an Input Port on another. Connections define how data flows through the Task.

Because every Input receives data from exactly one source, the Dependency graph is deterministic and each Execution Path is stable.

A Dependency is the runtime relationship derived from Connections. If Node 4 has an Input connected to an Output of Node 1, then Node 4 depends on Node 1 — meaning Node 1 must run before Node 4.

A Node can depend on multiple upstream Nodes (through different Input Ports, each connected to a different source) and can feed multiple downstream Nodes. The set of all Dependencies forms the directed graph that determines execution order.


A Property is a configurable setting on an Operation. Properties control behavior such as timing, thresholds, formatting, or path control rules.

Each Operation document lists its available Properties and their defaults.


A Trigger is a Property of an Operation that marks it as an execution entry point. When a Trigger fires, it runs the Trigger’s Execution Path: every Node downstream of the Trigger, in Dependency order. The compiler builds one Path per Trigger from the graph, and each firing runs it. A Path is not one line: it forks where an Output feeds several Inputs, and it merges where a Node reads from several sources.

Only Operations explicitly marked as Triggers can start Execution Paths. Not every Operation without Inputs is a Trigger. A Trigger is always an explicit Property of the Operation.

When a Trigger fires:

  1. The Trigger itself executes first.
  2. The system walks through the remaining Operations in the path, in Dependency order.
  3. Before running each Operation, the system checks that all upstream Dependencies have valid results.
  4. Each Operation receives data from its connected Inputs, performs its work, and writes to its Outputs.
  5. The path ends when there are no more downstream Operations to run, or when an Operation stops the path.

Within a path, if two Operations have no Dependency between them, their relative order is not guaranteed.

A Node’s branch is the Node and everything downstream of it. A fork gives a Node several branches below it. A Node fed from two sources sits in both their branches, and it stops when either of them stops, because an Input it needs never arrives. Stop this branch on the Error Handling page, and “the branch continues”, mean exactly this set of Nodes.

Some Operations act as Triggers while also having Inputs — for example, Delay. When the compiler builds an Execution Path and encounters such an Operation, it treats it as a boundary: the Operation is included as a leaf of the incoming path, but none of its downstream Nodes are.

  • The incoming path ends at the Trigger Operation. This is structural — the path simply contains no Nodes past the boundary.
  • The Trigger’s downstream Nodes belong to a separate Execution Path that runs independently when the Trigger fires.

This means a single Task can contain multiple Execution Paths, each rooted at a different Trigger.


Many Operations have a Gate Input, shown as > on the first Input Port.

The Gate controls whether the Operation executes on a given run:

  • If the Gate is not connected — execution is allowed.
  • If the Gate receives a boolean — execution is allowed only when the value is true.
  • If the Gate receives a non-boolean value — execution is allowed when the value is not Nil.

When the Gate blocks execution, the Execution Path stops at that Operation — downstream Nodes that depend on it are skipped for this run. If you don’t want this behaviour, don’t connect a Gate.


When an Operation is reached but does not produce a valid result, the Nodes that depend on it do not run this firing. A closed Gate, an Input whose Validation rule is not satisfied, or the Operation’s own logic standing down stops the Node. A value on an Input the Operation cannot read fails it instead, and the Node’s On Error verb resolves that failure — see On Error: three verbs. There are two distinct stop mechanisms. (Separately, Trigger Boundaries end a path structurally at compile time — see Trigger Boundaries above. Ending a path at a boundary is not a stop and is not reported as one.)

A Conditional Stop is a built-in runtime decision made by the Operation itself. The Operation evaluates its Inputs and decides whether to continue or stop the path based on its logic.

For example, OnChange stops the path when its Input value has not changed since the previous run, and continues when it detects a new value.

Conditional Stops are not configurable through Properties — the behavior is defined by the Operation and documented on its page.

A Data-driven Stop is controlled through per-Port settings rather than per-Operation checkboxes. There are four sources:

  • Per-Port Input Validation (Any value, A value that exists, A value not used yet, A value whose last update succeeded, A value whose last update failed) stops the Node when the Input’s state does not satisfy the chosen rule.
  • Type-mask Validation fails the Node when the value on an Input is a type the Operation cannot read.
  • A connected Gate Input stops the path when the Gate value is false or Nil.
  • An Operation’s own runtime error (division by zero, a failed SQL query, …) goes through its per-Operation On Error verb — Stop this branch, Continue with the last value, or Continue with the fallback. So does a type the Operation cannot read. A rule that is not satisfied stops the Node without asking its verb. An Operation that answers later applies the same verb to the answer; see Operations that answer later.

All of this is documented in detail in the Error Handling guide. When a Path has already stopped and you are working back to why, start from When a Path Stops.

Both mechanisms work the same way once a stop occurs:

  • A stop only affects Nodes that depend on the stopping Node, directly or transitively.
  • Independent branches of the Dependency graph continue unaffected.
  • Other Execution Paths in the same Task are not affected.
  • Operations with no Outputs naturally end the current path — there is no downstream path to stop.

Some Operations preserve runtime state across service restarts, Task restarts, or reconfiguration.

When state preservation is supported:

  • Output values and internal state are saved when execution stops cleanly.
  • If the service restarts within a configured time window — for example during a graceful restart to apply updates — the Operation restores its saved state.
  • If the time window has expired, the saved state is discarded to avoid resuming from stale values.

Running a Task that is already running stops it, rebuilds, and restarts it. A confirmation dialog asks whether to preserve Operation state across this cycle:

  • Yes (default) — Each Operation saves its state before the stop and attempts to restore it after the restart.
  • No — All Operations start fresh; saved state is discarded.

State is always discarded when running a Task that is stopped, errored, or being started for the first time.

On reload, each Operation decides whether its saved state is still compatible with the current configuration. If the configuration changed in a way that invalidates the saved state — for example the number of outputs, a threshold value, an output type, or a subscribed topic — the saved state is discarded and the Operation starts from its default or configured initial state.

Rewiring an Operation’s inputs or outputs does not trigger a mismatch by itself; the Operation has no visibility into upstream topology. On the first run after a re-run with preserved state, outputs may briefly reflect values computed under the previous wiring until the next Execution Path refreshes them.

Each Operation document specifies which configuration changes cause saved state to be discarded.


Before a Task can run, the system compiles it — validating the graph and producing Execution Paths.

  1. Enumerate Nodes and Connections — Collect all Operations and the Connections between their Ports.

  2. Build the Dependency graph — For each Connection, record that the destination Node depends on the source Node.

  3. Identify Triggers — Find all Operations marked as Triggers. Each Trigger becomes the root of one Execution Path.

  4. Validate — Check that all Connections reference valid Operations and Ports. Flag unconnected mandatory Ports. Detect cycles in the graph.

  5. Generate Execution Paths — For each Trigger, traverse its dependents and produce an ordered sequence where every Operation appears after all the Operations it depends on.

If compilation finds errors — invalid Connections, cycles, or exceeded Operation limits — the Task cannot run and the issues are reported. See Errors and Warnings for where these show up in the Editor and what pressing Verify adds to them.


The diagram below shows a Task with 11 Nodes. Each Node is numbered in the editor.

A Nonbl Task with 11 Nodes

This Task has two Triggers: Node 1 and Node 7. The compiler produces two independent Execution Paths.

Node numbers reflect the order in which Nodes were placed on the canvas — not the order in which they execute. Execution order is determined entirely by Dependencies.

Path from Node 1

Dependencies:

  • Node 4 depends on Node 1
  • Node 11 depends on Node 1
  • Node 3 depends on Node 4
  • Node 5 depends on Node 3
  • Node 2 depends on Node 5
  • Node 6 depends on Node 5

Execution order:

Node 1 fires and starts its Execution Path. The Dependencies form two branches from Node 1:

  • The main branch: 1 → 4 → 3 → 5 → 2 and 5 → 6
  • A separate branch: 1 → 11

Node 11 depends only on Node 1, so it can appear anywhere in the sequence after Node 1. Node 2 and Node 6 both depend on Node 5 but not on each other, so their relative order is not guaranteed.

Valid execution orders include:

  • 1 → 4 → 3 → 5 → 2 → 6 → 11
  • 1 → 11 → 4 → 3 → 5 → 2 → 6
  • 1 → 4 → 3 → 5 → 11 → 6 → 2
  • 1 → 4 → 11 → 3 → 5 → 2 → 6

Path from Node 7

Dependencies:

  • Node 9 depends on Node 7
  • Node 10 depends on Node 9
  • Node 8 depends on Node 10

Execution order:

Node 7 fires and starts its Execution Path. This Path is a single line: each Node depends on the one before it.

7 → 9 → 10 → 8

This path is independent of the path started by Node 1. The two Triggers fire at different times based on their own logic, and their Execution Paths run independently.

Path stop in action

Node 5 in Path 1 is an Operation with a Conditional Stop — it stops downstream execution when its Output value has not changed since the last run. This is where the Dependency structure becomes important.

Consider the execution order 1 → 4 → 3 → 5 → 2 → 6 → 11:

When Node 5 detects a change — all Nodes execute normally. Node 2 and Node 6 receive the new value from Node 5 and perform their work. Node 11 executes as well.

When Node 5 detects no change — Node 5 stops the path. The effect is:

  • Node 2 — skipped. It depends on Node 5, which stopped.
  • Node 6 — skipped. It also depends on Node 5.
  • Node 11 — still executes. It depends only on Node 1, not on Node 5 or anything downstream of it. The stop does not reach Node 11 because Node 11 is not in Node 5’s branch.

The same holds regardless of where Node 11 appears in the sequence. Even in the order 1 → 4 → 3 → 5 → 11 → 2 → 6, Node 11 still executes because the stop is scoped to the downstream Dependency sub-graph of the stopping Node — not to everything that comes after it in the sequence.

A stop only affects Nodes that depend on the stopping Node, directly or transitively. Independent branches of the Dependency graph continue unaffected.


Key Concepts

  • A Task is a directed graph of connected Nodes.
  • A Node is the visual representation of one Operation.
  • An Operation defines the runtime behavior of a Node.
  • A Port is a named Input or Output on a Node.
  • A Property is a configurable setting on an Operation.
  • A Connection links an Output Port to an Input Port.
  • A Dependency is the runtime ordering derived from Connections.
  • A Trigger is a Property of an Operation that starts an Execution Path.
  • An Execution Path is the Nodes downstream of a Trigger, in Dependency order — see Triggers and Execution Paths above.
  • A Gate Input controls whether an Operation executes on a given run.
  • A Trigger Boundary — where an incoming path structurally ends at an Operation that is also a Trigger; not a stop, and not reported as one.
  • Conditional Stop — built-in runtime stop based on the Operation’s logic.
  • Data-driven Stop — an Input Validation rule that is not satisfied, or a closed Gate, stopping the Node; a type the Node cannot read fails it instead, and its On Error verb resolves that.