Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,28 +41,22 @@ jobs:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
lfs: true
persist-credentials: false

# dist is shipped in Python installations, so it must match the source in every PR.
# Installing LeLab builds the frontend, so every PR must build.
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json

- name: Verify frontend tests and committed bundle
- name: Verify frontend tests and build
working-directory: frontend
run: |
npm ci
npm test
npm run build
if [[ -n "$(git status --porcelain -- dist)" ]]; then
git diff --stat -- dist
echo "::error::frontend/dist is stale. Run 'cd frontend && npm ci && npm run build' and commit frontend/dist in this PR."
exit 1
fi

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
Expand Down
9 changes: 3 additions & 6 deletions .github/workflows/sync_space.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
branches: [main]
paths:
- 'frontend/**'
- '!frontend/dist/**'
- '.github/workflows/sync_space.yml'
workflow_dispatch:

Expand All @@ -16,16 +15,14 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
lfs: true
persist-credentials: false
- name: Push frontend/ (without dist/) to Hugging Face Space
- name: Push frontend/ to Hugging Face Space
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
run: |
cd frontend
# The Space builds its own bundle via Docker; dist/ would be
# rejected by HF's pre-receive hook for containing raw binaries.
rm -rf dist
# HF's pre-receive hook rejects raw binaries, so the meshes go back to LFS.
echo 'public/so-101-urdf/meshes/*.stl filter=lfs diff=lfs merge=lfs -text' >> .gitattributes
git init -b main
git config user.email "ci@huggingface.co"
git config user.name "GitHub CI"
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
lfs: true

# lerobot is a transitive dep that needs these native libs at install /
# import time. List taken from LeRobot's fast_tests.yml.
Expand Down
2 changes: 0 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
default_language_version:
python: python3.12

exclude: '^frontend/dist/'

repos:
##### Meta #####
- repo: meta
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

LeLab is a FastAPI + React web interface wrapping the [LeRobot](https://github.com/huggingface/lerobot) framework for the SO-101 leader/follower arm. It exposes teleoperation, dataset recording, calibration, replay, and training as HTTP/WebSocket endpoints, replacing LeRobot's CLI + keyboard-driven flows.

The frontend (React + Vite) lives in [`frontend/`](frontend/). The built bundle in [`frontend/dist/`](frontend/dist/) is committed and shipped inside the Python wheel as package data (`frontend.__init__.py` makes setuptools treat it as a package); [`lelab/server.py`](lelab/server.py) mounts it as `StaticFiles` at `/` so a single `lelab` process serves both API and UI on `:8000`. The `frontend/` directory is also force-pushed to the [LeLab HF Space](https://huggingface.co/spaces/lerobot/LeLab) by [`.github/workflows/sync_space.yml`](.github/workflows/sync_space.yml) — that's a separate runtime; the Space builds the [Dockerfile](frontend/Dockerfile) (which runs `npm run build` again, so committed `dist/` doesn't matter to it).
The frontend (React + Vite) lives in [`frontend/`](frontend/). The bundle in `frontend/dist/` is not committed: [setup.py](setup.py) builds it while building the wheel, with Node from the `nodejs-wheel-binaries` build requirement, and ships it as package data (`frontend.__init__.py` makes setuptools treat it as a package); [`lelab/server.py`](lelab/server.py) mounts it as `StaticFiles` at `/` so a single `lelab` process serves both API and UI on `:8000`. The `frontend/` directory is also force-pushed to the [LeLab HF Space](https://huggingface.co/spaces/lerobot/LeLab) by [`.github/workflows/sync_space.yml`](.github/workflows/sync_space.yml) — that's a separate runtime; the Space builds the [Dockerfile](frontend/Dockerfile) (which runs `npm run build` itself).

## Common commands

Expand All @@ -25,7 +25,7 @@ lelab # uvicorn on :8000, serves built frontend at /, opens browser
lelab --dev # spawns Vite dev (:8080) + uvicorn --reload (:8000), opens browser to :8080
```

Frontend PRs must include the rebuilt `frontend/dist/` bundle: use Node.js 22 and run `cd frontend && npm ci && npm run build`, then commit `dist/` alongside the source changes. The required [Quality workflow](.github/workflows/quality.yml) rebuilds and rejects stale bundles before merge. `lelab --dev` serves directly from Vite, so development itself needs no rebuild.
Editable installs skip the frontend build: `lelab --dev` serves directly from Vite, and `lelab --rebuild` builds `frontend/dist/` with your local Node.js 22 when you want to try the production bundle. The SO-101 meshes in `frontend/public/` are kept out of LFS because installing from git does not fetch LFS files.

Run the Python tests with `pytest` (config in [pyproject.toml](pyproject.toml); install dev deps via `pip install -e ".[test]"`). Tests live in [tests/](tests/) and cover request schemas, pure helpers, and idle/mutex branches of the feature handlers — subprocess/thread happy paths and HF Jobs integration are deliberately not unit-tested. Lint with `ruff check` / `ruff format` (config in [pyproject.toml](pyproject.toml)). There is no Python build step; for end-to-end validation, run `lelab` and exercise endpoints (curl or via the frontend).

Expand Down
13 changes: 1 addition & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,7 @@ PRs welcome. Hot-reload mode for working on the code:
lelab --dev
```

Vite on `:8080`, uvicorn `--reload` on `:8000`.

For frontend changes, use Node.js 22 and rebuild the bundle before submitting your PR:

```bash
cd frontend
npm ci
npm run build
git add dist
```

Commit `frontend/dist` alongside the source changes. Python installations serve this bundle; the required Quality check verifies that it is up to date.
Vite on `:8080`, uvicorn `--reload` on `:8000`. Installing LeLab builds the frontend bundle, so PRs never include `frontend/dist`.

<div align="center">
<sub>Originally hacked together by <a href="https://www.linkedin.com/posts/nicolas-rabault-_lerobot-hackathon-lerobot-ugcPost-7341065019368828930-jTnl/">Team LeLab at the 2025 LeRobot Worldwide Hackathon 🏆</a>, now maintained by the <a href="https://huggingface.co/lerobot">LeRobot</a> team at <a href="https://huggingface.co">Hugging Face</a> with ❤️</sub>
Expand Down
5 changes: 3 additions & 2 deletions frontend/.gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
*.stl filter=lfs diff=lfs merge=lfs -text
*.lockb filter=lfs diff=lfs merge=lfs -text

# Build output: store as plain binary (overrides LFS) so the wheel can ship real files
dist/** -filter -diff -merge
# Plain binary (overrides LFS): installing from git skips LFS, and the build copies these into the wheel.
# sync_space.yml puts them back in LFS for the Space.
public/so-101-urdf/meshes/*.stl -filter -diff -merge
1 change: 1 addition & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

# Production
/build
/dist

# Misc
.DS_Store
Expand Down
1 change: 0 additions & 1 deletion frontend/dist/assets/index-BlBfFkzT.css

This file was deleted.

3,958 changes: 0 additions & 3,958 deletions frontend/dist/assets/index-Draxdzks.js

This file was deleted.

Binary file removed frontend/dist/favicon.ico
Binary file not shown.
20 changes: 0 additions & 20 deletions frontend/dist/index.html

This file was deleted.

Binary file not shown.
1 change: 0 additions & 1 deletion frontend/dist/placeholder.svg

This file was deleted.

14 changes: 0 additions & 14 deletions frontend/dist/robots.txt

This file was deleted.

37 changes: 0 additions & 37 deletions frontend/dist/so-101-urdf/CMakeLists.txt

This file was deleted.

45 changes: 0 additions & 45 deletions frontend/dist/so-101-urdf/README.md

This file was deleted.

This file was deleted.

12 changes: 0 additions & 12 deletions frontend/dist/so-101-urdf/joints_properties.xml

This file was deleted.

Binary file not shown.
Binary file removed frontend/dist/so-101-urdf/meshes/base_so101_v2.stl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed frontend/dist/so-101-urdf/meshes/sts3215_03a_v1.stl
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
26 changes: 0 additions & 26 deletions frontend/dist/so-101-urdf/package.xml

This file was deleted.

Loading
Loading