[build-system] requires = ["uv_build>=0.8.19,<0.9.0"] build-backend = "uv_build" [project] name = "mjlab-microduck" version = "0.1.0" description = "RL training environments for the Microduck robot, built on mjlab" readme = "README.md" license = "Apache-2.0" license-files = ["LICENSE"] # <3.13: bam (better-actuator-models) pins requires-python <3.13, and jobs must # run the same interpreter we test locally (3.12) — a floating upper bound let # HF jobs pick 3.13.14 (2026-07-21). requires-python = ">=3.12, <3.13" dependencies = [ "mjlab==1.3.0", "warp-lang==1.12.0", # BAM distribution name is `better-actuator-models`; the import stays `bam`. "better-actuator-models", "onnxruntime>=1.24.4", "rustypot>=1.4.2", "huggingface_hub>=0.27.0", "matplotlib>=3.10.9", # mjlab 1.3.0 imports scipy (terrains/heightfield_terrains.py) but forgets # to declare it — without this line a fresh `uv sync` (e.g. on HF jobs) # can't even `import mjlab_microduck` (found 2026-07-21). "scipy>=1.16", # Direct dep ONLY so [tool.uv.sources] can bind torch to the CUDA index on # aarch64 (see the torch source below) — uv applies sources to DIRECT # dependencies only, so as a purely transitive dep (mjlab, rsl_rl) the # source entry is silently ignored. # Pinned to the exact version uv.lock already resolved from PyPI so this # changes only the SOURCE of the wheel on aarch64, not the version: a # floating `>=` lets the CUDA index (which carries newer builds than the # PyPI pin) drag torch 2.9.1 -> 2.13.0, an unvetted bump for mjlab/rsl_rl. "torch==2.9.1", ] [project.entry-points."mjlab.tasks"] mjlab_microduck = "mjlab_microduck.tasks" [project.scripts] # Shadows mjlab's `train` entry point: identical behavior, plus a --hf-jobs # flag that submits the run to Hugging Face Jobs instead (see train_cli.py). train = "mjlab_microduck.train_cli:main" [tool.ruff] src = ["src"] # Helpful for recognizing first-party imports. indent-width = 4 exclude = [ "src/mjlab/third_party", "typings", ] [tool.uv] override-dependencies = [ # NOTE: do NOT override mujoco — mjlab 1.3.0's mujoco-warp pins a compatible # mujoco (3.10.x); an override here previously forced mujoco down to 3.4.0, # which lacks mjDSBL_MULTICCD that mujoco-warp 3.8.1 imports → import crash. # bam pins protobuf<4.0 (for its zmq/dynamixel messaging, which we don't # use — we only import bam.model/bam.actuator). Without this override the # downgrade cascades onnx down to 1.17.0, which has no wheel and fails to # build from source. "protobuf>=4.0,<7.0", # Keep onnx on a version with prebuilt wheels (1.17.0 has no py3.13 wheel and # fails to build from source). Pulling in bam otherwise nudges it downward. "onnx>=1.20.1", # bam depends on the PyPI stub `zmq==0.0.0`, whose prebuilt wheel is invalid # (missing .dist-info) -> `uv sync` fails on a FRESH install (e.g. HF Jobs # remote build), even though a warm local cache tolerated it. We only use # bam.mjlab (no zmq/erob messaging), so drop zmq via an always-false marker. "zmq ; python_version < '3.0'", ] [tool.uv.sources] # mjlab now comes from PyPI (==1.3.0, pinned in [project.dependencies]); no git source. # Official BAM actuator model. Switch to `main` (or a tag) once the # mjlab-facing API lands there. better-actuator-models = { git = "https://github.com/Rhoban/bam.git", branch = "mjlab_frictionloss" } # For local BAM development, comment the line above and use: # better-actuator-models = { path = "/home/antoine/Rhoban/bam", editable = true } # On linux-aarch64 (DGX Spark / GB10) PyPI's torch wheel is CPU-ONLY: # torch.__version__ == "2.9.1+cpu", torch.version.cuda is None, so # torch.cuda.device_count() == 0 and mjlab's select_gpus() indexes an empty # list -> `IndexError: list index out of range` before training even starts # (mjlab/utils/gpu.py:70). Route torch to PyTorch's CUDA index there. # cu129 (not cu130) matches the CUDA toolkit warp 1.12.0 bundles, so the # zero-copy warp<->torch interop stays on one runtime major version. # The marker keeps x86_64 (HF Jobs) on PyPI, where the wheel already bundles # CUDA via its nvidia-*-cu12 deps — that resolution is unchanged. torch = [ { index = "pytorch-cu129", marker = "sys_platform == 'linux' and platform_machine == 'aarch64'" }, ] [[tool.uv.index]] name = "pytorch-cu129" url = "https://download.pytorch.org/whl/cu129" # explicit: only packages that name this index resolve from it. explicit = true