Import from Hugging Face
Point the checkpoint field at a public model repo, name the runtime, and evaluate — no export step, no container build.
Hugging Face
If your policy already speaks a known runtime, this is the shortest path
onto hardware: Policy.checkpoint(hf=..., runtime=...) names a Hugging
Face model repo and one of the managed runtimes — openpi or lerobot
— and Roborama fetches the checkpoint and serves it GPU-adjacent to the
cell. No export, no Dockerfile, no server of yours in the loop.
Prerequisites
A model repository, not a dataset repository. The Hub hosts both
kinds under the same naming scheme: a model repo holds weights and
config, a dataset repo holds training episodes. The hf: field must
point at the model kind.
Readable without authentication. The hf: field carries a repo id
and nothing else — there is no token parameter anywhere in the API. On
the Hub side, private repos and gated models are real mechanisms
(per-user access approval, fine-grained read tokens scoped to a repo),
but Roborama has nowhere to accept a token, so private and gated models
cannot be imported directly today. Route those weights through
Import from private storage
instead: your CI downloads with its own credentials and bakes the
checkpoint into a container image.
The runtime's expected files, all present.
| Runtime | Required files |
|---|---|
lerobot | config.json, model.safetensors, train_config.json, plus the processor files (policy_preprocessor.json, policy_postprocessor.json) |
openpi | a training-config name (e.g. pi05_droid) plus the checkpoint directory, with assets/<asset_id>/norm_stats.json present alongside the weights |
Compatible hardware. Declare the action_space and
observation_contract the checkpoint was trained for, and pin a robot
and scene that provide them — aloha2-pro@fw1.1 in cell-a@v1.0 in the
example below. Admission checks the declarations against the pins, so a
policy that expects droid-3cam needs a cell that has three cameras.
Pin a version in the repo id
There is no revision field — you cannot pin a commit or a tag. The
supported convention is version-in-repo-id: publish an immutable release
repo per version (acme/skill-v4; the canonical openpi run uses
pi/espresso-v7) and never push to it again. Mutating a repo in place
makes results unattributable — two runs against the same repo id can be
two different policies, and nothing in the record will say so.
Connect
One call packages the checkpoint, one call runs it. The runtime names
how the checkpoint is served; the declared contracts say what it needs
from the cell.
import roborama # reads ROBORAMA_API_KEY from the environment
policy = roborama.Policy.checkpoint(
hf="acme/act-so101-pick-v2",
runtime="lerobot",
inference={"action_horizon": 100, "chunk_size": 100, "temp": 0.0},
action_space="joint_delta_50hz",
observation_contract="droid-3cam",
)
run = roborama.run(
robot="aloha2-pro@fw1.1",
environment="cell-a@v1.0",
policy=policy,
task="pick_place@v1",
episodes=300,
max_budget_usd=1000,
)
print(run.result())
# n=300 rate=0.843 ci95=(0.797, 0.881)The inference dict — action_horizon, chunk_size, temp — is
recorded with the run, because reproducibility includes decoding: the
same checkpoint at a different action horizon is a different policy as
far as your statistics are concerned.
The fetched copy
A checkpoint fetched for a run is cached to schedule and execute that
run, and is deleted when the run's data.retention window closes — or
immediately on roborama.data.purge(run_id), receipted. Making the
source repo private after import does not delete an already-fetched
copy; purge does. Retention and the rest of the IP posture live in the
data contract.
Validate
Three layers, in the order they can fail:
- Local (mock).
ROBORAMA_MOCK=1ormock=Trueruns the full quote → submit → result loop against packaged fixtures — no API key, no hardware. Catch a malformed call at your desk. - Admission (free). At submission, the declared
action_spaceandobservation_contractare checked against the pinned robot and scene. A mismatch returnscontract_validation_failed(422), and a rejected submission costs nothing. - Cell startup. The cell fetches the repo and loads the checkpoint under the named runtime. A repo that went private, or a checkpoint missing its files, surfaces here — after admission, before episodes.
import roborama
# Mock mode: no API key, no hardware. The whole loop runs
# offline against packaged fixtures — or set ROBORAMA_MOCK=1.
client = roborama.Client(mock=True)
quote = client.quote(
robot="aloha2-pro",
environment="cell-a",
episodes=300,
)
print(quote)
# {robot_hours: 10.0, env_hours: 10.0, usd: 860, queue_eta: "2h"}
run = client.run(
robot="aloha2-pro@fw1.1",
environment="cell-a@v1.0",
policy=roborama.Policy.checkpoint(
hf="acme/act-so101-pick-v2",
runtime="lerobot",
),
task="pick_place@v1",
episodes=300,
max_budget_usd=1000,
)
print(run.result())
# n=300 rate=0.843 ci95=(0.797, 0.881)Quote
A quote resolves both meters and the dollars before you commit
anything: quotes are free, rejected submissions are free, and nothing
bills until a motor moves. max_budget_usd is the mid-run hard stop.
Meters, tiers, and account-level controls are covered in
Billing & budgets.
import roborama # reads ROBORAMA_API_KEY from the environment
quote = roborama.quote(
robot="g1-edu-pro",
environment="kitchen-std",
episodes=600,
)
print(quote)
# {robot_hours: 20.0, env_hours: 20.0, usd: 3740, queue_eta: "6h"}Evaluate
Submission is the same run() every packaging
plugs into — the Connect example above already passes the policy in.
Episodes tick as the cell works through them; follow live with
run.watch() or the SSE stream.
import roborama # reads ROBORAMA_API_KEY from the environment
run = roborama.runs.get("run_8842")
for event in run.watch(): # live: episode ticker + WebRTC stream URLs
print(event.episode, event.status)
stream = roborama.streams.get("cell-g1-04")
print(stream)
# {webrtc: "wss://streams.roborama.com/cells/cell-g1-04/webrtc",
# mjpeg: "https://streams.roborama.com/cells/cell-g1-04/mjpeg",
# viewer_token: "vt_7Kq2mHentXw4"}Inspect results
run.result() carries n, the success rate, and a Wilson 95% interval —
the canonical openpi import, run_9101 (pi/espresso-v7 on
espresso@v1), reports n=412, rate=0.85. Per-episode artifacts (video,
MCAP telemetry, replay spec) hang off run.episodes, and
run.report(format="pdf") renders the citable verification report.
Field-by-field detail: data contract.
Compare versions
Version-in-repo-id makes comparison mechanical: keep the declared test
configuration — robot, scene, task, contracts, inference — identical
and change only the repo id, acme/act-so101-pick-v1 against
acme/act-so101-pick-v2. compare()
reports the paired delta; change anything else and you are comparing
test setups, not policies.
Troubleshoot
| Code | Symptom | Fix |
|---|---|---|
contract_validation_failed | submission rejected — the checkpoint's processor expects a camera set the pinned robot lacks, or an action space its firmware doesn't accept | declare the contracts the checkpoint was trained for, and pin a robot and scene that provide them |
firmware_pin_unavailable | the requested model@firmware isn't installed on any cell | list installed firmwares with robots.list() and pin one of them |
task_unknown | task id or version typo — pick_place@v2 when the catalogue has pick_place@v1 | check the task catalogue and pin an existing version |
budget_exceeded | run halted mid-flight at max_budget_usd; partial result kept, with honest n and interval | read the partial result; resubmit with a higher cap if the interval is too wide |
retention_expired | artifacts fetched after the run's data.retention window closed, or after a purge | the data is gone by design — re-run if you need fresh episodes |
Where next
- Walkthrough: LeRobot from the Hub — this path end to end, with real numbers.
- Upload a local checkpoint — publish local files to the Hub first, then import them the same way.
- Import from private storage — the route for weights that can't be public.
- Policies — the declared contracts and the
inferencedict in depth.