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