Rivet is a domain-specific language (DSL) for designing Reactive State Machines for robotics and autonomous systems. It compiles high-level coordination logic into asynchronous, thread-safe C++.
A Rivet program is composed of System Modes, Nodes, and Modes.
System modes define the global states of the entire application.
systemMode Startup
systemMode Active
systemMode Shutdown
Nodes represent isolated processes, hardware drivers, or software modules.
node controller FlightCore : Autopilot
topic altitude = "nav/alt" : float // Published data stream
topic state = "sys/state" : string
// Handlers for remote requests (RPC)
onRequest arm() -> bool
log info "Arming System"
transition system "Active"
return true
// Internal private functions
func internalCalibrate() -> bool
return true
controller: Marks a node authorized to trigger globalsystemtransitions.ignore system: Prevents a node from automatically reacting to global system state changes.topic: Defines an output data stream (int,float,string,bool).onRequest: A public method reachable by other nodes viarequest.func: A private method for internal node logic.
Rivet utilizes a hybrid Publish-Subscribe and Request-Response model.
Nodes subscribe to data from other nodes using onListen.
node Perception : Lidar
// Automatically triggers adjust() when FlightCore publishes to 'altitude'
onListen FlightCore.altitude do adjust()
Nodes can explicitly trigger actions on other nodes.
mode FlightCore->Init
request Perception.scan() // Standard request
request silent Motors.calibrate() // Request without automatic logging
Modes define logic blocks that execute at specific state intersections.
The entry point for a node; runs exactly once upon instantiation.
mode FlightCore->Init
altitude.publish(0.0)
log "FlightCore initialized"
Logic that triggers automatically when the global SystemManager transitions.
mode Motors->Shutdown
request Motors.instantStop()
log warn "Motors reacting to global Shutdown"
Logic that is active only when the node itself is in a specific internal state.
mode Camera->Scanning
onListen Sensors.trigger do snap()
| Command | Description | Example |
|---|---|---|
log |
Formatted console output with node context | log warn "Battery at {val}%" |
print |
Raw standard output | print "DISK RECORD: {val}" |
transition |
Changes node or global system state | transition system "Active" |
publish |
Broadens data to a topic | state.publish("READY") |
return |
Exits a function with a return value | return true |
Supported levels: info, warn, error, debug.
Rivet is statically typed for safety:
int: 32-bit integers (42,-7)float: 64-bit floating point (3.14159)string: UTF-8 text strings ("Hello World")bool: Logic values (true,false)
- Authoring: Write your logic in a
.rvfile. - Compilation:
rivet.exe <script>.rv --cpp - C++ Build:
g++ <script>.rv.cpp -o <app_name> -std=c++17 -pthread - Deployment: Run the generated binary on your target hardware.