scripts/setup/ — workspace bootstrap modules
This directory hosts the modular pieces sourced by scripts/setup.sh:
| File | Responsibility |
|---|---|
detect.sh |
OS / arch / Python detection; resolves IBR_HOST_* and IBR_LEROBOT_PROFILES. |
platforms/<id>.sh |
Per-platform package managers, ROS source, and platform_lerobot_profiles() defaults. |
lerobot_patches.sh |
Drives git am of the curated lerobot patch stack into libs/lerobot. |
lerobot_resolve_active.py |
Resolves the active lerobot tag from INDEX.yaml; cross-checks the per-tag manifest.yaml. |
lerobot_filter_series.py |
Reads manifest.yaml + host facts, prints the patch series that actually applies. |
tests/test_lerobot_filter.sh |
Regression fixtures pinned to the canonical 3-platform matrix + tag-binding cases. |
LeRobot patch dispatch
libs/lerobot ships one patch series per supported upstream tag under
third_party/patches/lerobot/<tag>/. The single source of truth that
selects which tag is active is third_party/patches/lerobot/INDEX.yaml
(see Multi-tag layout below). Within the active
tag, not every patch applies to every host. The applier filters the
raw series.txt through lerobot_filter_series.py, which gates each
patch on independent predicates declared in manifest.yaml:
python_min/python_max— bounded interval (>=3.10,<3.11, ...).profiles— set intersection against the active profile set.
The active profile set is resolved with this precedence (highest first):
--lerobot-profiles core,ascend,...CLI flag onsetup.sh.IBR_LEROBOT_PROFILES=core,ascend,...environment variable.platform_lerobot_profilescallback in the active platform script.- The fallback
core,ros,hardware,dev.
Common overrides for hardware bring-up
# Force the Ascend NPU patches on a desktop verifying inference parity:
./scripts/setup.sh --yes --lerobot-profiles core,ros,hardware,ascend
# Bring up an OpenHarmony device as if it were a vanilla core target:
./scripts/setup.sh --yes --lerobot-profiles core
# Explicitly bypass the filter (last-resort escape hatch — applies the raw
# series.txt verbatim, even patches that do not match host facts):
IBR_LEROBOT_FORCE_UNFILTERED=1 ./scripts/setup.sh --yes
Diagnosing the filter
The applier prints a [CTX] python=X.Y profiles=... audit line and a
KEEP / SKIP decision for every patch. To preview without touching
libs/lerobot:
IBR_HOST_PYTHON_VERSION=3.11 \
IBR_LEROBOT_PROFILES=core,ros,hardware,openeuler \
python3 scripts/setup/lerobot_filter_series.py \
--manifest third_party/patches/lerobot/v0.5.1/manifest.yaml \
--series third_party/patches/lerobot/v0.5.1/series.txt
When to add a new patch
- Add the patch file under the active tag's directory
(
third_party/patches/lerobot/<active_tag>/;<active_tag>is whateverINDEX.yaml.active_tagcurrently points at). - Append it to that tag's
series.txt. - Register a
patches[]entry in the same directory'smanifest.yamldeclaring explicitpython_min/python_max/profilespredicates. Default to the narrowest set that is known to be safe; broaden later once verified on additional platforms. - Add a fixture line to
scripts/setup/tests/test_lerobot_filter.shso the pre-commit hook catches accidental scope changes.
Multi-tag layout
third_party/patches/lerobot/INDEX.yaml is the single source of truth
for which upstream lerobot tag the setup script targets. Each tag owns
its own directory of patches plus a manifest.yaml that re-declares the
binding so the resolver can fail closed on drift:
third_party/patches/lerobot/
├── INDEX.yaml # active_tag + supported_tags + archived_tags
├── v0.5.1/ # one directory per supported tag
│ ├── manifest.yaml # declares lerobot_tag + lerobot_commit_range
│ ├── series.txt
│ └── 0001-*.patch ...
└── v0.6.0/ # (example: future tag added side-by-side)
└── ...
The resolver (lerobot_resolve_active.py) enforces these invariants:
| Invariant | Failure mode |
|---|---|
INDEX.active_tag matches a supported_tags[] entry |
resolver exits 1 with "active_tag not found" |
The active entry's dir exists with manifest.yaml + series.txt |
resolver exits 1 with "directory does not exist" |
INDEX.supported_tags[i].upstream_commit == manifest.lerobot_commit_range.min |
resolver exits 1 with "INDEX vs manifest mismatch" |
INDEX.active_tag is not present in archived_tags[] |
resolver exits 1 with "archived tag" |
libs/lerobot HEAD prior to patch application falls inside manifest.lerobot_commit_range |
filter exits 1 with "HEAD not in commit_range" |
Upgrading to a new lerobot tag
- Bump the
libs/lerobotsubmodule to the new upstream tip and record the resulting sha as<NEW_COMMIT>. - Create
third_party/patches/lerobot/<NEW_TAG>/and rebase the patches you need on top of<NEW_COMMIT>(drop / port any that no longer apply). Author a freshmanifest.yamlwith:lerobot_tag: <NEW_TAG> lerobot_commit_range: min: <NEW_COMMIT> max: <NEW_COMMIT> # widen later if you accept fast-forward upstreams - Append a
supported_tags[]entry underINDEX.yamlpointing at the new directory, with matchingupstream_commitand a uniquebranch_name(convention:ibrobot/lerobot-<NEW_TAG>-patched). - Flip
INDEX.yaml.active_tagto<NEW_TAG>. Optionally move the previous tag's entry fromsupported_tags[]intoarchived_tags[]once it is no longer maintained — archived entries stay in tree for audit but the resolver refuses to use them. - Add fixture coverage for the new tag in
scripts/setup/tests/test_lerobot_filter.shand run the regression harness; both the resolver and the per-platform filter cases must pass before submitting.
Failure modes
| Symptom | Cause | Fix |
|---|---|---|
lerobot_filter_series.py failed with exit 1, "PyYAML required but missing" |
venv lacks python3-yaml |
pip install pyyaml in the workspace venv, or set IBR_LEROBOT_FORCE_UNFILTERED=1 to skip filtering. |
failed to parse manifest, exit 1 |
manifest.yaml is malformed |
Lint the YAML; the applier fails closed by design. |
lerobot_resolve_active.py failed, "active_tag not found" |
INDEX.yaml.active_tag does not match any supported_tags[] entry |
Add the entry, or fix the active_tag value. |
lerobot_resolve_active.py failed, "INDEX vs manifest mismatch" |
INDEX.supported_tags[i].upstream_commit and manifest.lerobot_commit_range.min disagree |
Update one to match the other; they MUST be kept in sync. |
libs/lerobot HEAD ... is not in the manifest commit_range |
submodule HEAD diverged from the active tag's declared range | Either checkout the expected base, fast-forward the manifest range, or add a new tag directory + flip INDEX.yaml.active_tag. |
| Worktree dirty, applier aborts | local edits in libs/lerobot |
Stash / commit your edits, or set IBR_LEROBOT_FORCE_REBUILD=1 to discard them and rebuild the patched branch from scratch. |