Architecture
OhhO OS is layered so that one API works across every robot and either runtime. The key idea: the robot and the middleware are swappable backends, not forks of your code.
The layers
Robot Abstraction Layer (RAL). The
RobotAPI —drive,move_joints,telemetry,emergency_stop,has— plus the capability model and a unified command/telemetry schema. Your code talks to this and nothing below it.Runtime port. A small interface (publish/subscribe, timers, parameters) that both backends implement. Engines depend on this port, never on a specific runtime.
Runtimes. The
nativeruntime (a pure-Python threaded scheduler with direct firmware / DDS / MAVLink drivers) and theros2runtime (rclpy plus the full ROS 2 stack — Nav2, SLAM, MoveIt 2, ros2_control). See Runtimes.Adapters. One per robot family, translating the native protocol to the RAL. v1.0.0 ships 6 adapters:
sim,yahboom(serial),feetech(arm),unitree(DDS),ros2(ROS 2 topics), andcomposite(base + arm merge).Engines. The agent (
ohho.brains.HarnessBrain), data collection (ohho.data.Recorder), training (ohho.train.finetune), and serving (ohho.serve) modules. All depend only on theRuntimeport and theTransportinterface.
The one invariant rule
Engines depend only on the Runtime port and the Transport interface —
never import rclpy, serial, lerobot, or a specific adapter directly. This
is what makes "switch runtime / robot with one argument" true. New backends and
adapters implement the interface; nothing above them changes.
Capability-typed commands
Commands are typed by capability. A robot that lacks a capability turns the command into a safe no-op rather than crashing, so a single behavior degrades gracefully across heterogeneous hardware.
if bot.has("manipulation"):
bot.move_joints([0, -0.5, 0.5, 0, 0, 0.2]) # runs on OmniBot
else:
bot.drive(vx=0.1) # graceful on Go2 (no arm)
The capability vocabulary: base.drive, base.holonomic_drive, legged.pose,
manipulation, perception.rgb, perception.depth.
Agent-native
The agent is a first-class part of the architecture, not a wrapper bolted on
top. HarnessBrain wires agent_engine.AgentHarness — a continuous
perceive → reason → act → reflect → remember loop with:
- A
ToolRegistrybuilt automatically from the robot's capabilities (drive,move_joints,stop,emergency_stop,get_telemetry,get_status). - A
RobotPerceptorthat turnsRobot.telemetry()into aWorldState. - A
ClaudeToolCallingReasonerover aReasoningRouter(cloud Claude whenANTHROPIC_API_KEY+anthropicare present, echo fallback otherwise). ScriptedBrainas the no-dependency fallback whenagent_engineisn't installed.
The record → train → serve loop
- Record:
Recorderwraps aRobot, interceptsdrive()andmove_joints()to capture actions, pollstelemetry()for state. Writes LeRobot v2.0 datasets (Parquet + meta JSON). - Train:
finetune()delegates tolerobot_engine(torch + LeRobot). Supports smolvla, act, diffusion, openvla.mock=Truefor sim loops. - Serve: FastAPI server with
/health,/load_model,/predict.ohho serveCLI. Mock model for sim.
See Training pipelines for the full guide.
Extending OhhO OS
- Add a robot: one manifest + one adapter + one test. See Contributing.
- Add a runtime: implement the
Runtimeport. - Add a skill:
@skilldecorator +register_skill(). See Skills.
No platform fork, no core rewrite.