Skip to main content
Basis is a robotics development framework by Basis Robotics that fundamentally changes how you write and test robot software. Instead of manually wiring up publishers and subscribers, you declare what your code needs — inputs, conditions, and outputs — and Basis generates all the plumbing for you.
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 a Inputs + 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.
Inputs arrive on topics

  Synchronizer checks conditions

  Handler fires with all inputs

  Outputs published to topics

Design goals

Basis has three main goals, in order of priority:
  1. Testability — Unit and integration tests should always produce the same result. Testing should never require manual process management.
  2. Usability — You declare the behavior you want. The framework handles the rest. You should never have to fight the framework.
  3. 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.
1

Set up your environment

Use the provided Docker image to get a complete build environment with all dependencies. See Environment Setup.
2

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.
3

Launch your robot

Compose Units into processes using launch files. Run everything with a single command. See Launch Files.
4

Test with replay

Record a real run to an MCAP file, then replay it deterministically in CI. See Deterministic Replay.

Build docs developers (and LLMs) love