Layer 4 — rSkill (S1)
Part of the OpenRAL public-symbol inventory. Hand-curated;
(LNN)markers are refreshed bytools/refresh_methods_linenos.py.
python/rskill/src/openral_rskill/base.py
rSkillBase — abstract base class with lifecycle state machine.
class rSkillBase(abc.ABC)— Abstract base class for all OpenRAL skills (rSkill is the official package-format name, CLAUDE.md §6.4). (L72)__init__(name, *, version='0.1.0', role='s1', embodiment_tags=None, latency_budget_ms=None)— Init only; does not configure or load weights. (L102)info -> RSkillInfo[@property] (L126)name -> str[@property] (L134)state -> RSkillState[@property] (L139)configure() -> None—unconfigured → inactive. (L146)activate() -> None—inactive → active. (L171)deactivate() -> None—active → inactive. (L193)shutdown() -> None— Any state →finalized. (L213)step(world_state) -> Action— One inference step (hot path). (L237)on_load_weights() -> None— Hook: load weights. (L283)on_unload_weights() -> None— Hook: release weights, called byshutdown()(VRAM eviction). (L290)on_quantize() -> None— Hook: apply quantization. (L300)on_warmup() -> None— Hook: dummy forward pass, called byactivate()before_activate_impl. Default is a no-op. Implemented on the deploy path by_PolicyAdapterSkill.on_warmup(packages/openral_rskill_ros/openral_rskill_ros/rskill_runner_node.py), which delegates to_vla_core.warm_up_lerobot_policyand swallows+logs any failure. (L307)_configure_impl/_activate_impl/_deactivate_impl/_shutdown_impl/_step_impl()[@abstractmethod] (L317)- private:
_transition,_update,_require_transition,_enter_error
python/rskill/src/openral_rskill/runtime.py
Runtime Protocol and NullRuntime — inference backend contract.
class Runtime(Protocol)— Structural protocol for skill inference backends. (L24)is_loaded -> bool[@property] /device -> str[@property]load(path) -> None(L49)infer(inputs) -> dict[str, Any](L61)quantize(config: QuantizationConfig) -> None(L76)warmup(inputs) -> None(L88)unload() -> None(L96)class NullRuntime— No-op backend for testing. (L101) — same surface asRuntime.
python/rskill/src/openral_rskill/runtime_pytorch.py
class PyTorchRuntime—torch-backedRuntime. (L41)__init__(device='cpu'),is_loaded,device,load(path)(unpickles a full module — gated behindOPENRAL_ALLOW_UNSAFE_PICKLE, C2),load_safetensors(path, *, model, strict=True)(safe: loads astate_dictinto a caller-supplied module, no code execution — preferred for new skills),infer(inputs),quantize(config)(dynamic INT8 on Linear),warmup(inputs),unload()(frees CUDA cache).
python/rskill/src/openral_rskill/runtime_onnx.py
class ONNXRuntime—onnxruntime-backedRuntime. (L52)- same surface as
Runtime.quantize(config)always raises — ONNX quantization is pre-applied.
python/rskill/src/openral_rskill/backend_registry.py
Extraction seam: entry-point-based runtime-backend + policy-attach-hook registry.
resolve_runtime_backend(kind: str) -> type[Runtime]— built-in dict (pytorch→PyTorchRuntime,onnx→ONNXRuntime,null→NullRuntime) first, else looked up via theopenral.runtime_backendsentry-point group (e.g.openral-pro-trtregisteringtensorrt). Miss →ROSConfigErrornamingopenral-pro-trt.maybe_attach_pro_hooks(policy_name: str, skill, **kwargs) -> bool— generic policy-attach-hook lookup via theopenral.policy_attach_hooksentry-point group (name =policy_name, e.g."smolvla"/"act"). No hook installed → debug log +False(not a silent skip, CLAUDE.md §1.4); hook found → invoked ashook(skill, **kwargs),True/info-log iff it reports attaching. Replaces the old hardcodedtry: from openral_rskill.smolvla_trt import .../act_trtcall sites insmolvla.py/openral_sim.policies.act.
Moved to OpenRAL Pro:
runtime_tensorrt.py(TensorRTRuntime),smolvla_export.py,smolvla_trt.py, andact_trt.pynow live in the privateopenral-pro-trtpackage asopenral_pro_trt.*, plugging in via theopenral.runtime_backends/openral.policy_attach_hooksentry-point groups above.
python/rskill/src/openral_rskill/engine_cache.py
Filesystem-based per-host engine cache for compiled skill runtimes.
class EngineCache— Filesystem-backed cache for compiled skill engine files. (L30)__init__(cache_dir=DEFAULT_CACHE_DIR)(L49)cache_key(rskill_id, backend, config: QuantizationConfig) -> str— Stable key for skill+runtime+quant. (L56)get(key) -> Path | None— Cached engine path orNone. (L96)put(key, engine_path) -> Path— Copy into cache. (L114)invalidate(key) -> None— No-op on miss. (L133)clear() -> None— Remove all engine files. (L143)size_bytes -> int[@property] (L151)entry_count -> int[@property] (L163)- private:
_key_path
python/rskill/src/openral_rskill/quantization.py
auto_select_quant(device_info: DeviceInfo) -> QuantizationConfig— Heuristic to pick dtype/backend. (L79)
python/rskill/src/openral_rskill/loader.py
rSkill loader — HF Hub download, manifest validation, license guard, local registry.
class InstalledRSkillEntry(BaseModel)— One row in the local registry. (L97) fields:repo_id, version, revision, local_dir, manifest_path, license, role, embodiment_tags, installed_atclass rSkill— Packaged, signed, capability-tagged robot skill. (L141)__init__(manifest, local_dir)(L165)from_pretrained(cls, repo_id, *, revision=None, cache_dir=None, force_download=False, commercial_use=True, registry_path=None) -> rSkill[@classmethod] — Download from HF Hub, validate, register. (L178)from_yaml(cls, path, *, local_dir=None) -> rSkill[@classmethod] — Load locally without network. (L296)list_installed(registry_path=None) -> list[InstalledRSkillEntry][@staticmethod] (L331)uninstall(repo_id, registry_path=None) -> bool[@staticmethod] — Remove from registry only. (L362)check_embodiment_tags(manifest, robot_capabilities) -> None[@staticmethod] — Verify embodiment tag intersection (raises on disjoint sets). Exempt for perception kinds (detector/vlm,_EMBODIMENT_AGNOSTIC_KINDS): they are camera-in → detections/text-out with no action contract, so they match any robot regardless of tags. (L392)check_capability_flags(manifest, robot_capabilities) -> None[@staticmethod] — Verify everymanifest.capabilities_requiredflag againstRobotCapabilities. (L420)check_runtime(manifest, robot_capabilities) -> None[@staticmethod] — Verifymanifest.runtime∈gpu_supported_runtimes; skipped when the legacy capability field is missing or empty (the GPU support fields moved toComputeSpec, so missing means "unknown" for now). (L452)check_quantization_dtype(manifest, robot_capabilities) -> None[@staticmethod] — Verifymanifest.quantization.dtype∈gpu_supported_dtypes; skipped when the legacy capability field is missing or empty. (L481)check_capabilities(manifest, robot_capabilities) -> None[@staticmethod] — Composition of the four narrower checks; raises on first failure. (L509)_check_license(manifest, *, commercial_use) -> None[@staticmethod] — Enforce license guards (CLAUDE §7.4, §12). (L707)_validate_eval_jsons(skill_dir) -> None[@staticmethod] — Validate every<skill_dir>/eval/*.jsonagainstRSkillEvalResult(CLAUDE §6.4). (L808)_register(entry, registry_path) -> None[@staticmethod] (L834)__repr__() -> str(L858)resolve_rskill_local_dir(uri) -> Path | None— Return the absolute on-disk directory of an in-tree rSkill referenced by a bare skill ref (bare name,rskills/<name>, or Hub repo id), orNonefor Hub-only refs with no in-tree shim. Used byopenral benchmark runto write<skill_dir>/eval/<id>.jsonand update<skill_dir>/rskill.yamlregardless of cwd or which ref form the user typed. (L870)_candidate_local_paths(uri) -> list[Path]— Enumerate on-disk candidates (cwd-relative + repo-root anchored) for a skill reference. Also unwraps HF Hub form<org>/rskill-<name>to in-treerskills/<name>. (L891)discover_intree_rskills() -> list[tuple[str, RSkillManifest]]— Walk<repo>/rskills/*/rskill.yamland return(name, manifest)pairs. Malformed entries are skipped with a stderr warning. (L926)_find_repo_root_from(start) -> Path | None— Walk up fromstartfor the first ancestor containing bothpyproject.tomlandrskills/. (L957)_validate_skill_ref(raw) -> str— Validate and return a bare rSkill reference unchanged. Accepts bare names,rskills/<name>paths, or HF repo ids; rejects inputs carrying a known URI scheme (hf://,local://,file://,http(s)://). Private — used internally by the CLI and loader. (L970)load_rskill_manifest(uri) -> RSkillManifest— Resolve a bare skill reference to a parsed manifest. Tries local path → in-tree mapping → HF Hub download. In-process memoised. (L1010)resolve_rskill_to_hf(uri) -> str— Resolve a skill reference to either the underlying HF Hub repo id (hf://...) or an absolute local path (local://...); both forms are accepted byfrom_pretrainedhelpers. (L1082)resolve_rskill_to_hf_with_revision(uri) -> tuple[str, str | None]— Likeresolve_rskill_to_hfbut splits the optional@<branch-or-sha>pin off anhf://weights_uriinto a separaterevisionso loaders can pass it tofrom_pretrained/snapshot_downloadinstead of gluing it onto the repo id where HF drops it (security audit 2026-06, H4). (L1116)
python/rskill/src/openral_rskill/gpu_passthrough.py
GpuPassthroughSkill — minimal rSkill whose per-step image processing provably runs on GPU (M8 PR I/10).
_REDUCTION_SIZE: int = 64— module constant; reduction-target size used to bound GPU latency. (L48)_RGB_CHANNELS: int = 3— module constant; channel count for the GPU mean-reduction read-back. (L52)class GpuPassthroughSkill(rSkillBase)— Uploads eachSensorFrameto torch.cuda, runs per-channel mean reduction (with explicittorch.cuda.synchronize), emits result asAction.confidence. Refuses silent CPU fallback. (L55)__init__(sensor_id='wrist_rgb', n_joints=6, horizon=1, device='cuda', latency_budget_ms=None)(L76)step_count -> int[@property] (L104)on_load_weights/on_quantize() -> None— no-ops (skill is weight-less). (L110)on_warmup() -> None— Allocate the GPU input buffer + launch a kernel so the first step doesn't pay cudaMalloc latency. (L118)_configure_impl()— Lazy-import torch, resolve device, raise ifcudarequested andtorch.cuda.is_available()is False. (L144)_activate_impl/_deactivate_impl/_shutdown_impl(L169)_step_impl(world_state) -> Action— Pull frame → CPU→GPU upload → GPU reduction → action with confidence. (L185)- private:
_extract_latest_image(world_state) -> NDArray[np.uint8],_gpu_reduce(frame, *, torch) -> (float, float, float). (L227 / L260) _channels(encoding: FrameEncoding) -> int— Per-pixel channel count for aFrameEncoding; MONO8 → 1, BGR8/RGB8 → 3, everything else falls through to a defensive BGR default of 3. (L297)_zero_frame() -> NDArray[np.uint8]— Resilient placeholder when no sensor frame is available yet. (L310)
python/rskill/src/openral_rskill/_diagnostics.py
Shared load-phase instrumentation seam — generalises the inline _heartbeat originally inside openral_sim.policies.pi05 so every VLA adapter's _build_* factory uses the same <prefix>_<name>_{start,heartbeat,done} event shape (CLAUDE.md §1.13 — single seam, no duplicates).
phase_timer(name, *, prefix="phase", interval_s=15.0, log=None, gpu_mb=False, **fields) -> Iterator[None][@contextmanager] — Emits<prefix>_<name>_start/..._heartbeateveryinterval_s/..._donewithelapsed_s. Heartbeat and done also carryrss_mb+major_faults(Linux, delta from phase entry) so a load that is slow while burning no CPU is attributable to page reclaim.gpu_mb=Trueattachestorch.cuda.memory_allocated()to the heartbeat for phases that move tensors to/from the GPU. Lazy torch import so CPU-only hosts still work. Consumed by_pi05_phase+_smolvla_phasein the sim adapters and bytools/profile_policy_load.py. (L149)_gpu_mb() -> float | None— Cheap helper. (L55)_rss_majflt() -> tuple[float, int] | None— Process RSS (MB) + lifetime major-fault count from/proc/self/{statm,stat};Noneoff Linux. (L91)
python/rskill/src/openral_rskill/executor.py
Action-chunk executor — promoted from smolvla so every chunked VLA family reuses one implementation. Also the home of Real-Time Chunking (RTC): with an enabled lerobot RTCConfig the buffer becomes an ActionQueue whose tail a landing prefetch replaces.
class ChunkedExecutor— Owns the per-step action buffer for every chunked VLA family and optionally overlaps chunk N+1 inference with execution via a background daemon thread. The executor owns its buffer and callspredict_action_chunkdirectly; it never resets or consumes lerobot's mutableselect_actionqueue from two threads. The former shared-queue design reset the live queue during prefetch, reordered commands, and blocked 0.42-0.77 s at every 50-step boundary. Default producer ispolicy.predict_action_chunk; a customchunk_fn(payload) -> chunksupports adapters with autocast, decode, or non-lerobot APIs. Tensor chunks consume the configured prefix; sequence producers must return exactlychunk_size, keeping scheduling and telemetry aligned.select_action(batch_or_fn)materialises lazy payloads only when an inference launches.prefetch_at=0is synchronous;stop()waits for a running inference before teardown. RTC mode (an enabled lerobotRTCConfigviartc_config=) swaps the deque for lerobot'sActionQueueand changes the merge rule from append behind to replace the tail: a prefetched chunk takes over the moment it lands, dropping the actions consumed during inference, and the producer is called withinference_delay=/prev_chunk_left_over=so the flow-matching guidance can blend the two chunks. RTC has no synchronous form — it needs a real overlap — so an effectiveprefetch_at >= 1is required. (L71)__init__(policy=None, *, chunk_fn=None, chunk_size=None, prefetch_at=20, rtc_config=None)— policy OR chunk_fn+chunk_size; ValueError otherwise. Negativeprefetch_atraisesROSConfigError; the value is clamped tochunk_size - 1at construction (logged aschunked_executor.prefetch_at_clamped). Twenty remaining 30 Hz steps provide ~667 ms for the measured 313-600 ms chunk inference.rtc_configis a lerobotRTCConfig; when enabled it requires a clampedprefetch_at >= 1(ROSConfigErrorotherwise) and warnschunked_executor.rtc_prefetch_below_horizonwhen the lead is shorter thanexecution_horizon— a degradation (the blend runs overprefetch_atsteps instead), not an error. (L74)start() -> None— Mark as running (call after policy is on-device). (L193)stop() -> None— Signal background thread, join. (L197)reset() -> None— Clear buffer/bg state and the RTC queue + last delay;policy.reset()when a policy was given. (L204)select_action(batch_or_fn) -> Any— Next action; cold-start foreground inference / buffer pop / wait-on-prefetch. Delegates to_select_action_rtcin RTC mode. (L221)- private:
_pop_and_maybe_prefetch(batch)(every pop routes through it so the trigger is branch-independent),_produce(payload, chunk_index, kind, rtc_kwargs=None)(passessynchronize=Trueon the prefetch path only),_materialize,_extend_buffer,_launch_prefetch(batch) - private (RTC):
_select_action_rtc(batch)— serve from theActionQueue; re-checks after the pre-fetch wait so a chunk that landed in between is not discarded by the cold-start path._rtc_merge(chunk, *, idx_before)— replace the tail;real_delayis the index delta the queue advanced during inference (valid in wall-clock deploy and fast-forward sim, unlike a latency estimate), and the producer's batch dim must be 1._raise_bg_error_if_any()— re-raise a latched background error on the foreground thread. The prefetch path truncates the leftover tail toexecution_horizonrows (weights are zero past it) so the tail length does not depend on how earlyprefetch_atfires.
python/rskill/src/openral_rskill/ros_action_rskill.py
ROS-wrapping rSkill adapter — bridges arbitrary ROS 2 action / service servers (MoveIt, Nav2, …) into the rSkillBase lifecycle. Selected by make_default_skill_resolver when manifest.kind in {"ros_action", "ros_service"}.
build_joint_permutation_from_names(*, source_names, target_names) -> list[int]— Build the permutation that reorders a wrapped server'sJointTrajectory.positionsinto the hostRobotDescription.jointsorder. RaisesROSConfigErroron set-inequality so a joint mismatch surfaces loudly instead of silently swapping bytes. (L172)CUMOTION_PIPELINE_ID = "isaac_ros_cumotion"— the cuMotion MoveIt planning-pipeline id.maybe_inject_cumotion_pipeline(goal_dict, *, interface_type, capabilities) -> dict— On a host that clears the cuMotion GPU floor (RobotCapabilities.supports_cumotion()), setrequest.pipeline_id = CUMOTION_PIPELINE_IDon aMoveGroupgoal so MoveIt plans with cuMotion; no-op for non-MoveGroup actions, CPU/low-VRAM hosts (→ OMPL default), an already-setpipeline_id, or a goal with norequestblock. Pure; never mutates the input. Called by_configure_implafter the goal-merge.class ROSActionRskill(rSkillBase)—rSkillBaseshim wrapping a ROS 2 ActionClient (or service client). Two modes selected bymanifest.ros_integration.result_trajectory_field: trajectory mode replays one waypoint perstep()and raisesROSRskillGoalSatisfiedafter the last; result-only mode awaits the wrapped result and raisesROSRskillGoalSatisfiedon success without emitting anyAction. ROS imports are deferred to_configure_implso the module imports cleanly without ROS sourced. (L301)__init__(*, manifest, ros_node, robot_description, prompt, prompt_metadata_json)(L334)_configure_impl()— Lazy-import IDL, build ActionClient/service client, parsedefault_goal_json. (L405)_activate_impl()— no-op; the wrapped action dispatches on firststep(). (L495)_deactivate_impl()/_shutdown_impl()— Release the wrapped client. (L498)_step_impl(world_state) -> Action— First call sends goal and caches result; subsequent calls dequeue waypoints. (L515)
python/rskill/src/openral_rskill/look_at_rskill.py
Camera-aiming MoveGroup skill. Selected by make_default_skill_resolver when manifest.ros_integration.goal_builder == "look_at" (new RosIntegration.goal_builder field; RSkillAction gains LOOK = "look").
resolve_camera_sensor(description, camera) -> SensorSpec— Find the named camera inRobotDescription.sensors;ROSConfigErrorlisting the available sensor names on a miss (explicit beats implicit — default camera is"wrist").build_look_at_constraints(*, camera_goal: Pose6D, link_name, link_t_cam=None, position_tolerance_m=0.02, orientation_tolerance_rad=0.15) -> dict— Lower a camera gaze pose into one MoveGroupgoal_constraintsentry — delegates topose_goal_rskill.build_pose_constraintswith the optical (z) axis tolerance set to π (roll free); the position/offset math lives there now. Withlink_t_camthe goal is re-expressed for the mount link; without it the camera frame is the constrained link.class LookAtRskill(ROSActionRskill)— Consumes the merged goal'slook_atblock (target_xyzrequired;frame_id,camera,standoff_m, tolerances) instead of raw constraints._configure_implpops/validates the block, resolves the camera, builds a TF2 listener; the lowering runs lazily on the firststep()(needs the camera's current TF pose): re-aim in place, or place the camera atstandoff_mfrom the target along its current line of approach, thencompute_gaze_pose(+z optical) →build_pose_constraints→ constraints injected intorequest.goal_constraintsbefore the parent dispatches. Trajectory replays waypoint-per-chunk through the safety supervisor; the manifest shipsplan_only: trueso MoveIt-side execution never bypasses the kernel.
python/rskill/src/openral_rskill/pose_goal_rskill.py
Generic Cartesian end-effector pose MoveGroup skill. Selected by make_default_skill_resolver when ros_integration.goal_builder == "pose". Home of the shared pose→constraints lowering LookAtRskill reuses.
build_pose_constraints(*, pose: Pose6D, link_name, link_t_target=None, position_tolerance_m=0.01, orientation_axis_tolerances_rad=(0.05, 0.05, 0.05)) -> dict— Lower a target pose into one MoveGroupgoal_constraintsentry (sphere position region + per-axis orientation constraint).link_t_targetre-expresses the goal for the constrained link (goal_link = goal_target @ inv(link_t_target)); the per-axis tolerance tuple lets a generic pose constrain all three axes while look-at frees the optical (z) axis at π. Reuse watch: the one place pose→MoveGroup-constraint math lives — do not re-implement.pose_from_block(block) -> tuple[Pose6D, str, float, float]— Parse aposegoal block →(pose, link_name, pos_tol, orient_tol). Orientation is a 4-float quaternion array; component order fromblock["quaternion_order"]("xyzw"default /"wxyz").ROSConfigErroron missing/ill-typed fields or an unknown order.class PoseGoalRskill(ROSActionRskill)— Consumes the merged goal'sposeblock; lowers it viabuild_pose_constraints(full orientation) on the firststep(), then dispatches/replays like the parent.link_t_targetis identity in v1 (the RobotDescription tool-frame offset is a later phase).
python/rskill/src/openral_rskill/joint_goal_rskill.py
Joint-space MoveGroup skill. Selected when ros_integration.goal_builder == "joint". The LLM-facing replacement for hand-written joint_constraints JSON.
joint_constraints_from_block(block) -> dict— Lower ajointblock (joint_names,positions, optionalposition_tolerance_rad) into onegoal_constraintsentry ({"joint_constraints": [{joint_name, position, tolerance_above, tolerance_below, weight}, …]}).ROSConfigErroron missing/ill-typed fields or a name/position length mismatch.class JointGoalRskill(ROSActionRskill)— Consumes the merged goal'sjointblock; lowers it into ajoint_constraintsgoal at_configure_impl, then dispatches/replays like the parent.
python/rskill/src/openral_rskill/smolvla.py
SmolVLA adapter — rSkillBase implementation for the SmolVLA family of VLAs.
from openral_rskill.executor import ChunkedExecutor— re-exported via__all__for back-compat (from openral_rskill.smolvla import ChunkedExecutorstill works after the move). (L91)class SmolVLAAdapter(rSkillBase)— Drives any SmolVLA-family policy. (L114)__init__(repo_id, obs_fn, prompt, *, device='cuda:0', n_dof=6, n_cameras=None, prefetch_at=20, name='smolvla', version='0.1.0', embodiment_tags=None, latency_budget_ms=None)—n_cameras(defaultlen(config.image_features)) truncates warmup to the cameras the deploy feeds and threads to the TRT export (phantom-camera fix). (L159)on_load_weights() -> None— Fetch checkpoint from HF Hub. (L197)on_warmup() -> None— Dummy inference. (L256)_configure_impl()— Validate IO shapes matchn_dof. (L289)_activate_impl()— Reset policy, startChunkedExecutor. (L305)_deactivate_impl()— Stop pre-fetch, keep weights. (L313)_shutdown_impl()— Stop threads, free GPU memory. (L319)_step_impl(world_state) -> Action— One S1 step. (L336)_preprocess(raw) -> dict[str, Any]— Lerobot preprocessor + tensor → device. (L372)class SO100SmolVLASkill(SmolVLAAdapter)— Pre-configured for the SO-100 6-DoF arm. (L428)__init__(prompt, *, repo_id='lerobot/smolvla_base', device='cuda:0', extra_images=None, **kwargs)(L450)_so100_obs_fn(world_state, *, device, extra_images=None, prompt) -> dict[str, Any]— SO-100 WorldState → SmolVLA raw input. (L386)
python/rskill/src/openral_rskill/_vla_core.py
Shared helpers for VLA adapters (Layer 3); internal — no public re-export.
InferenceKind— re-export ofopenral_observability.InferenceKind(Literal["foreground", "prefetch", "single"]), the closed value set for theinference.kindlabel; the Literal lives with the span helper that owns the label.kindis a TIMING axis (critical-path / background-prefetch / per-step-eval) — there is deliberately no"chunk": chunk shape ridesinference.chunk_size/chunk_index, and four adapters that used to passkind="chunk"through the then-untyped parameter now recordforeground. (L48)resolve_device(spec: VLASpec) -> str—"auto"→"cuda:0"/"mps"/"cpu"against real torch. (L51)resolve_rskill_repo_id(weights_uri: str, *, adapter_name: str) -> str— Validate skill reference and resolve to bare HF repo id;adapter_nameis used in theROSConfigErrormessage. (L76)resolve_rskill_repo_revision(weights_uri: str, *, adapter_name: str) -> tuple[str, str | None]— Likeresolve_rskill_repo_idbut also returns the optional@<sha>revision pin (threaded intofrom_pretrained/snapshot_downloadby the sim adapters) and warnsrskill.unpinned_weightswhen anhf://skill is unpinned (security audit 2026-06, H4). (L107)apply_chunk_replay(policy, spec_extra) -> int— Overridepolicy.config.n_action_stepsfromvla.extra(defaultchunk_size // 2); used by all lerobot-style adapters (smolvla,act,pi05) to amortise the heavy chunk forward over multiple env steps. (L294)_CUDAGRAPH_COMPILE_MODES—frozenset({"reduce-overhead", "max-autotune"}); thetorch.compilemodes that may capture CUDA graphs and therefore require output cloning (static replay buffers would otherwise be overwritten under lerobot's queued action views /ChunkedExecutorpre-fetch). (L353)_has_bnb_quantized_modules(policy) -> bool— True when any submodule's class comes frombitsandbytes(Linear4bit/Linear8bitLtrewrites fromopenral_sim._quantization). Class-module-path check; never imports bnb. (L365)_clone_chunk_output(out, torch) -> Any— Recursively.clone()every tensor in a chunk forward's output (tensor / tuple / list / dict; non-tensor leaves pass through) so downstream holders own their storage, detached from CUDA-graph static buffers. (L379)maybe_compile_chunk_forward(policy, spec_extra, device, torch, *, method_name="_get_action_chunk") -> bool— Best-efforttorch.compileof the chunk forward with a runtime fallback wrapper (latches into eager mode on backend errors). Skipped on CPU and whenvla.extra.compileis falsy. Two safety gates: bitsandbytes-quantized policies are never compiled (mixed nf4/bf16 graphs trip dtype-mismatch errors — the same reason the pi05 adapter forcescompile_model = False; logsvla_compile_skipped_bnb_quantized), and under cudagraph modes (_CUDAGRAPH_COMPILE_MODES) every output is routed through_clone_chunk_outputon both the compiled and eager-fallback branches. Logsvla_compile_setup_failed/vla_compile_runtime_fallbackon failure. (L397)run_inference(policy, batch, *, chunk_index=None, kind="single", chunk_size=None, engine=None, call=None, call_kwargs=None, synchronize=False) -> Tensor— Single seam wrapping a policy inference call ininference_span+torch.no_grad(); the only placeinference.kind/chunk_index/chunk_size/inference.engine/inference.deviceattributes are emitted across both eval and skill paths.callreplaces the defaultpolicy.select_action(batch)for custom chunk producers.call_kwargsis splatted intocall— the RTC executor threadsinference_delay/prev_chunk_left_overthrough it;None(the default) callscall(batch)exactly as before, so non-RTC producers keep their 1-arg signature. Aninference_delayentry is recorded on the span asinference.rtc_delay.ChunkedExecutorpassessynchronize=Trueon its prefetch: CUDA launches are asynchronous, so without it the background thread signalled ready before kernels completed and the first foreground action still paid the full 0.42-0.82 s boundary stall (it also stops the span's timer at kernel-launch rather than at compute).enginedefaults to"torch";deviceis auto-lifted frompolicy.devicewhen present.torch.no_grad()here must not becometorch.inference_mode()— lerobot's RTC guidance callsautograd.grad, which raises under inference mode (pinned bytests/sim/test_smolvla_rtc.py::test_inference_mode_would_break_the_guidance). (L500)resolve_inference_engine(owner, declared=None) -> str— Resolve the backend actually executing after optional runtime attachment. Explicit plugin marker_openral_inference_enginewins; the releasedopenral-pro-trtcallable module is recognized for backward compatibility; manifest names normalizepytorch→torch/tensorrt→trt. Used by bothrun_inferenceprefetch spans and the ROS runner's per-tick spans so the dashboard cannot keep reporting the pre-attachment manifest runtime. (L589)_RTC_ADAPTERS—frozenset({"smolvla", "pi05"}); the flow-matching adapters whose lerobot policies carry anrtc_config. molmoact2 / pi0_fast support RTC upstream but are out of scope — extend this set and the adapter's chunk_fn kwargs pass-through together. (L629)_parse_rtc_config(spec_extra, *, adapter_name) -> RTCConfig | None— Parse the manifest'spolicy_extras.rtcblock into a lerobotRTCConfig;Nonewhen there is no block. Keys are the closed setenabled/execution_horizon/max_guidance_weight/prefix_attention_schedule/debug(defaultstrue/10/10.0/exp/false); the schedule is one ofzeros/ones/linear/exp(lerobot'sRTCAttentionSchedule).ROSConfigErroron a non-mapping block, an unknown key or schedule, a non-positive horizon,RTCConfigpost-init rejection, or an adapter outside_RTC_ADAPTERS. lerobot imports are deferred (heavy optional dep). (L641)rtc_enabled_in_extra(spec_extra, *, adapter_name) -> bool— True only for a present, well-formed, enabledrtcblock. For factories that must decide before the executor exists: smolvla skipsmaybe_compile_chunk_forwardon it, since RTC andtorch.compilerewrite the same flow-matching forward. Keyed on the parsedenabledflag, not the block's presence, sortc: {enabled: false}still gets compiled. Re-raises the sameROSConfigErrora malformed block would raise later inbuild_chunk_executor. (L706)build_chunk_executor(spec_extra, *, policy=None, chunk_fn=None, chunk_size=None, adapter_name="policy") -> ChunkedExecutor | None— Shared executor construction.chunk_prefetchenables overlap;chunk_prefetch_atcalibrates the lead in actions (default 20, clamped to the chunk). Single-step custom producers retain a synchronous buffer so their output contract is validated; single-step lerobot policies use their normal path. Diffusion Policy remains excluded because it consumes observation history every tick. An enabledpolicy_extras.rtcblock additionally setspolicy.config.rtc_configand callsinit_rtc_processor()before the executor is built, then hands the sameRTCConfigto it. RTC is refused —ROSConfigError, never a silent downgrade — on chunk size 1 (no previous tail exists),chunk_prefetch: false(no overlap to blend across), a policy withoutinit_rtc_processor, or bitsandbytes-quantized weights (the guidance backpropagates through the denoiser each step). With nortcblock the construction, and the served actions, are byte-identical to before. Logsvla.chunk_executor_enabledwith anrtcfield. (L731)to_numpy_action(action_tensor) -> NDArray[np.float32]—(1, A)torch tensor → 1-D float32 NumPy. (L851)release_torch_modules(owner, *attrs, device="") -> None— Drop an adapter's references to its loaded torch modules, thengc.collect()and (on CUDA)torch.cuda.empty_cache(). The order is the whole point.empty_cache()returns only already-free cached blocks to the driver — it cannot free memory the allocator still considers live — so flushing while the adapter still holds the policy frees nothing. Measured on an RTX 4070 with a 768 MiB module resident:empty_cache()alone left it at 768.2 MiB; dropping the reference first returned it to 0.0 MiB. Every VLA adapter'sclose()did the former, which is why an rSkill swap never actually gave the card back and a second skill OOM'd on an 8 GB machine even though each fits alone.gc.collect()is not optional: a policy is typically part of a reference cycle (module ↔ parameters ↔ hooks), so dropping the last named reference does not necessarily run its finaliser on the spot. Best-effort by contract (teardown must always reach the code behind it), so a missing attribute or an unimportable torch is swallowed. Call sites:close()in all eight sim adapters —smolvla(after its NVMM encoder teardown),pi05,act,xvla,diffusion,gr00t,molmoact2,openvla.warm_up_lerobot_policy(adapter, *, prompt="", torch=None) -> bool— Run one dummy forward so the first real control tick does not blow its deadline. The first CUDA inference pays cuDNN autotune, kernel JIT and lazy-module materialisation: measured on an RTX 4070 with the ACT so101-pen checkpoint (resnet18 + transformer, two 480x640 cameras) call 1 = 330.4 ms vs 14.9 ms steady — 10x the 33.3 ms budget at 30 Hz, so tick 1 was a guaranteed deadline miss and underDeadlineOverrunPolicy.DROPthe robot's first commanded action was discarded. With the warm-up wired intoactivate()the same checkpoint's first real tick measured 14.9 ms, inside budget; the 303 ms moved to where the operator is already waiting. Shapes are read from the policy's ownconfig(image_features[k].shape,input_features['observation.state']) so the pass autotunes the exact kernels the real ticks use — a guessed resolution would warm the wrong ones. Honours an adapter's_image_dtype(SmolVLA casts images). ReturnsFalseand does nothing for adapters exposing no introspectable_policy(the HF-basedmolmoact2/openvla). Called from_PolicyAdapterSkill.on_warmup, which swallows and logs any failure — a warm-up is an optimisation and must never be why a skill fails to activate.parse_hf_file_uri(uri: str) -> tuple[str, str | None, str]— Splitshf://owner/repo[@rev]/path/to/file.extinto(repo_id, revision, filename)for per-filehf_hub_downloadcalls. Rejects bare-repo URIs with a typedROSConfigError. (L930)materialize_processor_dir(manifest: RSkillManifest) -> str— Downloads the manifest's per-fileprocessorsartefacts (Gap 1+3 of the rSkill self-containment audit) viahf_hub_downloadcalls and symlinks them under the lerobot-canonical filenames (policy_preprocessor.json/policy_postprocessor.json) in a fresh temp directory. Also walks each downloaded JSON'ssteps[*]and downloads any siblingstate_file(normalizer / unnormalizer.safetensors) into the same staging dir so lerobot'sPolicyProcessorPipeline.from_pretrained(<dir>)resolves every step locally without falling back tohf_hub_download(repo_id=<dir>). Single seam used by the SmolVLA and modern-ACT adapters; raisesROSConfigErrorifmanifest.processors is None. Every download is routed through_hf_download_cached_firstso a cache-hit avoids the per-file HF HEAD validation that otherwise stacks 3–5 seconds onto every load. (L980)_hf_download_cached_first(hf_hub_download, local_not_found_exc, *, repo_id, filename, revision=None, **extra) -> str— Cache-first wrapper aroundhuggingface_hub.hf_hub_download. Trieslocal_files_only=Truefirst; onLocalEntryNotFoundErrorfalls back to the normal call. Eliminates the per-file HEAD validation that turns a "cached" load into 500 ms – 3 s × N files on a cold TLS connection. SetHF_HUB_OFFLINE=1to extend the same skip to the inner lerobot / transformers calls this helper does not wrap.suppress_hf_weight_init() -> Iterator[None]— Context manager that patchestransformers.PreTrainedModel._init_weightsto a no-op for the duration. lerobot builds the SmolVLA backbone by callingSmolVLMForConditionalGeneration(config=...)directly (taken whenever the checkpoint setsload_vlm_weights=False, which every SmolVLA finetune does), so it pays a full random init of 507 M params, truncates half the text layers away, then overwrites the rest from the checkpoint. Measured on the SO-101 eraser-place checkpoint:from_pretrained16.34 s → 7.99 s, weights bit-identical. Only sound when the checkpoint covers every parameter — pair withassert_all_parameters_finite. Process-global while active; the skill runner serialises loads behind its resident-skill lock.assert_all_parameters_finite(policy, *, repo_id) -> None— RaisesROSConfigErrorif any floating-point parameter is NaN/Inf. The guard that makessuppress_hf_weight_initsafe: uninitialised memory read as float is overwhelmingly non-finite, so this catches a checkpoint that failed to cover the graph. ~0.06 s on a 500 M-param policy.call_make_processors_cached_first(make_pre_post_processors, policy_config, *, pretrained_path, **kwargs) -> tuple[Any, Any]— Wraps lerobot'smake_pre_post_processorsso theTokenizerProcessorStep.__post_init__ → AutoTokenizer.from_pretrainedcall skips its 5 HF HEAD /tree/mainrevalidations against the backbone tokenizer (google/paligemma-3b-pt-224for π0.5; SmolVLM for SmolVLA) when that tokenizer is already in the local HF cache. Reads<pretrained_path>/policy_preprocessor.json, probes fortokenizer_config.jsonviahuggingface_hub.try_to_load_from_cache, and flipshuggingface_hub.constants.HF_HUB_OFFLINEtoTruefor the duration of the inner call (transformers.utils.hub.is_offline_modedelegates to the same constant). Passthrough on a cold cache or for adapters whose preprocessor has no tokenizer step (ACT, Diffusion Policy). Call sites:openral_sim.policies.{pi05,smolvla,act,diffusion}._build_*.- private:
_read_tokenizer_repo_from_preprocessor(pretrained_path) -> str | None— Parses<pretrained_path>/policy_preprocessor.jsonfor thetokenizer_processorstep'sconfig.tokenizer_name. ReturnsNoneon missing/malformed JSON or absent step (ACT / Diffusion Policy). Used bycall_make_processors_cached_first. - private:
_hf_tokenizer_is_cached(repo_id) -> bool— Probeshuggingface_hub.try_to_load_from_cache(repo_id, "tokenizer_config.json")and returnsTrueonly when the result is a real cached path (str), notNoneor the_CACHED_NO_EXISTsentinel. ReturnsFalseon any import error so callers fall back to a normal online load.
python/rskill/src/openral_rskill/_lerobot_compat.py
Compatibility shim for lerobot.policies import side-effects.
- private:
_install_stub() -> None(L35)