#[cerulion_node] struct and a tick() method. This guide takes you from cerulion node create to a node that reads inputs, writes outputs, and is ready to stage into a graph.
For the full attribute and policy grammar, see the node macro reference and trigger policies reference.
Run these commands from inside a workspace (a directory with a
[workspace]
Cargo.toml and a graphs/ folder). Create one with cerulion workspace create <name>.Create the node type
cerulion node create <node_type> scaffolds nodes/<node_type>/ with a Cargo.toml (cdylib) and a src/lib.rs macro template. The type name becomes the folder name and, PascalCased, the struct name. It must be non-empty, alphanumeric or underscore, and must not start with a digit.
Add ports while creating the node:
Pick a trigger policy
The trigger policy decides when the node fires. Pass it with--policy SPEC:

--policy depends on the nodeβs inputs:
- 0 inputs (no
-i, no-T): a source-only node must declare a non-data policy.cerulion node createerrors otherwise. - 1+ inputs via
-ionly: no node-level policy is written; the runtime fires on any input arrival and emits a graph-build warning. -Tset: the policy becomesdata_triggerfor that trigger input.
Create a periodic source node
A camera with no inputs needs a period:
Create a data-triggered consumer
A detector that fires whenever an image arrives:
Write the tick()
Opennodes/<node_type>/src/lib.rs. The template pairs two macros:
#[cerulion_node(...)]on the struct declares the node and its trigger policy, and generates the glue that letscerulion graph runload it.#[cerulion_node_impl]on the adjacentimplblock letstick()use plain field access for ports β reads and writes go directly to shared memory, zero-copy. It takes no arguments, and the struct must appear before the impl block.
Fixed vs variable fields
How you write an output field depends on whether it is fixed-size or variable-length:- Fixed primitive fields (for example
x,y,z,height,width) are written directly:self.linear_velocity.x = 0.3;. The write goes straight to shared memory. - Variable-length fields (
string,T[], nested types) must be listed in the#[output(...)]attribute; you then write them with plain assignment too.
#[output(...)]:
For nested-typed variable fields, use the
complex(...) form, for example
#[output(data, complex(header))]. See the
node macro reference for the full #[output] grammar.Build the node
cerulion node build <node_type> compiles the crate into a cdylib. Add --release for an optimized build.
A successful build prints
Built '<node_type>'. On failure the CLI prints
Error: with the cargo output, and no cdylib is produced.Inspect and adjust
Use these commands to review and edit node types after creation.List node types
List node types
cerulion node list prints a table of types with input/output counts and a short policy label.Show one node's details
Show one node's details
cerulion node info <node_type> prints the type, policy, and each port with its schema. Metadata is parsed from src/lib.rs; there is no sidecar file.Add ports later
Add ports later
cerulion node modify <node_type> mutates src/lib.rs in place, preserving the tick body and comments. It takes the same -i, -T, -o, and --policy flags (at most one of each per call).-T also sets the data_trigger policy. To make a node externally triggered, use --policy external.Delete a node type
Delete a node type
cerulion node delete <node_type> removes the node crate and its workspace member entry.Next steps
Wire and run a graph
Stage these node types into a graph and run it.
Trigger policies
The full
--policy grammar and defaulting matrix.