Basis is alpha software. It is actively developed and may not be ready for all production use cases. We’d love your feedback on Discord.
Why Basis?
Traditional robotics frameworks like ROS require you to manually manage message subscriptions, callbacks, threading, and synchronization. This leads to complex, hard-to-test code where the same robot behavior may produce different results depending on timing. Basis inverts this model. You declare the behavior you want using aInputs + Conditions (synchronizer) → Handler → Outputs model. The framework manages all publishers, subscribers, and message routing automatically.
Get Started
Set up your development environment and build your first Unit
Core Concepts
Understand Units, pub-sub, synchronizers, and transport
Unit YAML Schema
Declare handlers, inputs, and outputs declaratively
Testing & Replay
Record and deterministically replay message streams for testing
Key features
Code generation
Declare your Unit’s behavior in YAML. Basis generates the C++ boilerplate — publishers, subscribers, synchronizers, and argument handling.
Deterministic replay
Record message streams to MCAP files and replay them deterministically. Get identical results every time, in CI and locally.
Plugin-based serialization
Use protobuf, ROS1 messages, or bring your own serializer. Basis doesn’t lock you in.
Plugin-based transport
Choose from inproc (shared pointer), TCP, and more. Control exactly how your messages flow.
Powerful synchronizers
Align messages across multiple topics by exact timestamp, approximate timestamp, rate, or “all received” — with accumulation and optional inputs.
Template-based launch files
Compose processes and Units declaratively using Jinja2-templated YAML launch files. Override arguments at runtime.
How Basis works
Basis is built around three core primitives: Units — The fundamental building block. A Unit is a C++ class that declares its message inputs and outputs. You implement handler functions; Basis calls them when all required inputs are available. Synchronizers — Determine when a handler fires. A handler can trigger when all inputs have arrived, when timestamps match exactly, when timestamps are approximately equal, or at a fixed rate. Transport — The mechanism by which messages move between Units. Basis supports inproc (zero-copy shared pointer), TCP, and is designed to be extended with additional transports.Design goals
Basis has three main goals, in order of priority:- Testability — Unit and integration tests should always produce the same result. Testing should never require manual process management.
- Usability — You declare the behavior you want. The framework handles the rest. You should never have to fight the framework.
- Performance — Inproc transport enables zero-copy message passing within a process. On-demand serialization means you only pay the cost of serialization when actually sending over the network or writing to disk.
Set up your environment
Use the provided Docker image to get a complete build environment with all dependencies. See Environment Setup.
Write your first Unit
Create a
.unit.yaml file declaring your handlers, inputs, and outputs. Run code generation to get a C++ base class. See Quickstart.Launch your robot
Compose Units into processes using launch files. Run everything with a single command. See Launch Files.
Test with replay
Record a real run to an MCAP file, then replay it deterministically in CI. See Deterministic Replay.