Docs / Get started

Quickstart

Turn one recorded log into a regression test, run it on your laptop against main, and add it to CI. About 15 minutes if your stack already runs in a container.

Design preview. These docs describe how Invariant is being built. Commands, output and limits are illustrative until release, and stage tags mark what ships first. See the roadmap.

Preview. The CLI isn't publicly available yet. This page shows the intended first-release workflow, and the commands and output are illustrative. Want early access? Book a design-partner call.

Before you start: Docker, a container image of your stack, and one recorded log (MCAP or rosbag2) of a drive or task you care about.

1. Install the CLI MVP

curl -fsSL https://invariant.run/install.sh | sh
invariant doctor

invariant doctor checks Docker, GPU access (if any) and credentials, and prints what each runner type on this machine can do.

2. Create a spec

cd ~/nav_stack
invariant init

init looks at your repo and writes a starter invariant.yaml. If it finds a ROS 2 package it sets adapter: ros2 and fills in your launch file. Otherwise it uses the generic process adapter.

invariant.yamlsuite: laptop
system:
  build: { context: ., dockerfile: Dockerfile }   # one image per commit
  adapter: ros2
  ros2:
    distro: jazzy
    launch: nav_stack bringup.launch.py
    record: [/localization/pose, /tf]
scenarios: []
metrics:
  - localization_rmse: { tolerance: 0.005 }   # meters
runs: { paired: 3 }

3. Turn a log into a scenario

invariant scenario add --from-log logs/dock_0611.mcap \
  --name dock_approach_02 --start 0:42 --end 2:10 \
  --ground-truth /gt/pose

This adds a replay scenario: an 88-second slice of the log, played into your stack with sim time. --ground-truth names the topic used as truth (RTK or survey poses, for example). The log stays where it is. The spec only stores a reference and a content hash.

4. Run it against main

invariant run laptop --compare main

Invariant builds an image for your working tree and for main, tags each with its commit, runs each version 3 times on the same inputs, and prints a verdict per metric:

✓ build      nav_stack@working-tree · nav_stack@main
→ running    6 runs on local docker
✓ done       2m 14s

  verdict     scenario           metric              change     95% CI
  unchanged   dock_approach_02   localization RMSE   +0.001 m   −0.002 to +0.003

Three pairs is a smoke check that catches obvious changes and broken runs, not a precise measurement. Replay is close to deterministic. Simulated scenarios vary more from run to run and need more pairs, and covering more independent scenarios matters more than repeating one log. See How many runs.

5. Add it to CI

Copy the suite to a pr suite with more scenarios, and call the CLI from your CI job. The exit code tells CI whether to block the merge:

.github/workflows/invariant.ymlon: pull_request
jobs:
  invariant:
    runs-on: ubuntu-latest        # or your own GPU runner for simulation
    env:
      INVARIANT_TOKEN: ${{ secrets.INVARIANT_TOKEN }}
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }   # so --compare can find main
      - run: curl -fsSL https://invariant.run/install.sh | sh
      - run: invariant run pr --compare origin/main --summary summary.md
      - run: cat summary.md >> "$GITHUB_STEP_SUMMARY"
        if: always()

Next: read Core concepts, then the invariant.yaml reference.