Close GR00T dogfood plan #403
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main, claude/test-aws-gpu-ci-gl5Jf] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: gpu-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install dependencies | |
| run: uv pip install --system ruff mypy | |
| - name: Ruff lint | |
| run: ruff check . | |
| - name: Ruff format check | |
| run: ruff format --check . | |
| - name: Mypy type check | |
| run: mypy src/ | |
| test: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| python-version: ["3.10", "3.11", "3.12", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install package with dev dependencies | |
| run: uv pip install --system -e ".[dev]" | |
| - name: Run tests with coverage | |
| run: pytest | |
| test-mujoco: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install system dependencies (OSMesa for headless rendering) | |
| run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev | |
| - name: Install package with demo and dev dependencies | |
| run: uv pip install --system -e ".[demo,dev]" | |
| - name: Run tests (including MuJoCo-dependent tests) | |
| env: | |
| MUJOCO_GL: osmesa | |
| run: pytest | |
| mujoco-example: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install system dependencies (OSMesa for headless rendering) | |
| run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev | |
| - name: Install package with demo dependencies | |
| run: uv pip install --system -e ".[demo]" | |
| - name: Run MuJoCo grasp example | |
| env: | |
| MUJOCO_GL: osmesa | |
| run: python examples/demos/mujoco/grasp.py --report --assert-success --output-dir ./harness_output | |
| - name: Upload visual artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: mujoco-grasp-output | |
| path: | | |
| harness_output/report.html | |
| harness_output/mujoco_grasp/trial_001/autonomous_report.json | |
| harness_output/mujoco_grasp/trial_001/alarms.json | |
| harness_output/mujoco_grasp/trial_001/phase_manifest.json | |
| harness_output/mujoco_grasp/trial_001/**/*_rgb.png | |
| harness_output/mujoco_grasp/trial_001/**/metadata.json | |
| retention-days: 30 | |
| - name: Post summary with checkpoint images | |
| if: always() | |
| run: | | |
| echo "## MuJoCo Grasp Example Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Checkpoint captures from the scripted grasp sequence:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| for cp in harness_output/mujoco_grasp/trial_001/*/; do | |
| name=$(basename "$cp") | |
| echo "### ${name}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ -f "${cp}front_rgb.png" ]; then | |
| echo ")" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ -f "${cp}metadata.json" ]; then | |
| step=$(python3 -c "import json; print(json.load(open('${cp}metadata.json'))['step'])") | |
| sim_time=$(python3 -c "import json; print(f\"{json.load(open('${cp}metadata.json'))['sim_time']:.3f}\")") | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Step: ${step} | Sim time: ${sim_time}s" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| done | |
| echo "---" >> $GITHUB_STEP_SUMMARY | |
| echo "Download the full artifact (including HTML report) from the Actions tab." >> $GITHUB_STEP_SUMMARY | |
| lerobot-g1-native-example: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install system dependencies (OSMesa for headless rendering) | |
| run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev | |
| - name: Install package with demo dependencies | |
| run: uv pip install --system -e ".[demo]" | |
| - name: Install unitree SDK directly from fork | |
| run: | | |
| # unitree-sdk2py is installed directly (not via a pyproject extra — | |
| # PyPI rejects packages with git-based direct references on upload) | |
| uv pip install --system "unitree-sdk2py @ git+https://github.com/MiaoDX-fork-and-pruning/unitree_sdk2_python_uv.git" | |
| - name: Install CPU PyTorch and lerobot | |
| run: | | |
| uv pip install --system torch --index-url https://download.pytorch.org/whl/cpu | |
| uv pip install --system lerobot | |
| - name: Install lerobot/unitree-g1-mujoco runtime deps | |
| run: uv pip install --system loguru pygame scipy pyyaml | |
| - name: Cache HuggingFace models | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/huggingface/hub | |
| key: hf-models-${{ runner.os }}-v1 | |
| - name: Run native LeRobot G1 example (GR00T) | |
| env: | |
| MUJOCO_GL: osmesa | |
| run: python examples/demos/g1/lerobot_native.py --controller groot --report --assert-success --output-dir ./harness_output | |
| - name: Upload visual artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lerobot-g1-native-output | |
| path: | | |
| harness_output/lerobot_g1_native_groot_report.html | |
| harness_output/lerobot_g1_native_groot/trial_001/**/*_rgb.png | |
| harness_output/lerobot_g1_native_groot/trial_001/**/metadata.json | |
| retention-days: 30 | |
| gpu-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| gpu_relevant: ${{ steps.filter.outputs.gpu }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| filters: | | |
| gpu: | |
| - 'tests/integration/gpu/test_gpu_smoke.py' | |
| - 'tests/integration/gpu/test_isaac_lab_gpu.py' | |
| - 'tests/unit/wrappers/test_isaac_lab_compat.py' | |
| - 'src/roboharness/wrappers/gymnasium_wrapper.py' | |
| - '.cirun.yml' | |
| - 'Dockerfile.gpu' | |
| - '.github/workflows/ci.yml' | |
| # ─── gpu-test (GCP) PAUSED 2026-04-14 ──────────────────────────────── | |
| # GCP runner is currently paused in .cirun.yml; AWS Sydney is the | |
| # primary GPU CI. To re-enable, uncomment the block below AND | |
| # uncomment the GCP runner block in .cirun.yml. | |
| # | |
| # gpu-test: | |
| # needs: [gpu-changes] | |
| # runs-on: [self-hosted, cirun-gpu] | |
| # timeout-minutes: 45 | |
| # # Only one GCP GPU job runs at a time globally — we only have quota for | |
| # # a single T4. `cancel-in-progress: true` so a new push immediately | |
| # # pre-empts any stale in-progress / queued job in this group; otherwise | |
| # # a stuck provisioning attempt would hold the slot indefinitely and | |
| # # every subsequent push would pile up behind it. | |
| # concurrency: | |
| # group: gpu-test-gcp | |
| # cancel-in-progress: true | |
| # if: | | |
| # github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| # || contains(github.event.pull_request.labels.*.name, 'gpu-test') | |
| # || needs.gpu-changes.outputs.gpu_relevant == 'true' | |
| # steps: | |
| # - uses: actions/checkout@v4 | |
| # - uses: actions/setup-python@v5 | |
| # with: | |
| # python-version: "3.12" | |
| # - name: Install uv | |
| # uses: astral-sh/setup-uv@v4 | |
| # - name: Install package with dev dependencies and torch | |
| # run: | | |
| # uv pip install --system -e ".[dev]" | |
| # uv pip install --system torch --index-url https://download.pytorch.org/whl/cu121 | |
| # - name: Verify GPU | |
| # run: | | |
| # nvidia-smi | |
| # python -c 'import torch; print(f"CUDA: {torch.cuda.is_available()}, GPUs: {torch.cuda.device_count()}")' | |
| # - name: Run GPU tests | |
| # run: pytest -m gpu -v --no-cov | |
| # ─── End paused gpu-test (GCP) ─────────────────────────────────────── | |
| # AWS GPU smoke test — primary GPU CI. Runs on the cirun-aws-gpu runner | |
| # provisioned on AWS (g4dn.xlarge in ap-southeast-2 + NVIDIA GPU-Optimized | |
| # AMI). Gated to the test branch and to the gpu-relevant paths filter so | |
| # we don't spin up AWS instances on unrelated pushes. | |
| gpu-test-aws: | |
| needs: [gpu-changes] | |
| runs-on: [self-hosted, cirun-aws-gpu] | |
| timeout-minutes: 45 | |
| # Serialize AWS GPU jobs too. `cancel-in-progress: true` so a new push | |
| # pre-empts any stale in-progress / queued attempt — important because | |
| # Cirun provisioning on AWS can silently sit queued (e.g. if the | |
| # Dashboard has no AWS credentials or the Marketplace AMI subscription | |
| # is still propagating), and `false` would stack pushes behind forever. | |
| # Runs in a different group from gpu-test-gcp, so GCP and AWS do not | |
| # block each other. | |
| concurrency: | |
| group: gpu-test-aws | |
| cancel-in-progress: true | |
| if: | | |
| github.ref == 'refs/heads/claude/test-aws-gpu-ci-gl5Jf' | |
| || contains(github.event.pull_request.labels.*.name, 'gpu-test-aws') | |
| || needs.gpu-changes.outputs.gpu_relevant == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Show host info | |
| run: | | |
| uname -a | |
| cat /etc/os-release || true | |
| nvidia-smi | |
| - name: Install package with dev dependencies and torch | |
| run: | | |
| uv pip install --system -e ".[dev]" | |
| uv pip install --system torch --index-url https://download.pytorch.org/whl/cu121 | |
| - name: Verify PyTorch CUDA | |
| run: | | |
| python -c 'import torch; print(f"torch={torch.__version__}, CUDA available={torch.cuda.is_available()}, GPUs={torch.cuda.device_count()}, name={torch.cuda.get_device_name(0) if torch.cuda.is_available() else None}")' | |
| - name: Run GPU tests | |
| run: pytest -m gpu -v --no-cov | |
| lerobot-g1-example: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v4 | |
| - name: Install system dependencies (OSMesa for headless rendering) | |
| run: sudo apt-get update && sudo apt-get install -y libosmesa6-dev | |
| - name: Install package with demo dependencies | |
| run: uv pip install --system -e ".[demo]" | |
| - name: Run LeRobot G1 example | |
| env: | |
| MUJOCO_GL: osmesa | |
| run: python examples/demos/g1/lerobot_locomotion.py --report --assert-success --output-dir ./harness_output | |
| - name: Upload visual artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lerobot-g1-output | |
| path: | | |
| harness_output/lerobot_g1_report.html | |
| harness_output/lerobot_g1/trial_001/**/*_rgb.png | |
| harness_output/lerobot_g1/trial_001/**/metadata.json | |
| retention-days: 30 | |
| - name: Post summary | |
| if: always() | |
| run: | | |
| echo "## LeRobot G1 Example Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Checkpoint captures from the G1 humanoid validation:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| for cp in harness_output/lerobot_g1/trial_001/*/; do | |
| name=$(basename "$cp") | |
| n_images=$(find "$cp" -name '*_rgb.png' 2>/dev/null | wc -l) | |
| if [ -f "${cp}metadata.json" ]; then | |
| step=$(python3 -c "import json; print(json.load(open('${cp}metadata.json'))['step'])") | |
| echo "- **${name}**: step ${step}, ${n_images} captures" >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "- **${name}**: ${n_images} captures" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| done | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Download the full artifact (including HTML report and images) from the Actions tab." >> $GITHUB_STEP_SUMMARY |