Run the Shell
Clone the repo, bring the stack up, sign in. It's self-contained — the repo's own docker-compose.yml carries every backing service. Two ways to run it:
- Just run it — one command brings the whole stack up, migrated and seeded. Best for a first look or a demo.
- Develop on it — run the API and UI from source for hot reload, with only the backing services in Docker.
Prerequisites
- Docker (Compose v2), Bun, and Node 20.12+ — the platform toolchain (full list).
- Docker runs the Shell's backing services — Postgres, Redis, MinIO and Keycloak — all defined in the repo's own
docker-compose.yml. - New to the platform? Get started brings it up end to end; this page is the Shell on its own.
1 · Clone
git clone https://github.com/VENIZIA-AI/veni-shell.git && cd veni-shell2 · Fastest — the whole stack in one command
docker-compose.yml is self-contained: it starts Postgres, Redis, MinIO and Keycloak, runs a one-shot migrate + seed, then the API and UI.
docker compose up -d
docker compose logs -f shell-api # watch it boot — the migrate job runs firstWhen shell-api is healthy, open http://localhost:5173 and sign in — that's the Shell running, migrated and seeded, no config to set. (New to the platform? bash dev-up.sh does this and more — see Get started.)
docker compose ps # every service should read "healthy"
docker compose down # stop it — add -v to wipe the DB + MinIO volumesWiping the volumes (-v) gives you a clean database, so the next up re-migrates and re-seeds from scratch. This path runs the API and UI as containers; to edit code with hot reload, use the development setup instead.
3 · Develop against it (hot reload)
Run only the backing services in Docker, and the API + UI from source. Postgres and Redis are enough to sign in; add minio keycloak when you need uploads or SSO:
docker compose up -d shell-db redis # host: shell-db :15433 · redis :16379Then the API first — it owns the database and the signing key — and the UI in a second terminal. bun is the direct path; make wraps the same commands.
API — :3000. Copy the env; you set only the signing secret (and the RSA key if remote apps will log in — tip below):
cp api/.env.example api/.env# api/.env — already wired for local dev; the service URLs match the compose above
APP_ENV_JWT_SECRET= # REQUIRED · openssl rand -hex 32
APP_ENV_JWT_PRIVATE_KEY= # optional — remote-app login (RS256)
APP_ENV_DATABASE_URL=postgresql://shell:shell@localhost:15433/shell_db # shell-db
APP_ENV_REDIS_URL=redis://localhost:16379 # redis
APP_ENV_PORT=3000
APP_ENV_FRONTEND_URL=http://localhost:5173Everything else is opt-in — the full env catalog (providers, storage, email, AI) is on Configure. Then install, set up the database, and run it:
cd api
bun install
bun run db:migrate && bun run seed # migrate before seed
bun run dev # :3000make install # installs API + UI deps
make migrate && make seed # migrate before seed
make dev-api # :3000UI — :5173. No .env to copy — the UI reads the committed ui/.env.development, which Vite loads automatically:
# ui/.env.development — already in the repo, points at the API above
VITE_API_URL=http://localhost:3000/api
VITE_DOCS_URL=http://localhost:5177In a second terminal:
cd ui
bun install
bun run dev # :5173make dev-ui # :5173 — deps already installed by `make install` above(Or skip the two terminals: make dev runs both in the background — make logs tails them, make stop stops them, make db-reset CONFIRM=yes rebuilds the database.)
Sign in
Open http://localhost:5173 and sign in — that's the Shell running. Either path leaves you with the same seeded database; the development seed creates one account per role tier:
| Sign in as | Password | Role |
|---|---|---|
admin@venizia.local | Admin123! | admin — start here |
developer@venizia.local | Developer123! | developer — self-service app registration (Build a satellite) |
guest@venizia.local | Guest123! | end-user — the plain signed-in view |
Three accounts, one per tier — the development seed is deliberately minimal. It also registers just the shell app itself; remotes appear on the launchpad only once you register them. The seed data is api/scripts/seed-data/development/.
Remote-app login needs the RSA key
The optional APP_ENV_JWT_PRIVATE_KEY line in the API env is what lets the Shell sign RS256 tokens and publish its public keys at the JWKS endpoint — which is how satellites verify them.
Leave it blank and the Shell signs HS256: you can still sign in here, but every satellite fails token exchange with "Shell JWKS returned no usable signing keys" (the satellite side). Generate a key into api/.env, then restart the API:
printf 'APP_ENV_JWT_PRIVATE_KEY="%s"\n' \
"$(openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 | openssl pkcs8 -topk8 -nocrypt | sed ':a;N;$!ba;s/\n/\\n/g')" >> api/.envCommon snags
| Symptom | Fix |
|---|---|
Remote apps report "not signed in" / Shell JWKS returned no usable signing keys | The Shell is signing HS256 — set APP_ENV_JWT_PRIVATE_KEY (see the RSA-key tip) and restart the API. |
make migrate fails / tables missing | Bring up shell-db first (docker compose up -d shell-db), and always migrate before seed. |
docker compose up fails — port is already allocated | Something already holds 15433 / 16379 / 3000 / 5173 — often a previous stack. Clear it with docker compose down, or stop the other process. |
| One-command stack is up, but sign-in 500s / no tables | The one-shot shell-migrate job failed — inspect docker compose logs shell-migrate. It must exit 0 before shell-api starts; a fresh docker compose down -v && docker compose up -d re-runs it. |
| Seeded account won't sign in | Run make seed after make migrate. To rebuild from scratch: make db-reset CONFIRM=yes. |
| Google / Keycloak missing from the login screen | Their env vars are unset, or the API wasn't restarted — both providers upsert on boot (Configure). |
| An edited OIDC provider row doesn't take effect | Seeding is insert-only — it won't update an existing row. Edit the DB, or clear and re-seed. |