Skip to content

Flows, nodes and messages

A flow is a group of nodes that exchange messages. Nodes declare what they consume (requires) and produce (provides); matching message names connect them. No wires to draw.

How nodes connect

For a Function node, declare input and output ports in its panel, then write process(...). Arguments use input port names; the returned dictionary uses output port names:

# Node "read": provides temperature
def process():
    return {"temperature": 18.5}

# Node "decide": consumes temperature, provides heat
def process(temperature, setpoint=21.0):
    return {"heat": temperature < setpoint}

Bind both temperature ports to the same message and decide follows read. Here setpoint uses a Python default; you can also add it as a node setting.

  • Several nodes can produce the same message. Consumers use the latest value.
  • Publishing an input wakes its consumers once their required values are available. An upstream node that publishes nothing leaves downstream nodes waiting for a new publication.
  • The editor arranges the graph automatically. Keep flows focused and share messages between them when needed.

Message names are namespaced

In flow house, temperature becomes house.temperature. A dotted name is used as written, so another flow can consume it directly. Bind an input port named temperature to house.temperature:

def process(temperature):
    return {"shown": temperature}

The canvas shows cross-flow messages as labelled endpoints.

Node types and payloads

Function nodes run your Python code. Built-in nodes handle MQTT, HTTP, InfluxDB, schedules, filtering and more through forms in their panels. See Node types.

Every port declares a payload type (dtype). Values are checked against it, and dashboard widgets offer compatible messages. Scalars, structured JSON and media references are covered in Payload types.

Messages carry JSON. For binary data, store the bytes as an artifact and publish its reference. image, audio and video are artifact references restricted to their media family.

Streaming ports

Mark an output streaming when it publishes during an execution: progress, training loss or media chunks. A Function node can yield values or call fluksio.emit.

Downstream nodes receive each publication in order; message state holds the latest value. A batch run records the full series. An output interval limits live publication without thinning the run's recorded series.

Keeping node code predictable

Write Function nodes as functions of their declared inputs and settings. Fluksio provides no hidden context or global flow store. To remember a value between executions, use a message the node reads and writes; see Keeping state in a flow.

Live and batch flows

Choose Mode in the flow settings:

live (default) batch
Runs reacts continuously once per requested run
Started by subscriptions, schedules, webhooks or manual execution Run in the editor, SDK or API
Finishes stays active until stopped when its work finishes
Keeps latest message values parameters, results, metrics and artifacts
Example thermostat experiment or build job

Batch flows use the same editor and validation, but do not activate background subscriptions, schedules or webhooks. See Runs.

Flow inputs

Declare messages supplied by dashboard controls, the API or run parameters as the flow's Inputs. Give live inputs a starting value:

{"inputs": [{"spec": {"name": "setpoint", "dtype": "float"}, "initial": 21.0, "origin": "panel"}]}

This seeds house.setpoint in flow house if it has no value yet. Later publications replace it. Batch inputs are run parameters, and batch outputs select the run's result. See Where a node's values come from.

origin says what writes an input: run (the default) for a parameter a run passes in, panel for a dashboard or panel control. The canvas labels each input with it, and the run form leaves panel inputs out, so a run keeps their starting value. The engine treats both the same.

Drafts and publishing

  • Saving stores a draft; the engine keeps running the published version.
  • Publishing promotes the draft and reloads the flow.
  • Discarding removes the draft.

Shared node code is an exception: saving it updates every flow using it immediately. See The flow editor.

Flows are stored in a git repository: flow.json describes the graph and nodes/*.py holds code. Saves are versioned, and stale versions return a conflict instead of overwriting another editor's changes.

Python installations need Git on the host to record history. Without it, flows still save as files; Docker includes Git.

When a flow needs attention

The canvas reports issues on the affected nodes:

Issue Meaning
unconnected_input no node or declared flow input supplies the message
missing_initial_value a live input has no starting value
cycle nodes depend on each other in a loop
self_loop_needs_initial a node reads and writes a message with no starting value
missing_source a Function node has no saved code
node_error code or configuration could not load
unauthenticated_hook a webhook or served websocket has no shared secret; advisory
ignored_worker a node other than a Function node names a worker, which nothing reads; advisory
unknown_device a Device node names no device, or one that does not exist
device_port a device port is wired in two places, or against the device's report the wrong way or type; a port the report does not list is advisory
node_unhealthy a loaded node reports a runtime problem, such as a lost connection
node_degraded a loaded node works but not as it should, such as a device being offline; advisory, amber on the canvas

Build issues prevent the affected flow from running. node_unhealthy and node_degraded are runtime issues: other work continues, and they clear when the node recovers. A degraded node is a warning on Home rather than a fault.

You can stop a live flow to remove its subscriptions and schedules, or pause it to hold pending work while values still arrive. Step releases one held item. Repeated background crashes can quarantine a flow; publishing a change gives it another chance.

Where to next