Self-host
Boot the whole hub on one machine from a checkout — Postgres, S3, API and web — and what a local stack does not have.
The hub is one FastAPI service, one Next.js app, a Postgres and an S3 API. This page boots all four on one machine from a checkout of the source repository — the same code a hosted hub runs — for development, or for a lab that wants its own. The commands were run verbatim against that local stack.
You need Docker, uv, Node ≥ 24 and the checkout.
Boot a local hub
One command builds the whole thing — database, object storage, migrations,
seed data, API on :8000, web on :3000:
make dev-local
Leave it running and open a second terminal for everything below. A Postgres runs in Docker and the S3 API is moto, in memory.
It seeds repos under the org lucen: a robot card built from the real Laika v2
MJCF, a dataset, a model, and one deliberately private repo so you can check
that "invisible" really means invisible. The dataset is synthetic —
generated at seed time — and the seeder says so on every run and writes the
warning into the repo's own README.
The local S3 is in-memory. If you restart it without also resetting Postgres, the database will still hold blob rows whose bytes are gone and downloads will fail.
docker rm -f lucen-hub-pg && make dev-localresets both.
A key without a browser session
On a hub with sign-in configured, keys are minted in API keys,
which requires a signed-in session by design — no API key may mint another. A
local stack runs with authentication unconfigured, so there is no session and no
button; tools/dev_api_key.py is the local-only door around it and refuses to
run against a database that is not on localhost:
NEON_DATABASE_URL=postgresql://postgres:lucen@127.0.0.1:5433/lucen uv run --no-sync python tools/dev_api_key.py --user you --scopes train | lucen auth login --stdin --url http://127.0.0.1:8000
Signed in as you (scopes: read, write, train) at http://127.0.0.1:8000
Saved to /Users/you/.config/lucen/credentials (mode 0600)
From here every step of From a terminal works against
the local stack, with http://127.0.0.1:8000 as the API and
http://localhost:3000 as the web app.
What a local stack does not have
- Sign-in. Clerk is unconfigured, so the browser is always signed out: public pages work, but the Quickstart's browser steps — adding a robot, training from its page, confirming a pairing, deploying — belong to an account and cannot be done from the page.
- The paid backends. Cloud training, hosted rollouts and hosted endpoints
(
executor: modal) answer 503 namingMODAL_APP_NAME; the Coach's diagnosis answers 503 withoutANTHROPIC_API_KEY. Everything that runs on your own machine —lucen worker run,lucen rollout --local,lucen serve— works.
Deploying a hub of your own to the cloud (Fly, Vercel, Neon, R2, Upstash,
Clerk) is described step by step in the repository's docs/RUNBOOK.md.