Before you start
Read the rules first. The most common cause of an invalidated
submission is an edited environment or metrics file, which is easy to avoid and painful to discover after
the deadline.
01
Submission Workflow
Three commands ship with the challenge release: evaluate runs your
policy and writes the logs and metrics, validate runs the same
automated checks the organizers run, and package produces the archive
you upload. All of them work from one submission directory.
-
Install the challenge release
Follow Getting Started. Evaluate from an unmodified
checkout of the release tag: the evaluator records a fingerprint of the benchmark source, and a modified
tree fails validation.
-
Start from the template
Copy the template bundle, then fill in
metadata.yaml, put your
weights in checkpoint/, and implement
policy/policy.py (see Policy Interface).
cp -r examples/challenge_submission ~/submission
-
Smoke-test on a few episodes
Catches interface and loading errors in about a minute. Partial runs are labelled as such and cannot be
submitted.
python -m roboeval.challenge.evaluate --submission ~/submission \
--tasks LiftPot --episodes 2 --output-dir /tmp/smoke --overwrite
-
Run the full evaluation
Runs all 8 tasks on the official seeds and writes
logs/ and
results.json into the bundle. Each worker evaluates one task;
--gpus spreads rendering across GPUs, and
--resume continues an interrupted run.
python -m roboeval.challenge.evaluate --submission ~/submission --workers 16 --gpus 0,1
For scale, measured with the template policy, which never finishes early (about 155k control steps
over the 8 tasks): with its three cameras, the command above took 81 minutes on 2 H100s;
proprioception-only took 7 minutes with 8 CPU workers. The longest task sets the pace, since each
worker runs one task. Policies that succeed early or use fewer cameras take less; your inference time
adds to these figures (a pi0.5 model served from one GPU took 42 minutes).
-
Write the report, then validate and package
Add
report.pdf. package runs
the full validation (including replaying a sample of your logged episodes), writes a checksum manifest,
and builds the archive. It refuses to package an invalid bundle.
python -m roboeval.challenge.validate ~/submission # optional: package runs it too
python -m roboeval.challenge.package ~/submission
-
Upload and submit
Host the archive somewhere the organizers can download without an account request — Hugging Face
Hub (preferred), Google Drive, S3, or an institutional server — and submit the link and the
printed SHA-256 through the form.
02
The bundle has this structure. Files marked generated are written by the tools; do not create
or edit them by hand.
submission/
├── metadata.yaml # you — team, method, and the interface the evaluator runs
├── report.pdf # you — technical report, max 4 pages + refs
├── checkpoint/ # you — policy weights (or set checkpoint_url, see below)
├── policy/ # you — inference code
│ ├── policy.py # defines make_policy(), see Policy Interface
│ └── requirements.txt # pinned extra dependencies
├── results.json # generated by evaluate
├── logs/ # generated by evaluate
│ └── <Family>_<Variation>/
│ ├── episode_<i>.json # seed, outcome, steps, raw and leaderboard metrics
│ └── episode_<i>.npz # the exact actions your policy sent
└── MANIFEST.sha256 # generated by package
metadata.yaml
The interface block is not just a declaration: the evaluator builds
every environment from it, so what you declare is exactly what runs.
team_name: "Your Team"
method_name: "YourMethod-v2" # as it should appear on the leaderboard
contact_email: "you@example.edu"
affiliation: "Your Institution"
members:
- "First Author"
- "Second Author"
roboeval_release: "corl2026-challenge"
interface:
action_mode:
absolute: false # false = delta actions
ee: true # true = end-effector pose, false = joint positions
control_frequency: 20 # Hz; fixed at 20 for the challenge
observation:
proprioception: true
cameras: # any of: external, head, front, left_wrist, right_wrist
- {name: head, resolution: [256, 256], rgb: true, depth: false}
- {name: left_wrist, resolution: [256, 256], rgb: true, depth: false}
- {name: right_wrist, resolution: [256, 256], rgb: true, depth: false}
policy_seed: 0
test_time_compute: "none" # e.g. "8 samples, reranked by value head"
training_data:
roboeval_demos: true # did you train on the provided demonstrations?
additional_demos: 0 # count of self-collected demonstrations
external_pretraining: "OXE, DROID" # or "none"
training_gpu_hours: 128
open_source: true
code_url: "https://github.com/you/your-method"
checkpoint_url: "https://huggingface.co/you/your-method"
Size limits
Keep the archive under 5 GB. Logs are small (a few kB per episode), so
the checkpoint is almost always what pushes a bundle over. If yours is large, host it separately, set
checkpoint_url, and package with
--exclude-checkpoint.
03
Policy Interface
policy/policy.py must define
make_policy(checkpoint_dir, metadata), returning an object with
reset and act. The evaluator
calls make_policy once per worker process. Other modules in
policy/ can be imported normally.
def make_policy(checkpoint_dir: Path, metadata: dict) -> Policy: ...
class Policy:
def reset(self, episode) -> None:
# episode.family, .variation, .env_name, .instruction (language goal),
# .seed, .policy_seed, .control_frequency, .max_steps, .action_space
...
def act(self, observation: dict) -> np.ndarray:
# observation["proprioception"] joint positions + velocities, both arms
# observation["proprioception_grippers"] gripper state
# observation["rgb_<camera>"] (3, H, W) uint8, per declared camera
# observation["depth_<camera>"] (H, W) float, if depth: true
# returns an action of shape episode.action_space.shape
...
Before each episode the evaluator seeds Python's and (if loaded) PyTorch's RNGs from
policy_seed and the episode seed, so a seeded policy reproduces exactly.
An exception in act ends that episode as a failure, with the
traceback in its log; the run continues.
04
results.json Schema
This file is produced by the evaluator from logs/. Do not edit it by
hand: the consistency check re-derives it from your logs, and the replay check re-runs your logged actions
in the simulator. It is documented here so you can confirm the evaluator ran over everything it should have.
{
"roboeval_release": "corl2026-challenge",
"harness_version": "1.0.0",
"method_name": "YourMethod-v2",
"episodes_per_variation": 50,
"seeds": [1000, 1001, 1002, "..."],
"interface": { "...": "copied from metadata.yaml" },
"results": {
"LiftPot": {
"PositionAndOrientation": {
"episodes": 50,
"metrics": {
"success": { "mean": 0.62, "std": 0.11 },
"tp": { "mean": 0.78, "std": 0.07 },
"bavd": { "mean": 0.19, "std": 0.03 },
"bgvd": { "mean": 0.08, "std": 0.01 },
"cpl": { "mean": 0.94, "std": 0.15 },
"ct": { "mean": 4.81, "std": 0.62 },
"ecc": { "mean": 1.90, "std": 0.44 },
"jpl": { "mean": 5.72, "std": 0.98 },
"mcj": { "mean": 5.11, "std": 0.87 },
"mjj": { "mean": 27.4, "std": 3.90 },
"opl": { "mean": 3.66, "std": 0.71 },
"scc": { "mean": 1.12, "std": 0.51 },
"sc": { "mean": 0.18, "std": 0.10 },
"tl": { "mean": 96.2, "std": 12.4 }
},
"terminations": { "success": 31, "fail": 2, "budget": 17, "unhealthy": 0, "error": 0 }
}
},
"LiftTray": { "...": "..." },
"StackTwoBlocks": { "...": "..." },
"StackSingleBookShelf": { "PositionAndOrientation": { "...": "..." } },
"CubeHandover": { "...": "..." },
"PackBox": { "...": "..." },
"PickSingleBookFromTable": { "...": "..." },
"RotateValve": { "PositionAndOrientation": { "...": "..." } }
},
"summary": { "per_family": { "...": "..." }, "suite": { "...": "..." } },
"score": { "overall": { "score": 0.283, "outcome": 0.334, "safety": 0.836, "efficiency": 0.550,
"coordination": 0.861 },
"tasks": { "LiftPot": { "...": "..." }, "...": "..." } },
"provenance": { "git_commit": "...", "source_fingerprint": "...", "mujoco_version": "3.3.3", "...": "..." }
}
Metric keys match the leaderboard schema in
static/data/leaderboard_schema.json. Each family has one entry, its
PositionAndOrientation variant. All 8 must be present: the schema check
rejects an incomplete file, so run your policy on every task even where you expect it to score zero.
05
Technical Report
A short report is required for every submission — maximum 4 pages plus references, CoRL format.
It is not peer-reviewed, and it does not affect your ranking. It exists so the community can learn
something from the leaderboard beyond a row of numbers. Cover:
- Method. Architecture, training objective, and what is novel relative to the
baselines.
- Data. Which demonstrations you trained on, any data you collected or generated, and
any external pretraining.
- Interface. Action mode, observation mode, control frequency, and any test-time
compute.
- Diagnostic analysis. Where your policy fails and why, using the stage-level and
behavioral metrics. This is the part we most want to read.
- Compute. Training GPU-hours and hardware.
Reports can become workshop papers
Challenge reports are welcome as submissions to the workshop's call for papers (short papers up to 5
pages, double-blind via OpenReview). See the
workshop
site for those deadlines, which are separate from the challenge deadline.
06
Submitting
Submissions go through the challenge portal, a Hugging Face Space that also hosts the live leaderboard.
Sign in with your Hugging Face account, then paste the link to your archive (or upload it) together
with the SHA-256 that package printed, and confirm you have read the
rules. Team name, method, and affiliation are read from
metadata.yaml.
The portal validates every submission on the spot, with the same checks as
validate, and shows you the report within a few minutes. Accepted
submissions appear on the leaderboard immediately; the most recent accepted submission is the one ranked.
Bundles that fail the automated checks are not counted toward your submission limit, so fix and resubmit.
- Each team submits from one Hugging Face account, and each account belongs to one team. The first
accepted submission links them.
- Each team may submit up to 2 times per day (UTC).
- Host the archive somewhere it downloads without signing in, such as a public Hugging Face repo. The
portal keeps a copy for verification.
07
Verification
Every submission goes through two automated checks, and prize-eligible submissions go through a third.
The automated checks are the ones python -m roboeval.challenge.validate
runs, so a bundle that validates locally passes them on receipt.
Evaluate on x86-64 Linux
Replay is exact only when the floating-point environment matches. The tools pin it automatically
(one OpenBLAS kernel, one thread), so run them on an x86-64 Linux machine with AVX2, using NumPy from
pip as the install does. Submissions evaluated elsewhere, for example
on Apple silicon, are held for organizer review rather than accepted automatically.
| 1. Schema check |
Automated. Confirms the bundle layout and metadata.yaml, and
that results.json covers all 8 tasks and all 14 metrics on
the official seeds, from an unmodified release. Runs on submission; failures are reported back so
you can fix and resubmit. |
| 2. Consistency check |
Automated. Re-derives every aggregate in results.json from
logs/, then replays a random sample of logged episodes' actions
in the simulator and requires the same outcome and metrics. This needs no checkpoint. Divergence
beyond floating-point tolerance is flagged for manual review. |
| 3. Held-out re-run |
Manual, for prize-eligible entries. Organizers run the same evaluator on your bundle with an
unpublished seed set (--seeds-file). Results must hold up within
normal run-to-run variance. |
If step 3 cannot be completed — the checkpoint does not load, dependencies are unresolvable, or the
inference code is incomplete — organizers contact you once with a fixed window to supply a working
artifact. Entries that remain unreproducible are not eligible for prizes, though they may still be listed
on the leaderboard marked as unverified.
08
FAQ
Do I have to train on the provided demonstrations?
No. The 3,000+ demonstrations are provided as a convenience. You may train from scratch, use your own
data, or fine-tune a pretrained model. Just declare what you used.
Can I submit a separate model per task?
Yes. make_policy is called once per worker, and
reset tells your policy the family and variation of every episode,
so policy.py can dispatch to per-task models. One bundle must still
cover all 8 tasks, and the report should say so. A generalist policy is not required, though we
expect it to be discussed in the report.
Can I use ground-truth object poses?
No. The challenge interface exposes proprioception and camera images only; object poses are not part
of any observation. Reading them, or any other simulator state, from inside your policy is a rules
violation. Submissions are grouped on the leaderboard by whether they use cameras, so image-based and
proprioception-only methods are compared separately.
My policy's inference is slower than 20 Hz. Is that a problem?
No. Evaluation is not real-time: simulated time advances only when your policy returns an action, so
inference speed affects how long the evaluation takes, not your score. Actions are applied at a
fixed 20 Hz for every submission. If your policy predicts action chunks, it can execute several
actions per inference call.
Can I update my submission after the deadline?
Only to fix a reproducibility problem the organizers raise during verification. You cannot change the
policy or improve results after the deadline.
Is a workshop paper required to compete?
No. The 4-page technical report is required; a workshop paper is optional and follows the workshop's
own OpenReview deadlines.
Do I need to attend CoRL 2026 to win?
No, but winning teams are invited to present at the workshop on November 12, 2026, and we strongly
encourage attendance.
Where do I ask technical questions?
Open an issue on the
RoboEval
repository. Questions about rules or eligibility go to
yiruwang@cs.washington.edu.