cerulion-inc/cerulion 是一个托管在 GitHub 上的开源项目,主要使用 GDScript 编写,采用 GNU General Public License v3.0 许可证,目前获得 101 个 Star、4 次 Fork。
仓库全名
cerulion-inc/cerulion
README 摘要
Run robots. Understand failures. Test every change. Cerulion connects the software running on a robot to the tools that inspect it and the tests that keep it working. Run your nodes, see their data in Studio, capture a failure, and re-execute that recording against a code or model change before deploying it. Built for Physical AI, Cerulion combines iceoryx2 zero-copy shared memory, a scheduler that follows your node…
Run robots. Understand failures. Test every change.
Cerulion connects the software running on a robot to the tools that inspect it and the tests that keep it working. Run your nodes, see their data in Studio, capture a failure, and re-execute that recording against a code or model change before deploying it.
Built for Physical AI, Cerulion combines iceoryx2 zero-copy shared memory, a scheduler that follows your node graph, ROS 2 interoperability and secure access to remote robots. The runtime records the data and execution context needed to turn real robot behavior into CI tests.
Zero-copy, beyond fixed-size messages. Write camera frames, scans and schema-defined variable-length fields directly into shared memory. Other local processes read the same bytes.
A scheduler that knows your graph. Dependency levels are computed ahead of time; trigger policies decide when nodes can run. Eligible nodes in the same level can run in parallel. Event-driven waits, reusable buffers and placement by measured cost reduce overhead; recorded scheduling and input decisions support deterministic replay.
Low latency, including the tail. A 1 MiB native round trip measures 4.08 µs median and 7.38 µs p99 in the Linux multi-process benchmark, with recording enabled. See the measurements and configurations.
Execution you can test. Periodic, data-triggered, synchronized and external nodes; explicit backpressure and deadlines; recorded execution traces and a virtual clock for deterministic re-execution.
Recordings that become regression tests. Standard MCAP, byte-exact output comparisons, per-field tolerances and machine-readable verdicts for CI. Test your changed code against the inputs that actually reached the robot.
Flashback when you forgot to record. Save the moments before and after a failure from a rolling in-memory history, then inspect the incident or replay its recorded topics.
Studio for the whole robot. Live sensors and 3D scenes, topic discovery, rates and graph inspection in a desktop workspace, with an agent beside the data.
Your robots, wherever they are. Automatic account-based pairing connects owned and shared robots, with access grants controlling authenticated pub/sub. Discover nearby robots with mDNS; reach remote ones through Iroh hole punching or a relay.
A path from ROS 2. Run an existing stack through rmw_cerulion, attach to one already running, or combine ROS 2 processes and native nodes in the same graph.
Tools your coding agent can use. Cerulion MCP exposes graph, node, topic, recording and replay operations. Hindsight investigates recordings with evidence tied to topics and timestamps.
One workflow across machines. Native single- and multi-process execution on Linux and macOS, with LAN topic delivery and remote data mirrored locally for your tools.
Install
CLI for robots and headless machines
curl -fsSL https://raw.githubusercontent.com/cerulion-inc/cerulion/main/tools/scripts/install.sh | sh && . "$HOME/.cerulion/env"
In fish, end the line with && source ~/.cerulion/env.fish instead. The installer links cerulion into ~/.local/bin and adds one line to each of your shell startup files, and the end of the line puts it on the PATH of the terminal you pasted it in, so sign in straight away with cerulion login: a robot or a headless box prints a short code to approve from any browser. It also installs the Rust compiler the release was built with. To remove it, run the same script with sh -s -- --uninstall.
Homebrew
brew tap cerulion-inc/cerulion
brew install cerulion-inc/cerulion/cerulion
Homebrew treats a third-party tap as untrusted until you install a fully qualified name, which is why the second line spells the formula out. On Homebrew 6.0.x the tap itself can refuse first; run brew trust --formula cerulion-inc/cerulion/cerulion before the two lines and try again.
The first line installs the three programs the second needs. The second is one chain, where every step runs only when the one before it succeeded, so a failed download, or a keyring holding any key other than the key the archive signs with, stops it before it writes a keyring file or a source list. The APT distribution page pins the same fingerprints in the same form, lists both during a key rotation, and carries a longer form of this recipe that names which step failed.
Homebrew and the Debian package do not provision Rust. To build your own nodes, run cerulion-install-rust once and put ${CARGO_HOME:-$HOME/.cargo}/bin on your PATH.
Build the CLI from crates.io
cargo install --locked cerulion_cli cerulion_netd
The release installer places cerulion-connectd (the desk side of a remote connection) and cerulion-remoted (the robot side) beside the CLI. See the installation guide or CONTRIBUTING for the complete source-build route.
Release binaries support Linux x86_64 and ARM64 (glibc 2.31+, Ubuntu 20.04 and later) and macOS Intel and Apple Silicon. The Linux packages also carry the ROS 2 Jazzy rmw and heap hook that cerulion ros2 run and cerulion ros2 launch use; the macOS packages do not, because ROS 2 Jazzy has no macOS binaries. The rmw libraries run where their ROS 2 distro runs: Jazzy on Ubuntu 24.04. For ROS 2 Lyrical, each release also publishes cerulion-rmw-lyrical-<version>-<target>.tar.gz for Linux x86_64 and ARM64: unpack it and set CERULION_LIB_DIR to the unpacked directory so cerulion ros2 run and cerulion ros2 launch load the Lyrical rmw. That library is built and tested in CI but has not been run on a robot, and unlike the Jazzy package it is not installed in a clean container before release.
Building nodes needs a C toolchain (build-essential on Debian and Ubuntu, xcode-select --install on macOS) and the same compiler that built your cerulion binary: a node is a shared library loaded into the CLI’s own process, so the loader refuses a node built by a different rustc and names both compilers. The install script installs that compiler (Rust 1.93.0 for the 1.0.0 binaries), and cerulion-install-rust does on the other routes. A workspace created with cerulion workspace create or cerulion workspace init records it in its rust-toolchain.toml when that compiler is installed. Elsewhere, when your rustup default is a different compiler, name it: RUSTUP_TOOLCHAIN=1.93.0 cerulion node build <node>. The installation details cover CERULION_NO_MODIFY_PATH, machines without rustup, CARGO_HOME and RUSTUP_HOME, hand-unpacked archives, workspaces without a rust-toolchain.toml, and a CLI built with cargo install.
Studio for your computer
Use Cerulion Studio to discover robots, inspect their live data and work with an agent in one desktop app.
Studio bundles its visualization, network and workspace daemons; it does not install the CLI. Robots and headless machines use the CLI install above. Install it on your computer too if you want to build nodes or use Cerulion from a terminal.
How it fits together
On the robot: the scheduler derives dependency levels from your graph, waits on data and timers and executes ready nodes across process groups. Nodes exchange loaned shared-memory messages; capture records the data and execution context.
Across machines: mDNS discovers nearby robots and LAN topics stream to your computer. Account ownership and grants authorize remote access over Iroh, using direct peer-to-peer connections when possible and a relay when needed. The network daemon mirrors subscribed topics locally for your tools.
At your desk: Studio renders the robot’s data; CLI and MCP tools inspect, record and verify it. Captured failures become inputs to the next regression test.
This example connects a synthetic laser scanner to a safety controller. The controller publishes a forward velocity of 0.3 when the path is clear and 0.0 when an obstacle is within half a meter.
Choose the acquisition route for your installed CLI.
Released CLI 1.0.0
The public 1.0.0 binaries do not include the starter option. Obtain the matching
source tag and enter its complete example workspace:
git clone --depth 1 --branch v1.0.0 https://github.com/cerulion-inc/cerulion cerulion-starter-source
cd cerulion-starter-source/examples/obstacle_avoidance
Continue with the sign-in, build and run commands below. The
example runbook describes the source.
CLI builds with --starter
Use this route only when cerulion workspace create --help lists --starter:
cerulion workspace create safety_demo --starter obstacle_avoidance
cd safety_demo
This obtains complete source bundled with your CLI, including tests and all
variable-length scan fields, without GitHub credentials or a source download.
Exact release dependencies are selected and starter.toml records compiler
requirements. Existing paths are refused; failed installation leaves no partial
workspace. The generated README also shows explicit graph creation, staging and
wiring. To write nodes from scratch, start with
cerulion workspace create my_robot and the
getting-started tutorial.
Sign in once per machine. Cerulion commands run under an account, and the result is read locally from then on, so later commands keep working offline.
cerulion login
A robot or a headless box prints a short code to approve from a browser on any machine.
Build both nodes, check the graph, then run it with recording on. The first node build also compiles the Cerulion runtime, so it takes a few minutes on a laptop; later builds take seconds.
The graph declares no process_groups:, so graph run derives a layout of one process per node and runs it without asking, leaving the graph file unchanged. Add --yes to save that layout in the graph YAML (with a .bak backup), or run cerulion graph partition obstacle_avoidance to review it and save it interactively.
By default a run is visible to other machines on your network, so Studio and the CLI on another computer can find it; the log says so when the run starts. Add --network off to keep a run on this machine.
The x field switches between 0.3 and 0.0 as the synthetic scan crosses the distance threshold. Let it run for at least five seconds, then stop it with Ctrl+C; Cerulion prints the completed recording’s path, recordings/obstacle_avoidance_<timestamp>.mcap, where the timestamp reads like 20260918T181449Z. To find the file again:
ls recordings/
Besides recordings/, the node builds leave target/ in the example directory; a run leaves a ~/.cerulion/runs directory and the cerulion-netd network daemon, which exits on its own after 30 seconds idle.
Set BAG to that printed path, then verify the unchanged code first:
BAG="recordings/obstacle_avoidance_<timestamp>.mcap"
cerulion bag play "$BAG" --resim all --verify
A successful verification prints replay PASS and exits successfully: the outputs covered by the report match the recording.
Now open nodes/safety_controller/src/lib.rs and change the clear-path velocity from 0.3 to 0.25. Rebuild that node and verify against the same recording:
cerulion node build safety_controller --release
cerulion bag play "$BAG" --resim all --verify
This time verification reports a divergence and returns a nonzero exit code. On the same sensor inputs, the changed controller would command a different speed. In CI, that verdict flags the changed behavior for review before the code reaches a robot.
What replay verification checks
Cerulion re-executes the graph with recorded inputs and execution context, then compares the covered outputs against the recording. It checks behavior under those inputs; a passing result is not a claim about every environment the robot could encounter.
Exit 0: compared frames match.
Exit 1: output data diverged; the report names the topic or field.
Exit 6: the execution schedule diverged.
Exits 2 through 5: verification could not complete; the error identifies why.
Comparisons are byte-exact by default. Add --tolerance for acceptable per-field differences and --report for a machine-readable report.
Replay verification turns model changes into regression tests
The perception example records a synthetic camera and pixel-based detector, verifies the baseline, then tests a detector whose boxes move by eight pixels. Its bounding-box overlap tolerance catches the change and names the affected field.
From the repository root:
cd examples/perception
RECORD_SECS=8 ./run_replay_demo.sh
Choose tolerances that match the behavior you care about: bounding-box IoU, absolute or relative error, RMSE and set comparisons. Comparisons are byte-exact unless you set a field, topic or document-wide tolerance. The same checks can run on pull requests against recordings your team keeps as regression cases.
Performance
Native graph round trips
Local shared-memory delivery stays nearly flat as payloads grow. These measurements include the native capture plane on the measured Linux x86_64 host.
Each cell below is p50 / p99, in microseconds: median latency and the threshold at or below which 99% of measured round trips fall. Both legs use the advertised payload size.
The native benchmark loans that payload without filling it. Timing starts after the publisher’s loan and metadata setup and ends on echo receipt; the echo loans the same payload size and forwards the timestamp. Sensor production and payload processing add their own work.
This workload comparison uses a nominal 100 Hz offered load. The stock ROS 2 lane pipelines requests: at 16 MiB a round trip outlasts the 10 ms pacing interval, so requests overlap in flight. Native Cerulion includes recording; the ROS 2 and zenoh lanes do not. The benchmark suite documents the process layouts and timing boundaries.
Free run and lockstep
A multi-process graph free-runs by default: each process steps on its own clock and none waits on a barrier. CERULION_EXECUTION_MODE=lockstep opts out into barrier lockstep. Measured on one build and one Linux x86_64 machine, two processes, fixed 100 Hz, six interleaved reps per mode, recording enabled:
Payload
Free run (default), p50 / p99 in µs
Lockstep, p50 / p99 in µs
64 B
4.23 / 7.60
5.08 / 10.47
1 MiB
4.56 / 9.01
5.44 / 10.63
16 MiB
5.22 / 12.34
7.22 / 13.64
Free run has the lower median and the lower p99 at every measured size; the lockstep median is about 20% higher up to 1 MiB. This machine is not the one behind the table above, so compare within each table. All ten sizes · Results and provenance.
ROS 2 over Cerulion
The rmw_cerulion line in the chart above is ROS 2 Jazzy running over Cerulion’s transport, measured in the same harness, posture and pacing as every other line: three ROS 2 nodes in three processes, with loaned publishing and loaned subscription takes. At 1 MiB that is 11.12 µs p50 / 37.21 µs p99, beside 11.0 ms / 43.4 ms for stock rmw_fastrtps_cpp, the chart’s own stock ROS 2 line. The median stays between 10.43 and 10.65 µs from 64 B to 256 KiB and reaches 17.47 µs at 16 MiB. Methodology · Results and provenance.
Across platforms
These native runs include recording. On the measured Apple M4, single-process medians are 3.38 to 3.75 µs; multi-process medians are 87 to 93 µs. That M4 row predates the macOS data wake: on macOS 14.4 and later, a two-process consumer now blocks on a kernel wake word that the producer’s publish rings, instead of waking on the park’s recheck timer. Measured before and after that change on an Apple M3 Max, five reps per cell with the two builds alternating. This pair uses quiescent pacing rather than the charts’ fixed 100 Hz and a different machine, so compare within the table only, and its recorder state is not recorded:
Payload
Two-process before, p50 / p99 in µs
Two-process after, p50 / p99 in µs
64 B
70.17 / 141.54
10.42 / 28.21
4 KiB
77.75 / 143.79
12.79 / 29.83
1 MiB
80.12 / 152.42
16.14 / 41.67
Single-process medians on that machine rose by one to three ticks of its 24 MHz clock, inside overlapping per-rep ranges (64 B: 4.46 before, 4.50 µs after). The M4 chart row has not been re-measured since the change. Results and provenance.
Source measurements, build provenance and configuration receipts are in the benchmark results. Lines show p50 and bands extend to p99; both figures show round trips.
Bring your ROS 2 stack
When you control startup, keep your launch file and start it through Cerulion:
cerulion ros2 launch my_robot_bringup camera.launch.py
cerulion ros2 run my_robot_drivers imu_node
Both set up rmw_cerulion and run the ROS 2 command, one launch file or one executable at a time. Your nodes keep their ROS 2 APIs and executors. Neither rewrites your source: publishers that copy keep copying until you migrate them. The ros2 CLI graph tools (ros2 topic list, ros2 topic echo, rqt) do not see Cerulion topics yet, because the rmw’s discovery is process-local; inspect them with cerulion topic list and cerulion topic echo, which read the shared-memory plane.
Optional: migrate C++ publishers to zero-copy loans
The first command previews which C++ publish sites can move to the loaned-message API; --write applies the rewrite. Publishing and subscribing with loans are separate choices; the ROS 2 guide covers both and what to expect from each.
When the stack is already running, attach to its DDS topics:
cerulion ros2 attach --iface <local-interface-IP>
Use the IP address of this computer’s interface on the robot’s LAN. Attach discovers the existing DDS stack and bridges its topics; it does not restart those nodes.
Use ros2: entries to launch ROS 2 processes beside native nodes in one graph. The MoveIt 2 example shows an unmodified planning stack running over rmw_cerulion.
A typed input, a typed output and a tick method define the quickstart’s safety controller. The macro supplies the port plumbing; the graph declares the wiring and the runtime handles scheduling, transport, recording and observability. You do not configure an executor, register callbacks or write a spin loop.
use cerulion_core::prelude::*;
use native_ros2_messages::geometry_msgs::Vector3;
use native_ros2_messages::sensor_msgs::LaserScan;
#[cerulion_node]
#[derive(Default)]
struct SafetyControllerNode {
#[input(trigger, depth = 1, expect_within_ms = 100)]
scan: LaserScan,
#[output(promise_within_ms = 100)]
linear_velocity: Vector3,
}
#[cerulion_node_impl]
impl SafetyControllerNode {
fn tick(&mut self) -> Result<(), NodeError> {
let ranges = self.scan.ranges();
let stop = ranges.is_empty()
|| ranges.iter().any(|&r| r.is_nan() || r < 0.5);
self.linear_velocity.x = if stop { 0.0 } else { 0.3 };
Ok(())
}
}
Here, #[input(trigger)] runs the controller when a scan arrives. The port deadlines make timing expectations observable through miss counters, alongside delivery-failure counts.
Other nodes can run on synchronized input sets or external events. For a periodic node, use #[cerulion_node(period_ms = 10)] instead of a data trigger. Set queue depth and backpressure per input; for example, backpressure = sample(3) limits reads to one per 3 ms.
Fixed fields write directly into the shared-memory slot. Variable-length fields have loaned writers too: self.image.data.fill_from(producer)? lets a camera or generator fill the final buffer in place. An untouched output publishes nothing; if this node’s tick returns an error, its outputs are discarded.
Cerulion Studio brings your robot’s sensors, topics, graph and agent into one workspace. It is built on Rerun, the open-source viewer for multimodal data. Discover a robot, select its topics and inspect live images, scans, point clouds and scalar signals together. Topic rates and liveness show which parts of the graph are active.
The agent sidebar can inspect the view, take a screenshot and arrange the scene through Studio’s viewer tools. Ask it to investigate a signal alongside the live data.
Rendering and decoding run on your development computer. The robot supplies the topics you subscribe to; it does not need to run a visualization node.
A robot rarely fails on cue. Flashback keeps a memory-bounded window of recent activity in every running graph, so the moments before a problem are already there when you need them. It is event-based logging: nothing is written to disk until an event fires, and then the window around that event becomes a recording.
It captures on its own when the runtime sees a fault: a worker process dies, a node is disabled after repeated panics, the run it was bound to vanishes, the e-stop is engaged, a topic stalls while its process stays alive, or a topic’s rate collapses inside the window. Each capture holds the retained history plus a short period after the trigger, written to MCAP. A capture on a route that never produced at all is the one trigger that ships off.
You can also ask for one by hand from another shell on the robot:
Re-execution uses the capture’s execution trace and any state anchors its starting point needs; bag info reports whether a capture can be re-executed or only played back. To record an already-running graph instead, use cerulion bag record --run=obstacle_avoidance.
Cerulion MCP and Hindsight: tools for your coding agent
Cerulion MCP gives Claude Code, Codex and other MCP clients tools for graphs, nodes, topics, robots, recordings, Flashback and replay verification. An agent can inspect live data, rebuild a node and re-run a captured recording.
Hindsight investigates MCAP recordings with answers grounded in specific topics and timestamps.
Register the hosted endpoints with your client:
claude mcp add --transport http cerulion https://mcp.cerulion.com/mcp/cerulion
claude mcp add --transport http hindsight https://mcp.cerulion.com/mcp/hindsight
For screenshots and viewport control, use Studio’s built-in agent. Cerulion MCP exposes runtime tools and does not include Studio’s viewport tools.
The direction is CI/CD for autonomy: bring recordings, simulations and behavioral evidence into the review process before a change reaches a robot.
Area
What’s next
Faster execution
Chain-fused nodes that pass data directly within a process; nanosecond-scale handoff as a measured target; lower macOS cross-process wake-up latency.
Python and C++
First-class node authoring and client libraries, with clear boundaries for zero-copy access, scheduling and reproducible execution.
Robot building blocks
Native transforms and URDF support, parameters and lifecycle, with a clear path from the corresponding ROS 2 concepts.
Flashback from node code
Declare an incident from a node’s own code, so a bumper or a grasp check saves the moment it sees.
Services and actions
A native request/response API for node authors on the shipped deterministic service layer, then actions: long-running goals with feedback, cancellation and streaming replies.
Pull-request verification
A GitHub reviewer that runs recorded regressions and cloud simulations, reports behavioral differences and preserves the evidence with the change.
Scenario libraries
User-defined environments and expected behavior, prior failure bags promoted to regression cases, and generated stress scenarios with reviewable test expectations.
Model and embodiment adapters
Develop the Robot Context Protocol (RCP) with versioned robot capabilities, model interfaces, execution feedback and recorded outcomes so models can move between embodiments.
Studio and agents
A tighter loop for inspecting data, changing code and replaying results; agent-controlled views and comparison of live runs, recordings and verification reports.
Platforms and interoperability
Windows support, broader hardware validation and easier exchange with existing robotics data tools.
Remote access
Hardening the account-based pairing and remote access layer: robot-side provisioning, hosted account services and grant management across owned and shared robots.
The roadmap is open for use cases and contributions: discuss a feature. Release changes are recorded in the changelog.
AGPL-3.0-only, with a commercial license available. The client-side cerulion_wire, cerulion_link, cerulion_ops_proto and cerulion_pairing crates are MIT OR Apache-2.0; each manifest states its license.
Citing Cerulion
Use GitHub’s Cite this repository button or CITATION.cff:
@software{cerulion,
author = {Sharma, Lakshay and Kariyawasam, Raveen and {Cerulion Inc. and contributors}},
title = {Cerulion: a robot runtime with byte-exact re-execution of recorded runs},
year = {2026},
version = {2.0.0},
url = {https://github.com/cerulion-inc/cerulion}
}
评论