Skip to main content

tailor

Refine distributed robot datasets into training-ready data.

CI Python 3.12+ Ruff mypy License

English | 简体中文

tailor is a data-refinement pipeline for robot learning datasets (LeRobot v2.0 / v2.1 / v3.0):

  • Accept — verify incoming distributed datasets: format-version compliance, metadata-vs-data consistency ("does the package match the label"), transfer integrity, dims and stats vs your training config
  • Cut — episode-level filtering (frame-level issues escalate to episode removal to preserve action-chunk coherence)
  • Sew — deterministic cleaning only: timestamp rebuild, stats recompute, video re-encode. No imputation
  • Re-check — cleaned output must pass the acceptance suite again before release
  • Register — provenance ledger: source version, dropped episodes + why, recipe hash

Declarative recipes (YAML) in git; every dataset is reproducible and auditable.

tailor-made datasets for your training.

Quickstart

pip install lerobot-tailor      # once published; until then:
pip install git+https://github.com/XBR-1111/tailor

tailor check /path/to/lerobot/dataset
tailor check dataset.zip                # zip archive (wrapper dirs peeled)
tailor check lerobot/unitreeh1_fold_clothes   # HF repo id: meta pre-check, no full download
tailor check lerobot/... --full               # download everything, all 22 checks
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ check             ┃ status ┃ detail       ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━┩
│ info_json         │  PASS  │              │
│ codebase_version  │  PASS  │ v3.0         │
│ fps               │  PASS  │ 50           │
│ episodes_metadata │  PASS  │ 38 episodes  │
│ episode_files     │  PASS  │              │
│ total_frames      │  PASS  │ 19000        │
│ episode_lengths   │  PASS  │              │
│ task_indices      │  PASS  │ 1 task       │
│ state_action_dims │  PASS  │              │
│ nan_inf           │  PASS  │              │
│ timestamps        │  PASS  │              │
└───────────────────┴────────┴──────────────┘
ACCEPTED  ·  11 passed, 0 warn, 0 failed  ·  11 skipped (meta-only run)

Remote mode pulls only meta/* by default (seconds, a few MB) and runs every metadata-level check — file-presence checks SKIP honestly instead of faking a FAIL. HF_ENDPOINT is respected (mirrors work); downloads cache under ~/.cache/tailor-hf/.

Exit codes make it a CI gate: 0 accepted · 1 rejected · 2 unreadable (--fail-on-warn makes WARN exit 1 too). --json emits machine-readable output, --markdown report.md writes a PR/dataset-card friendly report, --max-episodes N samples the first N episodes of huge datasets (a convenience sample — tail-end episodes, a common corruption site, stay uncovered).

Filter — the Cut stage

tailor filter rewrites a dataset without the episodes you don't want, using lerobot's official delete_episodes engine (so the output is format-compatible by construction — parquet, videos and stats are rebuilt consistently). The result is re-checked automatically; its verdict is printed.

# drop explicit episodes (say, the ones a report flagged)
tailor filter /data/ds --drop-episodes 5,17,23 -o /data/ds_clean

# drop everything FAIL-level checks can pin to an episode (--drop-warn adds WARN)
tailor filter /data/ds --from-check --drop-warn

# rule-based
tailor filter /data/ds --min-length 100        # too short for your policy
tailor filter /data/ds --dedupe                # byte-identical trajectories, keep first

Requires pip install 'lerobot-tailor[lerobot]' (the acceptance suite itself stays dependency-free). Currently v3.0 datasets. Every drop is printed with its reason — no silent removals.

Clean — deterministic repairs

tailor clean fixes what deterministic math can fix: meta/stats.json recomputed from the parquet data (video entries preserved), timestamps rebuilt as frame_index / fps. Dry-run by default; --apply writes, backing up every replaced file to <dataset>_pre_clean/ outside the dataset root, then re-checks the dataset and prints the verdict. No lerobot dependency.

tailor clean /data/ds            # dry-run: what would change, nothing written
tailor clean /data/ds --apply    # repair + backup + automatic re-check

Register — the provenance ledger

Every filter and clean --apply appends one event to meta/tailor_ledger.jsonl inside the dataset, so the processing history travels with the data: filter writes a birth record into the output (source fingerprint, dropped episodes and why), clean appends what it rewrote.

tailor provenance /data/ds_filtered
# 2026-10-31T02:37:45+00:00  filter  from raw (b6b8be2337b9aae4, 38 eps) -> dropped 1: ep37 (explicit --drop-episodes)
# 2026-10-31T02:37:47+00:00  clean   rewrote ['meta/stats.json']

check never writes — acceptance is read-only. Fingerprints are structural (episode metadata + data file sizes), for identity not cryptographic proof.

Configurable acceptance profiles

What counts as acceptable differs per robot, task and training config. A profile (YAML in git — your dataset SLA, versioned and auditable) overrides per-check thresholds and severities; tailor is the engine that executes it:

# my_requirements.yaml
checks:
  codebase_version:
    allowed: [v2.1]     # this org only accepts v2.1
  fps:
    allowed: [30, 50]   # hardware reality
  episode_lengths:
    min: 100            # policy window needs headroom
    severity: fail      # short episodes are a hard reject here
  timestamps:
    spacing_tolerance: 0.2
tailor check /data/dataset --profile my_requirements.yaml

Any check can be remapped between WARN and FAIL. Unknown check names or keys in a profile fail fast with a clear error — a typo in your requirements must not silently keep a default you meant to change.

The 22 acceptance checks (v0.1)

check catches
info_json missing / invalid meta/info.json
codebase_version format version outside v2.0/v2.1/v3.0
fps non-positive or unusual fps
episodes_metadata missing/invalid episode metadata
episode_files data shard/parquet missing on disk (v2 files, v3 shard pointers)
total_frames declared total ≠ sum of episode lengths
episode_lengths zero/negative lengths; very short episodes that break chunked sampling
task_indices task references out of range; declared task count mismatch
state_action_dims state/action dims ≠ info.json features
nan_inf non-finite values in state/action
timestamps non-monotonic timestamps; frame spacing deviating >10% from 1/fps
stats_recompute declared stats.json mean/std drifting from recomputed values
action_quality frozen (stuck) action runs; one action dim pegged at its declared range edge; sudden jumps beyond k·sigma
video_files declared video streams missing on disk (v2 per-episode files, v3 shard pointers)
video_streams undecodable video; frame count vs episode lengths; resolution vs declared shape
zero_variance dims that never move (std < eps): normalization would divide by zero
schema_consistency column sets/dtypes drifting across episodes
frame_continuity dropped frames (row count vs declared length, frame_index holes)
training_readiness episodes shorter than your policy's chunk_size/horizon (configure to enable)
portability symlinks (break on transfer), stray files in data/, unexpected top-level entries
duplicate_episodes byte-identical state/action trajectories across episodes
splits overlapping episode ranges across declared splits (train/eval leakage)

Validated on a real 921 MB distributed dataset (lerobot/unitreeh1_fold_clothes, 38 episodes / 19k frames / stereo video) plus deterministic synthetic fixtures with injected corruptions — every corruption is caught by a test, on both format versions. The real dataset itself shipped two findings tailor caught on first contact: an action dim pegged at its range edge for 29 frames (gripper holding a folded shirt — WARN), and a genuine metadata defect where cam_left's episode-to-shard pointers all target file-000.mp4 while 500 of its frames actually live in an orphan file-001.mp4 — verified with the official reader: LeRobotDataset loads fine but every episode-37 frame raises IndexError (video index capped at 18500), so training crashes the moment a sampler touches the last episode.

Status

Acceptance suite, filter/clean and the provenance ledger shipped (v0.6). Roadmap, in priority order:

Accept depth (v0.2) — complete.

Pipeline closure (v0.3+) — Cut/Sew/Re-check/Register:

  • filter shipped (see above): explicit / rule-based / check-driven drops, dedupe, on official delete_episodes, auto re-check
  • clean shipped (see above): stats recompute + timestamp rebuild, dry-run first
  • provenance ledger shipped (see above): append-only, travels with the dataset
  • YAML recipes (tracking upstream recipe.py direction rather than inventing a schema)

Reference points: lerobot-doctor (diagnostics, now in the official dataset visualizer), Calibra (episode disposition decisions). tailor's lane is the acceptance gate plus the executed pipeline — verdict + exit code as a CI door, then deterministic refinement with provenance, not another report.

Metadata

Release files for lerobot-tailor 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lerobot-tailor 0.6.0
File Size Uploaded Provenance Actions
lerobot_tailor-0.6.0.tar.gz 230.5 kB Without provenance Details for lerobot_tailor-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for lerobot-tailor 0.6.0
File Interpreter ABI Platform Actions
lerobot_tailor-0.6.0-py3-none-any.whl Python 3 none any Details for lerobot_tailor-0.6.0-py3-none-any.whl

Total release size: 265.8 kB

Release files / lerobot_tailor-0.6.0.tar.gz

Download URL lerobot_tailor-0.6.0.tar.gz
Size 230.5 kB
Tags Source
SHA-256 checksum
How to use checksums
c184f44acdca6399dbd3bf073a3efc3abfdf148e2e1f11088f04f81ef8eef02b
BLAKE2b-256 checksum
How to use checksums
e4dcc8392895b42c66f0606634b8a4192ae29dce801e4bca12598187ab39fe84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Release files / lerobot_tailor-0.6.0-py3-none-any.whl

Download URL lerobot_tailor-0.6.0-py3-none-any.whl
Size 35.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
092c981120a8040f1ecb936b67c109f8aa98dcdfea1661f915814d7a4fee4d82
BLAKE2b-256 checksum
How to use checksums
2fa742b6b2352444a1686b8a364878f2b49c59d6691bf2d0de09da07d10c5345
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.12

Security for lerobot-tailor 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page