Skip to content

Architecture

Seven layers, one rule.

Layer 6   dashboard/        the operator's console: fleet, cameras, run, record, e-stop, passkeys
Layer 5   tools/            the agent @tool surface (14 tools) and the CLI, over RobotLike only
Layer 4   app/              Robot, PolicyRunner (RTC), teleop, Recorder impl, skills
Layer 3   sim/  policies/   MuJoCo first-class; Isaac + Newton adapters | lerobot_local, groot, cosmos3, mock, rl, microduck, wbc
Layer 2   drivers/  mesh/   13 native wires + the lerobot driver + twins | Zenoh transport, ACL, audit, e-stop lockout
Layer 1   registry/         declarative robots, policies, embodiments; the factories
Layer 0   core/             six contracts, UnitFrame, errors, types, knobs

A module at layer N imports only from layers below N. Siblings (drivers and mesh, sim and policies) never import each other. python3 scripts/check_layers.py walks the import graph and CI fails on any upward edge.

Two consequences:

  • Factories live in the registry. Robot() asks registry.make_driver or make_sim for a class by import string; a driver never builds a policy, a sim never knows a runner exists.
  • Tools depend on RobotLike, never on a concrete robot. An agent cannot reach a serial port except through the facade, where the clamp and the consent live.

Every module above layer 0 implements exactly one of the six contracts. Heavy imports (mujoco, torch, lerobot, zenoh, vendor SDKs) happen inside the function that needs them through core.optional.require, so import strands_robots is a no-op on a bare venv. Why the shape is what it is: VISION.md.