Layer 0 — Core Schemas & Exceptions
Part of the OpenRAL public-symbol inventory. Hand-curated;
(LNN)markers are refreshed bytools/refresh_methods_linenos.py.
Authoritative Pydantic v2 contracts (CLAUDE.md §1.3). Anything imported
from openral_core.__init__ is API; while we are pre-publish the
on-disk schemas sit at schema_version: "0.1" and the surface evolves
in place (CLAUDE.md §1.6).
python/core/src/openral_core/schemas.py
openral schema v0 — normative Pydantic v2 contracts for all layers.
Enums
class EmbodimentKind(str, Enum)— Top-level kinematic class. (L34)HUMANOID, MANIPULATOR, BIMANUAL, QUADRUPED, MOBILE_BASE, MOBILE_MANIPULATOR, DRONEclass JointType(str, Enum)— URDF joint type. (L46)REVOLUTE, PRISMATIC, CONTINUOUS, FIXED, FLOATING, PLANARJointRole: TypeAlias = Literal[…]— Structural classification of aJointSpec(ADR-0028a). (L57)"arm", "base", "gripper", "torso", "leg", "head", "neck", "wheel", "unknown". Used by runner/safety/dataset-bridge to identify a channel without name-substring heuristics. Default"unknown"keeps legacy manifests loadable.class ControlMode(str, Enum)— Action space / control interface. (L81)JOINT_POSITION, JOINT_VELOCITY, JOINT_TORQUE, JOINT_TRAJECTORY, CARTESIAN_POSE, CARTESIAN_DELTA, CARTESIAN_TWIST, BODY_TWIST, FOOT_PLACEMENT, GRIPPER_BINARY, GRIPPER_POSITION, DEX_HAND_JOINT, COMPOSITE_MODEconst BODY_TWIST_DIM: int = 6— Width of a BODY_TWIST / CARTESIAN_* twist row(vx, vy, vz, wx, wy, wz). Single source for the HAL packers (openral_hal.panda_mobile,openral_hal.sim_attached) + the safety supervisor that validate 6-vec twist payloads; matchesAction.body_twist(a 6-tuple). (L134)class SensorModality(str, Enum)— Physical sensing modality. (L147)RGB, DEPTH, STEREO, IR, POINT_CLOUD, LIDAR_2D, IMU, FORCE_TORQUE, JOINT_STATE, TACTILE_VISION, TACTILE_ARRAY, AUDIO, GPS, BATTERYclass Hand(str, Enum)— End-effector laterality. (L166)LEFT, RIGHT, NAclass StateRepresentation(str, Enum)— State vector format. (L590)JOINT_POSITIONS, EEF_POS_AXISANGLE, EEF_POS_EULER, EEF_POS_QUAT, EEF_POS_AXISANGLE_GRIPPERclass ActionRepresentation(str, Enum)— Action vector format. (L600)JOINT_POSITIONS, JOINT_VELOCITIES, DELTA_EE_6D_PLUS_GRIPPER, DELTA_EE_6D, CARTESIAN_POSEclass RSkillAction(str, Enum)— Closed vocabulary of high-level action verbs an rSkill can perform (ADR-0022); declared onRSkillManifest.actionsand surfaced to the reasoner LLM tool palette so it can pick a skill by what it does. (L610) Manipulation primitives:PICK, PLACE, PICK_AND_PLACE, TRANSFER, GRASP, RELEASE; articulated / contact-rich:OPEN, CLOSE, PUSH, PULL, SLIDE, INSERT, POUR, WIPE, ROTATE; motion:REACH; mobile:NAVIGATE; social/expressive:WAVE, SHAKE; generalist marker (foundation / multi-task checkpoints):GENERALIST; perception producer:DETECT(ADR-0037, forkind: "detector"rSkills); scene VLM:QUERY(ADR-0047, forkind: "vlm"rSkills).class QuantizationDtype(str, Enum)— Weight numeric format. (L2199)FP32, FP16, BF16, INT8, INT4, FP4_NVFP4class QuantizationBackend(str, Enum)— Inference backend. (L2223)PYTORCH, ONNX, TENSORRT, GGUF, MLXclass RSkillState(str, Enum)— Skill lifecycle. (L2295)UNCONFIGURED, INACTIVE, ACTIVE, FINALIZED, ERRORclass RSkillLicensePosture(str, Enum)— License posture (CLAUDE §7.4). (L2375)APACHE_2_0, MIT, BSD, PERMISSIVE_RESEARCH, NVIDIA_NON_COMMERCIAL, NVIDIA_OPEN_MODEL, RLWRLD_NON_COMMERCIAL, PROPRIETARY, UNKNOWN(NVIDIA_OPEN_MODEL = GR00T N1.7+, commercial OK — ADR-0046)class RSkillRuntime(str, Enum)— Manifest runtime hint. (L2389)PYTORCH, ONNX, TENSORRT, TRT_LLM, VLLM, GGUF, MLX, JAXclass PhysicsBackend(str, Enum)— Sim backend. (L4660)MUJOCO, MUJOCO_MJX, PYBULLET, ISAACSIM, GENESIS, MOCK
Pydantic models — robot manifest hierarchy
class IntrinsicsPinhole(BaseModel)— Pinhole camera intrinsics. (L177) fields:width, height, fx, fy, cx, cy, distortion_model, distortion_coeffsscale_intrinsics_to(base, width, height) -> IntrinsicsPinhole— Linearly rescale pinhole intrinsics to a new render resolution (fx/fy/cx/cy scale by width/height ratios; FOV and distortion preserved). ADR-0035: deploy-sim renders the same MuJoCo camera atscene.observation_width/height, so the HAL scales the manifest's nominal intrinsics to the render resolution before the depth back-projection — keeping the published camera model matched to what was rendered. Returnsbaseunchanged when the target equals its resolution; raisesValueErroron non-positive dims. (L205)class SensorSpec(BaseModel)— Generalizable sensor descriptor (all modalities).sim_camera_name: str | None(issue #191 Phase 3b, mirrorsJointSpec.sim_joint_name) carries the MJCF camera name when it differs from the sensorname—MujocoArmHAL.read_imagesrenderssim_camera_name or name(e.g. openarm'sbasesensor renders the MJCFtopcamera). (L259) fields:name, modality, frame_id, parent_frame, static_transform_xyz_rpy, rate_hz, intrinsics, encoding, fov_h_deg, fov_v_deg, n_channels, range_min_m, range_max_m, accel_noise_density, gyro_noise_density, n_axes, tactile_grid, vla_feature_key, ros2_topic, ros2_msg_type, qos_profile, vendor, model, driver_pkg, metadataclass SensorBundle(BaseModel)— Multi-modal sensor group. (L328) fields:bundle_name, sensors, sync, sync_tolerance_msclass JointSpec(BaseModel)— URDF-derived joint spec. (L347) fields:name, joint_type, parent_link, child_link, axis_xyz, origin_xyz, origin_rpy, position_limits, velocity_limit, effort_limit, has_position_sensor, has_velocity_sensor, has_torque_sensor, backlash_estimate, actuator_kind, sim_joint_name, role.origin_xyz/origin_rpy(ADR-0030) are the fixed parent-link→joint transform (URDF<joint><origin>); withaxis_xyzthey let the kernel compute forward kinematics for self-collision. Default zeros; populated by the offline lowering tool only for robots that enable collision checking.role(ADR-0028a) is aJointRoleliteral that downstream code reads to identify gripper / base / arm DoFs structurally instead of substring-matching the joint name (default"unknown").sim_joint_name(ADR-0025) carries the MJCF/MuJoCo joint name when it differs from the logicalname— used byopenral_sim.backends.robocasa.{synthesize_laser_scan_2d,read_panda_mobile_base_velocity},SimSensorBridge._compute_scan_ranges, andopenral_hal.sim_attached.SimAttachedHAL.read_stateto look upmj_name2idwithout hardcoding robosuite/robocasa naming.None= "MJCF name matchesname" (the common case for fixed-base manipulators). Population contract: a robot needssim_joint_namepopulated only when (a) its sim adapter doesmj_name2idon a joint name, AND (b) the loaded MJCF differs fromname. Today:panda_mobile(robocasa auto-prefixes withmobilebase0_*+robot0_*). LIBERO / ManiSkill3 / aloha / so100_robosuite / ur5e / widowx preserve URDF names — populatingsim_joint_namefor those is a no-op.openarm_robosuitedoes its own hardcodedmj_name2idlookups inenv.py:309-318(openarm_{side}_joint{i}) and is a candidate to refactor through this field.class EndEffectorSpec(BaseModel)— End-effector spec. (L418) fields:name, kind, hand, n_dof, max_grip_force_n, max_payload_kg, workspace_radius_m, tactile_sensors, actuated.actuated(ADR-0028a) defaults toTrue; setFalsefor passive tools (inert flanges, kinematic-only mounts) so the safety kernel can reject chunks addressed at them.class RobotCapabilities(BaseModel)— Capability flags for skill compatibility. (L456) fields:locomotion, can_lift_kg, has_dexterous_hands, has_tactile, has_force_control, has_vision, has_lidar, has_audio, bimanual, onboard_compute_tops, onboard_memory_gb, gpu_vram_gb, cuda_compute_capability, cuda_toolkit_version, tensorrt_version, gpu_supported_runtimes, gpu_supported_dtypes, supported_control_modes, supported_vla_embodiments, embodiment_tagsclass SafetyEnvelope(BaseModel)— Constraints enforced by C++ safety kernel. (L520) fields:workspace_box_min_xyz, workspace_box_max_xyz, no_go_zones, max_ee_speed_m_s, max_ee_accel_m_s2, max_joint_speed_factor, max_force_n, max_torque_nm, deadman_required, e_stop_topic, e_stop_qos, contact_force_threshold_n, cycle_time_violation_threshold_ms, human_in_loop_requiredclass ObservationSpec(BaseModel)— VLA observation config. (L661) fields:state_key, state_shape, state_representation, image_flip_180class ActionSpec(BaseModel)— VLA action config. (L678) fields:dim, representation, control_freq_hz, chunk_sizeclass ActionSlot(BaseModel)— One contiguous slice of an rSkill's action vector (ADR-0028b). fields:range, control_mode, discard, ee, frame, joint_names. Per-mode field requirements enforced by@model_validator: cartesian needs ee+frame, body_twist needs frame only, gripper needs ee only, joint needs neither (joint_names optional, length must equal slot width when supplied).discard=Trueslots drop their slice silently — used for dataset artefacts (RoboCasa365 torso placeholder, paired gripper channels).class ActionContract(BaseModel)— Per-rSkill action-vector contract (ADR-0019 + ADR-0028b). fields:dim, representation, slots. Whenslotsis set, every index in[0, dim)is covered by exactly oneActionSlot(@model_validatorrejects gaps + overlaps + over-range slots). Whenslots is None, the legacy single-Action JOINT_POSITION path applies (back-compat). Manifests carryingslotsare exempt from the ADR-0028adim <= len(robot.joints)invariant — the slot decoder gives a per-slice typed contract.class SphereShape(BaseModel)— Sphere collision primitive; discriminatorshape="sphere", fieldradius_m (>0). (ADR-0030, L835)class CapsuleShape(BaseModel)— Capsule collision primitive (segment along local +Z swept by a radius); discriminatorshape="capsule", fieldsradius_m (>0), length_m (>=0). (ADR-0030, L853)CollisionShape: TypeAlias = CapsuleShape | SphereShape— Discriminated union of convex collision primitives (discriminatorshape); mesh shapes excluded so the allocation-free kernel checks only analytic convex volumes. (ADR-0030, L882)class LinkCollisionGeometry(BaseModel)— One convex collision volume attached to a robot link; fieldslink_name, shape: CollisionShape, origin_xyz_rpy. Lowered, kernel-facing form (hand-authored or emitted by the offline lowering tool from MJCF/URDF). (ADR-0030, L894)class RobotDescription(BaseModel)— Top-level robot manifest, one per robot. (L1194) fields:name, embodiment_kind, assets, base_frame, odom_frame, map_frame, joints, end_effectors, sensors, sensor_bundles, capabilities, safety, ros2_namespace, middleware, onboard_compute, sdk_kind, hal, observation_spec, action_spec, sim, scene_defaults, base_joints, footprint_radius, base_kinematics, collision_geometry, allowed_collision_pairs, footprint_polygon.assets: AssetRefs(ADR-0058) is the single URDF/MJCF/SRDF reference block (default empty) — it replaces the former scatteredurdf_path,urdf_root_frame,static_base_to_urdf_root_xyz_rpy, andsrdf_pathfields (andSimDescription.mjcf_uri); refs share theopenral_core.assets.resolve_assetgrammar and the URDF'srobot_state_publisherwiring (root_frame+base_to_root_xyz_rpy, ADR-0027) lives onassets.urdf.collision_geometry: list[LinkCollisionGeometry]+allowed_collision_pairs: list[tuple[str, str]](ADR-0030) carry the per-link collision primitives and the self-collision allowed-collision matrix the safety kernel consumes; all default empty/Noneandjointsstays normative for the kinematic chain (URDF/SRDF add geometry + ACM only — the SRDFdisable_collisionsblock named byassets.srdfis the canonical source forallowed_collision_pairson real robots).footprint_radius: float | None(>0) +base_kinematics: Literal["differential","holonomic","omni","ackermann"] | None(ADR-0025) drive the generic Nav2 bringup (seenav2_param_overrides).footprint_polygon: list[tuple[float, float]] | None— optional base-frame XY polygon vertices (metres, CCW); when set, draws the true base outline on the SLAM occupancy grid instead of thefootprint_radiuscircle (ADR-0025).scene_defaults: SceneDefaults | None = None— Optional scene-level defaults (top-camera POV, etc.) consumed by the MJCF composers as the fallback when an environment does not pin its own values.validate_for_e2e_pipeline(self) -> None— Assert this manifest carries every field the e2e ROS graph (openral deploy sim→ C++ safety kernel) needs: every actuated joint must haveposition_limits,velocity_limit, andeffort_limitset. RaisesROSConfigErrorlisting every missing field at once — used bysim_e2e.launch.pyso a misshapen manifest fails at launch-parse time, not later in the HAL's first actuation tick. Pure validation; for synthesis of the kernelEnvelopeIntersectionuseopenral_safety.envelope_loader.compute_intersection(robot, skill=None).lidar_sensor(self) -> SensorSpec | None[@property] — First declaredlidar_2dSensorSpec(beam countn_channels,range_min_m/range_max_m,rate_hz), or None. Single source of truth for the synthetic/scanenvelope:openral deploy sim(deploy_sim._scan_params_from_description) forwards it as HALscan_*ROS params andSimSensorBridge(which owns/scanfor the manifest-driven node) reads the envelope from them, so neither hardcodes a scan envelope. ADR-0025.nav2_param_overrides(self) -> dict[str, str]— Nav2 param substitutions derived fromfootprint_radius(→robot_radiusand costmapinflation_radius=footprint_radius+NAV2_INFLATION_CLEARANCE_M, kept ≥ the inscribed/circumscribed radius Nav2 derives from the footprint) +base_kinematics(→ MPPImotion_model).{}for fixed-base arms.nav2.launch.pyRewrittenYaml-rewrites the shared base param file with these so one base file serves any mobile base — no hand-vendored per-robot Nav2 yaml. ADR-0025.class GripperReadMode(str, Enum)— HowMujocoArmHALreports the gripper qpos. (ADR-0023) Values:SUM_OVER_SCALE(Franka parallel — normalised to[0,1]),AFFINE_LOW_HIGH(SO-100 revolute Jaw — normalised to[0,1]),PASSTHROUGH(Aloha prismatic / OpenArm revolute — raw qpos in MJCF units).class GripperWriteMode(str, Enum)— HowMujocoArmHALmaps an Action's gripper value toctrl. (ADR-0023 bimanual amendment) Values:NORMALISED([0,1]→ctrl_range),PASSTHROUGH(raw →ctrl; MuJoCo clips).class SimGripperDescription(BaseModel)— Gripper wiring inside a MuJoCo MJCF. (ADR-0023) fields:joint, ctrl_range, qpos_addrs, qpos_scale, read_mode, write_mode, actuator_index, mirror_actuator_indexclass UrdfAsset(BaseModel)— A URDF asset reference plus itsrobot_state_publisherwiring. (ADR-0027 / ADR-0058) fields:ref: str(validated against theresolve_assetscheme grammar),root_frame: str | None(URDF root link when it differs frombase_frame),base_to_root_xyz_rpy: tuple[float×6] | None(staticbase_frame→root_frametransform [x,y,z,roll,pitch,yaw], metres+radians)class AssetRefs(BaseModel)— UnifiedRobotDescription.assetsblock: one URDF/MJCF/SRDF reference set replacing the former scattered asset fields. (ADR-0058 §4) fields:urdf: UrdfAsset | None,mjcf: str | None,srdf: str | None(the last two are bare refs, validated against the same scheme grammar; all defaultNone)class SimDescription(BaseModel)— OptionalRobotDescription.simblock holding MuJoCo joint↔qpos/qvel/actuator wiring forMujocoArmHAL.from_description; the MJCF itself is named byRobotDescription.assets.mjcf(ADR-0058). (ADR-0023) fields:floating_base, joint_qpos_addr, joint_qvel_addr, actuator_index, grippers, settle_steps_default, keyframe_index, seed_ctrl_from_qposclass HalEntrypoints(BaseModel)—RobotDescription.halblock: the robot's simulation + real-hardware HAL import strings, resolved byopenral_hal.build_hal. (ADR-0031) fields:sim: str | None(null → deriveMujocoArmHAL.from_descriptionwhen asim:block exists),real: str | None(null → simulation-only robot),parameters: HalParameters(per-robot HAL construction defaults; ADR-0029)class HalParameters(BaseModel)—RobotDescription.hal.parametersblock: per-robot HAL construction defaults (serialport,robot_ip, …) merged into the constructor byopenral_hal.build_hal(explicittransportwins; unaccepted keys dropped), so a parameterised robot needs no bespoke lifecycle subclass. Empty by default. (ADR-0029, issue #191) fields:defaults: dict[str, object]class TopCameraDefaults(BaseModel)— Default placement for the scene-level "top" / "base" camera consumed by sim backends that render an overview camera. (L926) fields:pos: tuple[float, float, float], target: tuple[float, float, float], fovy: float (gt=0, lt=180)- Replaces the dataset-specific
_DEFAULT_TOP_CAMERA_*module-level constants previously hard-coded inopenral_sim.backends.openarm_robosuite._assets. Backend YAML overrides (scene.backend_options.top_camera_*) still win — this submodel is the default fed to the composer. class SceneDefaults(BaseModel)— Per-robot scene rendering defaults consulted when the scene YAML does not override them. Fields:top_camera: TopCameraDefaults | None,composition: SceneComposition | None. (L991)class SceneComposition(BaseModel)— Declarative MJCF scene composition (issue #191 Phase 3b).composer: "module:fn"returning(xml, meshdir)+params: dict. The manifest-drivenManifestHALLifecycleNode._create_halcalls the composer and threads the composed MJCF in as the HAL'smjcf_path— replaced openarm's bespoke_create_haltabletop splicing. fields:composer: str,params: dict[str, object]fields:top_camera: TopCameraDefaults | None = None- First consumer is the
openarm_tabletop_pnpMJCF composer (openral_sim.backends.openarm_robosuite._assets.compose_openarm_tabletop_mjcf). Future scenes can extend this submodel as new defaults are pulled out of backend hardcodes.
Pydantic models — runtime snapshots
class JointState(BaseModel)— Real-time joint state snapshot. (L1595) fields:name, position, velocity, effort, stamp_nsclass Pose6D(BaseModel)— 6D pose (position + xyzw quaternion). (L1613) fields:xyz, quat_xyzw, frame_idclass DetectedObject(BaseModel)— Object detection. (L1627) fields:label, confidence, pose, bbox_3d, track_idclass WorldCollisionPrimitive(BaseModel)— A placed convex obstacle in the world (world-frame analogue ofLinkCollisionGeometry); fieldsshape: CollisionShape, pose: Pose6D, object_id: str | None. (ADR-0030, L1371)class OccupancyGridRef(BaseModel)— Reference to a 2D occupancy grid for mobile-base world-collision (mirrorsnav_msgs/OccupancyGridmetadata); fieldsframe_id, resolution_m (>0), width (>=0), height (>=0), origin: Pose6D, data_topic. (ADR-0030, L1395)class WorldState(BaseModel)— Snapshot consumed by Reasoner and Skills. (L1811) fields:stamp_ns, joint_state, base_pose, base_twist, ee_poses, contact_forces, images, image_frames, point_clouds, tactile, detected_objects, battery_pct, diagnostics, collision_primitives, occupancy_grid- collision_primitives / occupancy_grid (added ADR-0030) —
list[WorldCollisionPrimitive](default empty) +OccupancyGridRef | None(defaultNone): the bounded world surface the kernel's world-collision phase checks robot links against; an absent/stale world is treated as unavailable (fail-closed). - image_frames (added ADR-0010) —
dict[str, SensorFrame] | None. Optional in-process frame carrier for no-ROS deployments; defaultNonekeeps the existingimages: dict[str, str]topic-ref path unchanged.
Persistent spatial memory — scene graph (ADR-0038)
Advisory, queryable Layer-2 world model the S2 Reasoner consults to recall where objects/places/agents are. Never a safety input (the kernel gates only on the ADR-0030 geometric world). Poses anchored in the tf2 map frame.
class SpatialNodeKind(str, Enum)—OBJECT | PLACE | ROOM | AGENT. (ADR-0038)class SpatialRelationKind(str, Enum)—CONTAINS | AT_PLACE | TRAVERSABLE_TO | ON | NEAR. (ADR-0038)class SpatialNode(BaseModel)— A typed scene-graph node; superset ofDetectedObjectforkind=OBJECT. fieldsnode_id, kind, pose: Pose6D, label, confidence, bbox_3d, embedding_ref, is_container, occludes_contents, first_seen_ns, last_seen_ns, observation_count. Validators:last_seen_ns >= first_seen_ns;occludes_contentsrequiresis_container. (ADR-0038)class SpatialEdge(BaseModel)— Directed relation; fieldssrc, dst, kind: SpatialRelationKind. (ADR-0038)class SceneGraph(BaseModel)— Persistent scene-graph memory; fieldsschema_version="0.1", nodes: list[SpatialNode], edges: list[SpatialEdge]. Validators: uniquenode_id; every edge references an existing node. (ADR-0038)class RecallObjectQuery(BaseModel)— Read-only object recall; fieldstext, label, near: Pose6D | None, max_age_ns, limit. Validator: at least one oftext/labelnon-empty. (ADR-0038)class ApproachViewpoint(BaseModel)— Camera-facing standoff goal; fieldspose: Pose6D, standoff_m (>0), camera_frame_id. (ADR-0038)class RecallObjectMatch(BaseModel)— One ranked recall; fieldsnode_id, label, pose: Pose6D, score, last_seen_ns, approach: ApproachViewpoint | None, inside_container_id: str | None. (ADR-0038)class RecallObjectResult(BaseModel)—matches: list[RecallObjectMatch](empty = unknown → caller raisesROSObjectNotInMemory). (ADR-0038)class ResolvePlaceQuery(BaseModel)— Resolve a place/room/agent reference; fieldsreference, kind: SpatialNodeKind | None. (ADR-0038)class ResolvePlaceResult(BaseModel)— fieldsnode_id, goal: Pose6D, path_node_ids: list[str](atraversable_topath). (ADR-0038)class Action(BaseModel)— Action step or chunk produced by a Skill. (L551) fields:control_mode, horizon, joint_targets, joint_velocities, joint_torques, cartesian_pose, cartesian_delta, cartesian_twist, body_twist, foot_placements, gripper, dex_hand_joints, confidence, stamp_ns, ee_name, frame_id, safety_overridesclass QuantizationConfig(BaseModel)— Quantization recipe. (L644) fields:dtype, backend, per_channel, calibration_dataset, extraclass DeviceInfo(BaseModel)— Host compute snapshot. (L668) fields:device_str, gpu_memory_bytes, cuda_compute_capability, cpu_count, archclass RSkillInfo(BaseModel)— Skill runtime state snapshot. (L720) fields:name, version, state, weights_loaded, quantized, warmed_up, embodiment_tags, role, latency_budget_ms, last_inference_ms, error_msg, stamp_ns
Pydantic models — skill packaging (rSkill)
class RSkillLatencyBudget(BaseModel)— Per-stage latency budget. (L799) fields:per_chunk_ms, warmup_ms, load_msclass SensorRequirement(BaseModel)— One sensor an rSkill needs the robot to provide. (L980) fields:modality, vla_feature_key, min_width, min_height, countclass ControlModeSemantics(BaseModel)— Action-space semantics on eachActuatorRequirement(rSkill self-containment audit, Gap 2). (L1180) fields:mode: Literal["absolute","delta"], gripper_convention, joint_order, reference_frame- Cross-validator on
ActuatorRequirement: gripper kinds REQUIREgripper_convention; cartesian kinds REQUIREreference_frame; other kinds forbid both. GripperConvention(TypeAlias = Literal[...]) — Closed gripper-action encoding set. Members:normalized_open_unit, normalized_open_symmetric, binary_close_one, raw_joint_rad, width_meters. (L1147)class ActuatorRequirement(BaseModel)— One actuator slot an rSkill emits actions for (ADR-0013). (L1198) fields:kind, n_dof, vla_action_key, control_mode_semanticskindreusesControlMode;n_dof/vla_action_keyauto-fill from the robot YAML for canonical embodiments, REQUIRED on the manifest for the"custom"hatch.control_mode_semanticsis REQUIRED per the rSkill self-containment audit (Gap 2): declares absolute-vs-delta and (when applicable) gripper convention / reference frame.class EmbodimentExtra(BaseModel)— Sensor + actuator surface for the"custom"embodiment hatch (ADR-0013). (L1304) fields:sensors: list[SensorRequirement] (≥1), actuators: list[ActuatorRequirement] (≥1)class RSkillProcessors(BaseModel)— Explicit lerobotPolicyProcessorPipelineartefact pointers (rSkill self-containment audit, Gap 1 + Gap 3). (L1402) fields:preprocessor_uri, postprocessor_uri- Per-file URI shape
hf://owner/repo[@rev]/path/to/file.ext(file tail REQUIRED — bare repo URIs are the implicit-snapshot shape we deliberately replaced). - Cross-validator rejects identical pre/post URIs.
class RosIntegration(BaseModel)— Wiring for a wrapped ROS 2 action / service (ADR-0024). Required whenRSkillManifest.kind in {"ros_action", "ros_service"}; forbidden otherwise. (L2783) fields:package, interface_type, interface_name, result_trajectory_field, default_goal_json, ros_dependenciesresult_trajectory_field is None→ result-only mode (Nav2 shape); set → trajectory mode (MoveIt shape, adapter replays one waypoint perstep()).default_goal_jsonvalidator round-trips the literal throughjson.loadsand rejects non-dict payloads.class DetectorEngine(str, Enum)— Backend selector forkind: "detector"rSkills (ADR-0037 2026-06-12 amendment):RTDETR_ONNX = "rtdetr_onnx",VLM_SIDECAR = "vlm_sidecar",ZEROSHOT_HF = "zeroshot_hf". Set onDetectorContract.engineto disambiguate backends that share aruntime(the VLM sidecar and the in-process Transformers zero-shot detector are bothruntime: pytorch);Nonekeeps the legacyruntime-keyed dispatch.class DetectorMode(str, Enum)— Invocation mode of akind: "detector"rSkill (ADR-0051), orthogonal toDetectorEngine:CONTINUOUS = "continuous"(always-on background producer →WorldState.detected_objects; reasoner reads it passively, never prompts it; not ExecuteSkill-dispatchable) andON_DEMAND = "on_demand"(prompted open-vocab locator surfaced via thelocate_in_viewtool). Cleanly separates open-vocabulary from prompting: continuous detectors cover a fixed bank the reasoner reads for free; the on-demand locator handles the long tail.class DetectorContract(BaseModel)— Manifest contract forkind: "detector"rSkills (ADR-0037). Required whenRSkillManifest.kind == "detector"; forbidden otherwise. Frozen,extra="forbid". (L2878) fields:labels: list[str](min_length=1; class-label list indexed by model class-id),input_size: tuple[int, int](width × height, both > 0; default (640, 640)),score_threshold: float(ge=0.0 le=1.0; default 0.5),engine: DetectorEngine | None(default None; explicit backend selector — ADR-0037 2026-06-12 amendment),mode: DetectorMode(defaultcontinuous; invocation mode — ADR-0051).class RewardContract(BaseModel)— Manifest contract forkind: "reward"rSkills (ADR-0057; Robometer-4B reward monitor). Required whenRSkillManifest.kind == "reward"; forbidden otherwise. Frozen,extra="forbid". fields:progress_range: tuple[float, float](default (0.0, 1.0); validated max > min),success_threshold: float(ge=0.0 le=1.0; default 0.5),preference: bool(default False),frame_window_s: float(> 0; rolling-buffer horizon),target_fps: float(> 0; sampling rate),num_bins: int(> 0; default 100; discrete-mode progress bins → normalized [0,1]),instruction_required: bool(default True). A reward monitor is a pure perception consumer: no actuators, no action/state contract; its progress/success signal is advisory-only.class RSkillManifest(BaseModel)—rskill.yamlmanifest (schema_version="0.1"; pre-publish surface — ADR-0013 / ADR-0022 / ADR-0024 / ADR-0037 each extended it in place without bumping). (L2931) fields:schema_version, name, version, license, role, kind, model_family, embodiment_tags, embodiment_extra, capabilities_required, sensors_required, actuators_required, runtime, quantization, weights_uri, chunk_size, latency_budget, min_vram_gb, fallback_skill_id, benchmarks, paper_url, dataset_uri, source_repo, description, actions, objects, scenes, processors, image_preprocessing, state_contract, action_contract, n_action_steps, ros_integration, detector. ADR-0019 amendment:action_contract(mirrorsstate_contract) declares the per-checkpoint action dim consumed by the dataset bridge. ADR-0022 amendment:descriptionis now REQUIRED (was optional) and three new fields surface skill semantics to the reasoner LLM tool palette —actions: list[RSkillAction](closed-vocabulary, REQUIRED; min_length enforced per-kind in_check_kind_consistency),objects: list[str](free-form discriminative keywords),scenes: list[str](free-form). ADR-0024 amendment:kind: RSkillKindis REQUIRED (no default);model_familyandweights_uribecame optional and are gated onkind == "vla"; new optionalros_integration: RosIntegration | Noneblock. ADR-0037 amendment: newkind: "detector"value + optionaldetector: DetectorContract | Nonefield (required iffkind == "detector");actuators_requiredconstraint relaxed from global min_length=1 to per-kind enforcement in_check_kind_consistency(detectors have no actuators). ADR-0047 amendment: newkind: "vlm"value for video-language scene-understanding models (role: s2; no actuators, no action/state contract, no detector block);RSkillActiongainsQUERY = "query". Perception amendment:embodiment_tagsconstraint relaxed from globalmin_length=1to per-kind enforcement in_check_embodiment_tags_present— perception kinds (detector/vlm/reward,_PERCEPTION_KINDS) are embodiment-agnostic and ship emptyembodiment_tags(match-any); every other kind still requires ≥1 tag. ADR-0057 amendment: newkind: "reward"value for robotic reward/progress monitors (role: s2; no actuators, no action/state contract) + optionalreward: RewardContract | Nonefield (required iffkind == "reward");RSkillActiongainsMONITOR = "monitor".from_yaml(cls, path: str) -> RSkillManifest[@classmethod] — Load and validate anrskill.yaml.is_commercial_use_allowed: bool[@property] — Derived fromlicense: True for apache-2.0/mit/bsd, False otherwise (incl. unknown). Replaces V0's free-fieldcommercial_use_allowed.- ADR-0013 cross-validators:
"custom" ∈ embodiment_tags ↔ embodiment_extra is not None; when"custom"is present everyactuators_requiredentry must carry bothn_dofandvla_action_key. - rSkill self-containment audit cross-validator:
processorsREQUIRED whenmodel_family in {smolvla, pi05, xvla, diffusion, rldx}; onlyactmay omit it (legacy norm-stats-in-safetensors path). - ADR-0024 / ADR-0037 cross-validator (
_check_kind_consistency):kind == "vla"requiresmodel_family+weights_uri+ ≥1actuators_required, forbidsros_integration+detector.kind in {"ros_action","ros_service"}requiresros_integration+ ≥1actuators_required, forbidsmodel_family/weights_uri/processors/state_contract/action_contract/n_action_steps/image_preprocessing/starting_pose/detector, pinschunk_size == 1.kind == "detector"(ADR-0037) requiresdetector+weights_uri, forbidsmodel_family/ros_integration/action_contract/state_contract/processors/n_action_steps/starting_pose, requires emptyactuators_required.kind == "wam"validates schema-side; the loader rejects it at resolve time. - The historical
policy_idfield was removed in favour of dispatching onmodel_familydirectly. EmbodimentTag(TypeAlias = Literal[...]) — Closed canonical robot embodiments matchingrobots/*/robot.yaml, plus"custom"escape hatch and"mobile_base"class tag for any planar-base robot (so base-only rSkills like Nav2 can target the class without naming each specific mobile platform). (L2596)StateLayout(TypeAlias = Literal[...]) — Closed set of per-checkpoint proprioception layouts:smolvla_9d, human300_16d, gr1, rc365, simpler_widowx, simpler_google. Names the SHAPE the checkpoint was trained on (field order, frame convention, gripper encoding, quaternion handedness). Per-robot SOURCE bindings live onStateContractBindings. ADR-0027. (Thepi0_16d/eef_pose_7d/base_pose_7drobocasa sim-observation layouts were removed — no state-adapter assembler existed; recreate alongside an assembler when next needed.)WRAPPED_TASK_SPACE_LAYOUTS: frozenset[StateLayout]— Subset ofStateLayoutcovering Cartesian/FK-derived composites:{rc365, human300_16d}. These layouts REQUIREStateContract.bindings; the cross-validator onStateContractenforces this at manifest load. Joint-space layouts (smolvla_9d,gr1,simpler_*) are excluded — they're served verbatim from rawJointState.position. ADR-0027.StateContractBindings(Pydantic model) — Per-robot source bindings for an rSkill'sstate_contract.layout. Fields:eef_frame: str | None,base_frame: str | None,world_frame: str | None = "map",gripper_qpos_joints: list[str],quaternion_convention: Literal["xyzw","wxyz"] = "xyzw". Symmetric toControlModeSemanticson the action side. Required whenStateContract.layoutis inWRAPPED_TASK_SPACE_LAYOUTS, forbidden otherwise. ADR-0027.BenchmarkName(TypeAlias = Literal[...]) — Closed canonical benchmark suite ids matchingbenchmarks/*.yaml. Members:aloha_insertion, aloha_transfer_cube, gr1_tabletop, libero_10, libero_goal, libero_object, libero_spatial, maniskill3_franka_pick_cube, maniskill3_pick_place, metaworld_mt50, pusht, robocasa_pnp, simpler_env_widowx. (L2633)ModelFamily(TypeAlias = Literal["smolvla","pi05","xvla","act","diffusion","rldx","molmoact2","gr00t"]) — Closed VLA/policy family used by the eval/runner adapter dispatch. Required only whenRSkillManifest.kind == "vla".gr00t(NVIDIA Isaac GR00T) runs out-of-process via a ZMQ sidecar, reusing therldxadapter — ADR-0046. (L2655)RSkillKind(TypeAlias = Literal["vla","wam","ros_action","ros_service","detector","vlm"]) — Discriminator selecting the loader / runner branch (ADR-0024 + ADR-0037 + ADR-0047)."vla"is today's learnable policy path;"ros_action"/"ros_service"route throughROSActionRskill;"wam"is reserved (loader rejects at resolve time);"detector"(ADR-0037) is a perception producer that runs an exported ONNX/TRT detection model and publishesObjectsMetadata— emits noAction;"vlm"(ADR-0047) is a video-language model answering natural-language scene queries from camera frames — emits text, no actions/boxes,role: s2(reached via the read-onlyquery_scenetool, notExecuteSkill). (L2752)
Pydantic models — skill benchmark results (rskills/<id>/eval/<benchmark>.json)
class RSkillEvalSource(BaseModel)— Provenance of a benchmark block. (L985) fields:paper, arxiv, model_variant, evaluated_by, reproduced_locally, reproduction_planned, reproduction_cli, table, statusclass RSkillEvalBenchmark(BaseModel)— Suite identity for a benchmark block. (L1023) fields:name, dataset, protocol, robot, simulatorclass RSkillEvalResult(BaseModel)— On-disk shape ofrskills/<id>/eval/*.json. Carries an optionaltrace_id: str | None(32-hex) populated byopenral benchmark runfor offline cross-reference into the OTel trace tree. (L1042) fields:schema_version, source, benchmark, eval_config, results, baselinesfrom_json(cls, path: str) -> RSkillEvalResult[@classmethod] — Load and validate a single benchmark JSON. (L1083)
Pydantic models — sim eval
class SceneSpec(BaseModel)— Physics scene declaration. (L1283) fields:id, backend, assets_uri, observation_height, observation_width, cameras, backend_optionsclass RoboCasaBackendOptions(BaseModel)— Typed validator forSceneSpec.backend_optionsunder the RoboCasa backend (ADR-0015). Prebuilt-vs-procedural XOR enforced by amodel_validator. (L1324) fields:mode, prebuilt_task, kitchen_style, layout_id, fixtures, spawn_objects, task_verb, robots, controller, horizonclass TaskSpec(BaseModel)— What the robot must achieve. (L4500) fields:id, scene_id, instruction, max_steps: int | None, success_key: str | None, metadataclass VLASpec(BaseModel)— Policy / brain declaration. (L1029) fields:id, weights_uri, device, runtime, quantization, deterministic, extraclass SimEnvironment(BaseModel)— Runtime (robot × scene × task × VLA) tuple. Composed at the CLI from aSimSceneorBenchmarkSceneYAML plus anRSkillManifest(--rskill); never loaded from YAML directly. (L2343) fields:robot_id, scene, task, vla, base_pose, seed, n_episodes, record_video, save_dir, metadatabase_pose: Pose6D | None = None— Per-rollout robot mounting pose in the scene's world frame; honoured by free-axis scenes only. See ADR-0002 (Amendment 3).model_post_init(_context: object) -> None— Cross-field validationtask.scene_id == scene.id. (L2389)from_yaml(cls, path: str) -> SimEnvironment[@classmethod] — Deprecated shim; always raisesROSConfigErrordirecting the caller toSimScene.from_yaml(path) + --rskill rskills/<id>. (L2405)class BenchmarkMetadata(BaseModel)— Provenance block required on everyBenchmarkScene; fields:paper: str,honest_scope: str, optionaldisplay_name: str | None, optionalsimulator: str | None. The two optional fields (ADR-0042) becomeRSkillEvalResult.benchmark.name/.simulatorwhen present; suite invariants treat the whole block as byte-identical across scenes. (L4687)class DeployScene(BaseModel)— Env-only scene foropenral deploy run; carriesscene,robot_id, andbase_pose; no task or eval config. Rejects legacyvla:blocks. (L4711)from_yaml(cls, path: str) -> DeployScene[@classmethod] — Load and validate aDeploySceneYAML from disk. (L4734)class SimScene(DeployScene)— ExtendsDeployScenewithtask,seed,n_episodes,record_video,save_dir,metadata; cross-validatestask.scene_id == scene.id; accepted byopenral sim run. (L4743)from_yaml(cls, path: str) -> SimScene[@classmethod] — Load and validate aSimScene(orBenchmarkScene) YAML from disk. (L4770)class BenchmarkScene(SimScene)— ExtendsSimScenewith requiredn_episodes,seed, andmetadata: BenchmarkMetadata; also requirestask.success_keyandtask.max_steps; consumed byopenral benchmark. (L4779)from_yaml(cls, path: str) -> BenchmarkScene[@classmethod] — Load and validate aBenchmarkSceneYAML; raisesValidationErrorif eval fields are missing. (L4808)class ProtocolSpec(BaseModel)— Standalone eval-protocol schema (ADR-0009). Retained as a public surface for ADR drafts and report tooling that quote a published protocol verbatim; never embedded in a benchmark suite (Task 10 of ADR-0041 flattened the per-scene fields ontoBenchmarkScene; ADR-0042 then deleted theBenchmarkSpecwrapper entirely so a suite is now a barelist[BenchmarkScene]). (L1386) fields:n_episodes, seeds, success_key, max_steps, min_repsmodel_post_init(_context: object) -> None— Cross-field validation:len(seeds) >= n_episodesandmin_reps <= n_episodes. (L1427)
Pydantic models — inference runner (ADR-0010)
On-disk + runtime contracts for the hardware inference runner (openral deploy --config R.yaml), sibling of SimEnvironment / openral sim run. Schemas are additive — SimEnvironment / RSkillEvalResult / BenchmarkScene are untouched.
class FrameEncoding(str, Enum)— HowSensorFramebytes are interpreted. (L557)BGR8, RGB8, MONO8, DEPTH16, JPEG, PNG, CUDA_NV12, RAWclass SensorFrame(BaseModel)— Single sensor frame: metadata + optional inline / topic / handle payload. JSON-serializes the binary payload as base64. (L576) fields:sensor_id, stamp_monotonic_ns, stamp_wall_ns, encoding, width, height, channels, data, topic, handle, metadata_decode_data(cls, value: Any) -> bytes | None[@field_validator("data", mode="before")] — Accept rawbytesor a base64-encodedstron JSON parse. (L614)_encode_data(self, value: bytes | None) -> str | None[@field_serializer("data", when_used="json")] — JSON-serialize the binary payload as base64. (L632)model_post_init(_context: object) -> None— Cross-field validation: exactly one of(data, topic, handle)must be set. (L637)class SensorReaderBackend(str, Enum)— WhichSensorReaderimplementation a sensor uses. (L1691)OPENCV_THREAD, ROS2_IMAGE, GSTREAMERclass DeadlineOverrunPolicy(str, Enum)— Behaviour when a tick exceeds1 / rate_hz. (L1706)WARN, DROP, RAISEclass SensorReaderConfig(BaseModel)— Per-sensor reader backend + optional ROS-tee. (L1720) fields:sensor_id, backend, backend_params, max_age_ms, publish_to_ros, publish_topic, publish_rate_hzmodel_post_init(_context: object) -> None— Cross-field validation:publish_to_ros ↔ publish_topic. (L1774)class HalConfig(BaseModel)— Which HAL adapter to instantiate + transport params (serial port / FCI URI / ROS namespace). (L1786) fields:adapter, transport, paramsclass RobotEnvironment(BaseModel)— Full hardware deployment configuration;openral deployartefact. Sibling ofSimEnvironment. (L1819) fields:robot_id, hal, sensors, task, vla, safety, rate_hz, thumbnail_hz, deadline_overrun_policy, max_ticks, save_dir, metadata(thumbnail_hz: float = 25.0, ge 0 — per-camera dashboard thumbnail rate, 0 disables)model_post_init(_context: object) -> None— Cross-field validation: unique sensor ids +vla.weights_urimust be a valid skill reference (bare name,rskills/<name>, or HF repo id — norskill://scheme). (L1900)from_yaml(cls, path: str) -> RobotEnvironment[@classmethod] — Load and validate aRobotEnvironmentYAML from disk. (L1918)class TickResult(BaseModel)— One tick's record returned byInferenceRunner.tick. v2 (ADR-0010 amendment 1) adds five optional sim-only fields (step_idx,episode_idx,reward,terminated,truncated) and an optionaltrace_context: str | None(full W3Ctraceparentfor the tick'srskill.tickspan). All optional fields default toNone; hardware ticks that don't carry sim metadata or a live trace context serialise byte-identically to v1 underexclude_none=True. (L1937) fields:stamp_ns, tick_idx, sensors_ms, world_state_ms, inference_ms, safety_ms, hal_ms, tick_ms, chunk_index, safety_violations, action_applied, step_idx, episode_idx, reward, terminated, truncatedclass RunResult(BaseModel)— Aggregated summary returned byInferenceRunner.run. (L1980) fields:n_ticks, success, budget_violations, avg_inference_ms, p99_inference_ms, avg_tick_ms, p99_tick_ms, trace_id, save_dir, metadata
Pydantic models — failure evidence (ADR-0018 F3)
Discriminated union backing the evidence_json field of openral_msgs/msg/FailureTrigger. Discriminator is the kind field (a Literal[...] on each variant); decode via pydantic.TypeAdapter(FailureEvidence).validate_json(...). All variants are frozen=True and extra="forbid".
class _FailureEvidenceBase(BaseModel)— Private base,frozen=True,extra="forbid". (L3064)class TimeoutEvidence(L3075) —kind="timeout"; fieldsoperation, deadline_s, elapsed_s.class ForceEvidence(L3092) —kind="force"; fieldsjoint_or_ee, measured_n, limit_n.class WorkspaceEvidence(L3108) —kind="workspace"; fieldsee_name, measured_xyz, box_min, box_max.class PerceptionStaleEvidence(L3126) —kind="perception"; fieldssensor_id, staleness_ms, threshold_ms.class CriticEvidence(L3142) —kind="critic"; fieldscritic_id, score, threshold.class ControllerEvidence(L3158) —kind="controller"; fieldscontroller_name, state, detail.class SelfVerifyEvidence(L3174) —kind="selfverify"; fieldscheck, expected, observed.class HumanEvidence(L3190) —kind="human"; fieldsactor, reason.class WamEvidence(L3204) —kind="wam"; fieldshorizon, discrepancy, wam_id.class ReasonerTimeoutEvidence(L3220) —kind="reasoner_timeout"; fieldsmodel, deadline_s, elapsed_s.class CollisionEvidence(L4694) —kind="collision"; fieldscollision_kind: Literal["self"|"world"], link_a, link_b_or_object, horizon_step, min_distance_m. Maps toFailureTrigger.KIND_COLLISION = 10(ADR-0030).class SuppressedSummaryEvidence(L3236) —kind="suppressed_summary"; fieldswindow_s, kinds: list[int], severities: list[int], counts: list[int]. Model-validator enforces parallel arrays (raisesROSConfigError).FailureEvidence: TypeAlias(L3270) — Discriminated union over the twelve variants above. Module docstring shows the encode/decode pattern.
Pydantic models — perception event metadata (ADR-0018 F6)
Discriminated union backing the metadata_json field of openral_msgs/msg/PromptStamped when published on /openral/perception/<kind>. Discriminator is the kind field (a Literal[...] on each variant); decode via pydantic.TypeAdapter(PerceptionEventMetadata).validate_json(...). All variants are frozen=True and extra="forbid". New kinds = new topics, not a schema bump.
class _PerceptionEventBase(BaseModel)— Private base; carriessensor_id: str. (L3304)class ObjectDetection2D(BaseModel)(L3323) — single 2D detection insideObjectsMetadata; fieldslabel, confidence, bbox_xyxy.class MotionMetadata(L3344) —kind="motion"; fieldsmagnitude, threshold, region_bbox.class ObjectsMetadata(L5070) —kind="objects"; fieldsdetections: list[ObjectDetection2D], model_id, frame_width: int (>0), frame_height: int (>0). ADR-0035:frame_width/frame_heightadded to make the pixel space ofbbox_xyxyexplicit so theVoxelFrustumLiftercan scale to the intrinsics resolution (CLAUDE.md §1.4). Producers (ObjectsDetector,NvmmObjectsDetector) populate both at detect-time.class OcrMetadata(L3386) —kind="ocr"; fieldstext, confidence, region_bbox.class SceneChangeMetadata(L3404) —kind="scene_change"; fieldsdistance, threshold, metric.PerceptionEventMetadata: TypeAlias(L3427) — Discriminated union over the four variants above. Module docstring shows the encode/decode pattern.
Pydantic models — reasoner tool calls (ADR-0018 F4)
Discriminated union over the closed palette of typed tool calls the F4 reasoner can emit each tick. Discriminator is the tool field (a Literal[...] on each variant); decode via pydantic.TypeAdapter(ReasonerToolCall).validate_json(...). All variants are frozen=True and extra="forbid" so an LLM cannot smuggle ad-hoc fields onto the wire. The reasoner holds no authority over actuation — it never publishes ActionChunk; ExecuteRskillTool is indirect (action goal on the F1 server which gates through F5 safety).
class _ReasonerToolBase(BaseModel)— Private base; carries optionalrationale: str. (L3455)class ExecuteRskillTool(L3480) —tool="execute_rskill"; fieldsrskill_id, prompt, deadline_s.class ReloadGstPipelineTool(L3508) —tool="reload_gst_pipeline"; fieldssensor_id, pipeline_yaml.class LifecycleTransitionTool(L3532) —tool="lifecycle_transition"; fieldsnode, transition: Literal["configure"|"activate"|"deactivate"|"cleanup"].shutdownis intentionally absent — shutdown is the safety supervisor's authority per CLAUDE.md §6 Layer 6. ADR-0025: this is the canonical primitive for managing long-lived background services (slam_toolbox, RTAB-Map, perception trees) — they are LifecycleNode peers, not rSkills.class EmitPromptTool(L3556) —tool="emit_prompt"; fieldstarget_topic(must start with/),text,metadata_json.class RecallObjectTool— read-only query (ADR-0039);tool="recall_object"; fieldsquery(free-text/label),limit. Recalls an object from the ADR-0038 scene-graph memory; no actuation authority. Dispatch + result-return is ADR-0039 Phase 2 (not yet in the live provider palette).class ResolvePlaceTool— read-only query (ADR-0039);tool="resolve_place"; fieldreference("the kitchen", "where I was standing"). Resolves a place/room/agent to a goal pose + path; no actuation authority. Dispatch is ADR-0039 Phase 2.class LocateInViewTool— read-only query (ADR-0043);tool="locate_in_view"; fieldsquery(object to look for),camera(optional viewpoint id, default""= primary — camera-agnostic, not a hardcoded name),detector(ADR-0056 — optional on-demand locator selector / alias, default""= the deployment default; the reasoner routes to/openral/perception/<detector>/locate_in_view). Asks a live VLM detector if the object is in the CURRENT frame (vsrecall_object's remembered objects). No actuation authority — choosing a model does not grant it.class QuerySceneTool— read-only query (ADR-0047);tool="query_scene"; fieldsquestion(open-ended scene-state question, min_length=1),camera(optional viewpoint id, default""). Asks a scene VLM (Qwen3.5-4B) an open-ended question about the CURRENT frame for task-progress / success verification; dispatched via/openral/perception/query_scene, answer fed back as a re-prompt. Distinct fromlocate_in_view(localization → boxes): returns free text. No actuation authority.class QueryTaskProgressTool— read-only query (ADR-0057);tool="query_task_progress"; fieldswindow_s(seconds of recent frames to assess, > 0, default 8.0),task(optional instruction override, default""→ reuse the active goal). Asks the Robometer reward monitor for a quantitative windowed assessment of the CURRENT task; dispatched via/openral/perception/query_task_progress, the verdict (progress/success now + trends +stalled/succeeded) fed back as a re-prompt driving the replanning ladder. Distinct fromquery_scene(free text): returns normalized scalars. No actuation authority.ReasonerToolCall: TypeAlias— Discriminated union over the eight variants above (four actuation/effect + four ADR-0039/0043/0047 read-only query). Module docstring shows the encode/decode pattern.
Module-level functions (Layer 0)
def control_modes_for_representation(rep: ActionRepresentation) -> set[ControlMode](L2376) — ADR-0036. Maps a VLA's declaredActionRepresentationto the set ofControlModes it drives (JOINT_POSITIONS→{JOINT_POSITION},JOINT_VELOCITIES→{JOINT_VELOCITY},DELTA_EE_6D→{CARTESIAN_DELTA},DELTA_EE_6D_PLUS_GRIPPER→{CARTESIAN_DELTA, GRIPPER_POSITION},CARTESIAN_POSE→{CARTESIAN_POSE}). Single source of truth for the reasoner's deploy-path palette gate (a skill is offered only when the target robot advertises every returned mode).SIM_EXECUTABLE_CONTROL_MODES: frozenset[ControlMode](L2492) — ADR-0036 (amended 2026-06-04). Canonical set ofControlModes the default sim HAL action-packers can execute, and the single source of truth for the reasoner'shal_mode == "sim"deploy-path palette gate:{JOINT_POSITION, JOINT_VELOCITY, CARTESIAN_DELTA, GRIPPER_POSITION, BODY_TWIST, COMPOSITE_MODE}. MirrorsCONTROL_MODE_TO_UINT8as a shared core constant (core is a dep of both reasoner and HAL). Pinned in both directions to the packers inpython/hal/src/openral_hal/sim_attached.py(pack_action_for_env,SimAttachedHAL._pack_with_composite_split, and theBODY_TWISTdirect-qpos path) bytests/unit/test_sim_executable_modes_match_packers.py. ExcludesJOINT_TORQUE/JOINT_TRAJECTORY/CARTESIAN_POSE/GRIPPER_BINARY(decoded but never pack-executed → would E-stop mid-run) andCARTESIAN_TWIST/FOOT_PLACEMENT/DEX_HAND_JOINT(no sim controller).def canonical_slots_for_representation(rep: ActionRepresentation, *, dim: int, description: RobotDescription) -> list[ActionSlot] | None(L2408) — ADR-0036. Builds the canonicalActionSlotlayout the skill_runner dispatches a representation-onlyActionContractthrough. Joint representations →None(caller keeps the legacy whole-vectorJOINT_POSITIONpath).DELTA_EE_6D/CARTESIAN_POSE→ one cartesian slotrange=(0,5)addressed at the primary EE (description.end_effectors[0]);DELTA_EE_6D_PLUS_GRIPPERadds aGRIPPER_POSITIONslotrange=(6, dim-1).EndEffectorSpechas no explicit tf-frame field, so the EEnameis used as the slotframe. RaisesROSConfigErrorwhen the representation needs an EE butend_effectorsis empty, or whendimis too small (DELTA_EE_6D/CARTESIAN_POSEneeddim>=6;DELTA_EE_6D_PLUS_GRIPPERneedsdim>=7).
python/core/src/openral_core/loaders.py
Strict YAML loaders for the three scene tiers (ADR-0041).
def load_scene_strict(path: str, expected: type[DeployScene | SimScene | BenchmarkScene]) -> DeployScene | SimScene | BenchmarkScene(L36) — Loadpathas exactlyexpected; reject other tiers withROSConfigErrorcarrying a redirect message that names the right CLI command.mypy --strictoverloads narrow the return to the requested concrete type. Centralises the rejection logic used by every scene-driven CLI loader (openral deploy sim→DeployScene,openral sim run→SimScene,openral benchmark scene→BenchmarkScene) so a YAML one tier too rich is not silently widened (e.g. a BenchmarkScene YAML passed toopenral sim runwould otherwise dropn_episodes/metadataon the floor). RaisesFileNotFoundErrorfor a missing path andROSConfigErrorfor a non-mapping YAML root, an extra-key mismatch, or a tier mismatch.def load_benchmark_suite(path: str) -> list[BenchmarkScene](L148) — ADR-0042. Load a barelist[BenchmarkScene]frombenchmarks/<id>.yaml. The suite id is the filename stem; the YAML root MUST be a list. Pre-ADR-0042{id, tasks, metadata}dict shape is rejected with an explicit ADR-0042 redirect message naming the migration. Per-scene Pydantic validation runs here; suite-level invariants (uniformity, uniqueness, non-empty) are NOT enforced — callraise_on_invalid_suiteseparately so tests can construct invalid in-memory suites without touching disk. RaisesFileNotFoundErrorfor missing paths andROSConfigErroron every shape / validation failure (never a bareValidationError).def raise_on_invalid_suite(scenes: list[BenchmarkScene], *, suite_id: str) -> None(L223) — ADR-0042. Free-function replacement for the deletedBenchmarkSpec.model_post_init. Enforces the five suite invariants: non-empty list, everyscenes[i].robot_idnon-None, everytask.idunique within the suite, everyscenes[i].robot_id/n_episodes/seed/metadatabyte-identical across the list. Per-scenetask.success_keyandtask.max_stepsMAY differ (ManiSkill3 mixed-budget suite).suite_idis embedded in every error message so failures point back at the rightbenchmarks/<id>.yaml. First violation wins — no batched reporting. RaisesROSConfigErroron any invariant violation.
python/core/src/openral_core/assets.py
The single resolver for robot description assets — URDF / MJCF / SRDF (ADR-0058).
class AssetRefError(ValueError)(L40) — A description-asset reference is malformed or cannot be resolved.def resolve_asset(ref: str, kind: AssetKind, *, manifest_dir: Path | None = None) -> Path | None(L44) — Resolve one assetrefto a concrete file path for the requestedkind(urdf/mjcf/srdf). One grammar replacingresolve_urdf_path,resolve_mjcf_uri, plain-path SRDF, andurdf_lowering._load_urdf_model. Schemes:rd:<module>(upstreamrobot_descriptions, downloads on first use; xacro-only URDF →AssetRefErrordirecting toopenral robot vendor-urdf),file:<relpath>(manifest dir then repo root),gym_aloha:<scene>/openarm:<variant>/menagerie:<model>(sim-only MJCF loaders, lazy-imported; menagerie not yet wired),ros2://robot_description(URDF-only dynamic marker → returnsNone). RaisesAssetRefErrorfor every other unresolvable/malformed ref.
python/core/src/openral_core/exceptions.py
openral exception hierarchy — use these, do not invent new base classes.
class ROSError(Exception)— Base class for all OpenRAL errors. (L43)class ROSConfigError(ROSError)— Bad manifest, missing weights, invalid YAML/URDF. (L50)class ROSCapabilityMismatch(ROSError)— Skill requires a capability the robot lacks. (L54)class ROSRuntimeError(ROSError)— General runtime failure. (L61)class ROSInferenceTimeout(ROSRuntimeError)— VLA inference exceeded latency budget. (L65)class ROSQuantizationError(ROSRuntimeError)— Quantization failed. (L69)class ROSGPUMemoryError(ROSRuntimeError)— Out of GPU memory. (L73)class ROSSafetyViolation(ROSError)— Safety constraint violated. Never silently caught. (L80)class ROSWorkspaceViolation(ROSSafetyViolation)— Action outside allowed workspace. (L88)class ROSForceLimitExceeded(ROSSafetyViolation)— Contact force exceeds limit. (L92)class ROSCollisionImminent(ROSSafetyViolation)— Proposed motion would self-collide or strike a world obstacle. (ADR-0030, L95)class ROSEStopRequested(ROSSafetyViolation)— Emergency stop requested. (L107)class ROSPerceptionStale(ROSError)— Sensor reading exceeds staleness deadline. (L114)class ROSObjectNotInMemory(ROSPerceptionStale)— A scene-graph query (RecallObjectQuery/ResolvePlaceQuery) matched no node or only stale nodes; caller degrades to "unknown" (may trigger active search), never fabricates a pose. (ADR-0038)class ROSPlanningError(ROSError)— Reasoner failed to produce valid plan. (L131)class ROSReasonerInvalidPlan(ROSPlanningError)— LLM returned invalid plan. (L135)class ROSBTValidationError(ROSPlanningError)— BehaviorTree XML failed BT.CPP v4 validation. (L139)class ROSFleetError(ROSError)— Fleet-level / dispatch error. (L146)class ROSDispatchUnavailable(ROSFleetError)— No dispatcher available. (L150)class ROSRskillGoalSatisfied(ROSError)— Typed control-flow completion signal raised byROSActionRskill._step_implonce a wrapped-ROS rSkill (kind: ros_action / ros_service) has emitted its last waypoint (trajectory mode) or finished awaiting the wrapped action's result (result-only mode). Caught only at therskill_runner_nodeexecute-callback boundary; the runner closes the goal withsuccess=True. NOT an error — inheritsROSErroronly to stay inside the OpenRAL exception surface. (L161)class ROSDeadlineMissed(ROSFleetError)— Cloud RTT exceeded skill deadline. (L154)