What is actually in the directory
my_so100_pick/
meta/
info.json fps, robot type and the feature schema
episodes.jsonl one line per episode, including its task string
stats.json per-feature mean and standard deviation, used to normalize
data/
chunk-000/
episode_000000.parquet per-frame joint state and action
videos/
chunk-000/
observation.images.wrist/episode_000000.mp4
observation.images.scene/episode_000000.mp4The split is deliberate. Numbers a trainer touches on every step live in Parquet, which is cheap to scan. Frames live in video, which is the only sensible way to store them. Everything a loader needs to interpret the columns lives in meta/info.json. stats.json is the part people forget: the normalization statistics are computed from your data, which is one reason a checkpoint belongs to the dataset it was trained on.
v2.1 against v3.0
| v2.1 | v3.0 | |
|---|---|---|
| Per-episode files | One Parquet file per episode | Episodes batched into larger chunks |
| Scaling | Fine at the size one arm produces | Built for corpora far larger than that |
| Preview and archive on this platform | Yes | Yes |
| Accepted by the GR00T trainers | Yes | No, rejected outright |
A v3.0 dataset fails a GR00T run right after upload, and the error does not name the cause in plain language. The client writes v2.1 by default, which keeps a dataset usable for all five trainers. If you moved to v3.0 deliberately, convert before queuing the run rather than after paying for it.
Datasets move with three commands, and none of them start training. Training runs on a rented cloud GPU, from the dashboard under Training or through the start_training tool on the MCP server.
ay-robots datasets list --local
ay-robots datasets upload ./my_so100_pick --name "SO-100 pick v1"
ay-robots datasets download <dataset-id>/so-100/lerobot goes through the format and the version split in detail, including converting in both directions.