01 / Get started · Cloud

Cloud setup ​

Develop against a hosted environment instead of a local Shell — Dev by default (UAT/prod use the same shape). The Shell and platform already run in the cloud; you run only your app locally, point it at Dev, and register it there. The cloud Shell loads your local app in your browser — so keep your app's API and UI running, the UI as a production build, in Chrome (why).

You still run the app locally, so have the prerequisites installed — Docker, Bun, Node 20.12+ and git — and run the check there first.

Dev Shell UIveni.dev.venizia.ai
Dev Shell APIhttps://shell-api.dev.venizia.ai/api

First — get a Dev account

Dev has no seeded logins (unlike local). Request a Dev account with the developer role from the platform team — the developer role is what unlocks self-service app registration (Developer mode / My Apps). Once you're provisioned, sign in at veni.dev.venizia.ai via Keycloak / Google SSO.

The counter-intuitive part — the cloud Shell loads your local app in your browser, and your local API talks back to the cloud Shell to verify tokens:

1 · Get a Dev token ​

You need a Dev token to register an app. Two ways to get one — pick whichever suits you.

Install the veni CLI and let it sign you in (no local builder needed; also what you want if you're scaffolding a new app):

bash
curl -fsSL https://veni-builder-api.dev.venizia.ai/api/cli/install.sh | bash

It prints a short code, opens the Dev Shell in your browser to approve it, and saves a 90-day token — no copy-paste. veni lands in ~/.local/bin; put that on your PATH, then run bare veni to check it resolves. The full scaffold path is in Build a satellite.

Or mint one by hand — signed in to the Dev Shell, Profile → Personal access tokens → Create (shown once). Use it to register, to install the CLI without the browser step (-H "X-Veni-Token: <token>"), or in CI as VENI_TOKEN.

2 · Clone the app & start its services ​

Requirement

The app brings its own backing services — a database and its own Redis (cache + RBAC) — in its own repo. Nothing here comes from the cloud; only the Shell does.

Clone the app and start its services — HRM is the example; every app follows the same shape (swap the name, port and DB). Building your own instead? Scaffold it first, then continue here. From your workspace folder:

bash
git clone https://github.com/VENIZIA-AI/hrm.git
cd hrm
docker compose up -d hrm-db hrm-redis   # DB + Redis — both ship in the hrm repo

3 · Configure & run — pointed at Dev ​

Requirement

The app answers on its own port, talks to its own database, and can prove that a token the Dev Shell issued is genuine.

Configure. From the app folder, copy both envs — the API's and the UI's:

bash
cp api/.env.example api/.env
cp ui/.env.example ui/.env

api/.env — the copied defaults are already wired for this app's own database, Redis and port (3012); every line is documented in .env.example. Two things are yours to set. First the signing secret, same as local:

bash
sed -i.bak "s|^APP_ENV_JWT_SECRET=.*|APP_ENV_JWT_SECRET=$(openssl rand -hex 32)|" api/.env && rm -f api/.env.bak

Then the three lines that point at Dev instead of a local Shell — the only real difference from Local:

bash
APP_ENV_SHELL_JWKS_URL=https://shell-api.dev.venizia.ai/api/.well-known/jwks.json  # verifies Dev tokens
APP_ENV_SHELL_GRPC_URL=https://shell-api.dev.venizia.ai/api                        # call the Dev Shell
APP_ENV_CORS_ORIGINS=https://veni.dev.venizia.ai                                   # allow the Dev Shell origin

Using veni register? The three Shell lines are set for you

veni register --shell https://shell-api.dev.venizia.ai writes all three lines above into api/.env itself — that block is what you'd set by hand on the no-CLI path. You still set the secret yourself, and you still restart the API afterwards.

It leaves ui/.env alone, though — those Shell URLs are always yours to set.

ui/.env — the copied defaults keep pointing at your local API (VITE_API_URL, port 4175, service id hrm), which is right: the UI is still yours. Only its two Shell links move to Dev:

bash
VITE_SHELL_API_URL=https://shell-api.dev.venizia.ai/api  # Dev Shell API
VITE_SHELL_URL=https://veni.dev.venizia.ai               # Dev Shell UI — where a 401 sends you

Run. API and UI are separate processes — a terminal each. Copy one block per terminal. Note the UI is built and previewed, not dev — see below:

bash
# Terminal 1 · API :3012 — from hrm/
cd api && bun install && bun run db:migrate && bun run dev
bash
# Terminal 2 · UI :4175 — from hrm/ — a build, never `bun run dev`
cd ui && bun install && bun run build && bun run preview

Check it booted: curl http://localhost:3012/api/health → {"status":"ok"}. Restart the API after any .env change.

The UI must be a production build here — bun run dev will not do

This is the one place Cloud differs from Local, and it catches everyone.

Against a local Shell, bun run dev works because that Shell is itself a Vite dev server. The Dev Shell is a production build, and a dev-mode remote is a dev artifact — it ships an HMR shim and imports out of Vite's on-the-fly module graph (/node_modules/.vite/deps/…). A production host has no business loading that. So serve a production build of your own — the bun run build && bun run preview from the Run step above, never bun run dev.

preview serves on the same :4175 as dev, so the remote entry you register doesn't change. The trade: no hot reload — re-run build after every UI change, then refresh the Shell.

Because it is a build, ui/.env is baked in when you run build — set it first, and re-build after touching it. Skip it and the UI compiles happily with empty URLs, then fails at runtime with a token exchange to nowhere.

Open the Dev Shell in Chrome

The Shell is HTTPS and your app is http://localhost:4175. Chrome treats localhost as a trusted origin and loads it anyway; other browsers can refuse it as mixed content and your app silently never appears. Use Chrome for local-against-Dev work.

4 · Register & open ​

Requirement

The app is running on your machine, but the Dev Shell has never heard of it. It should appear on your launchpad and load at /<you>-hrm — signed in, no second login.

Your Dev account has the developer role (step 1), so register your own copy from the Dev Shell UI — nothing to install:

  1. Open veni.dev.venizia.ai and flip the sidebar toggle End-user → Developer. You land on My Apps.

  2. Paste HRM's two values:

    FieldValue
    Local UI URLhttp://localhost:4175
    App slughrm
  3. Register app — a local URL is allowed automatically here, no tick box.

Done — reload the Dev Shell and HRM is on your launchpad. Open https://veni.dev.venizia.ai/<you>-hrm in Chrome, keeping the API and the UI preview running: you're already signed in, no second login, and the cloud Shell loads your local remoteEntry.js.

Your slug is prefixed — that's expected

Self-service prefixes the slug with your Dev username and registers a private draft only you see, so many developers each register their own hrm without colliding. The unprefixed /hrm needs the admin role, which a Dev developer account doesn't have. Full role split: Register.

Prefer the CLI — or registering another app?

CLI — one command from the app root, using the Dev PAT and veni from step 1:

bash
veni register --shell https://shell-api.dev.venizia.ai   # PAT → self-service: mounts at /<you>-hrm, private draft

Dev is SSO-only, so there's no --user password login — and a PAT is always self-service (why). It also rewrites api/.env (JWKS, gRPC, CORS origin), so restart the app's API after.

Another app — same three steps, different values. Drive: local UI URL http://localhost:4176, slug drive, opens at /<you>-drive. Full reference + troubleshooting: Register.

Another environment — UAT/prod use the same shape; swap the host for shell-api.uat.venizia.ai / shell-api.venizia.ai.

Want more apps? Repeat steps 2–4 for each — they never collide (each owns its own database and ports).

Start over — reset the app locally

The Dev Shell is cloud-hosted, so there's nothing to reset there — only your local app holds state. From the app folder:

bash
docker compose down -v      # drops hrm-db and hrm-redis data

Then re-run bun run db:migrate (step 3) on the empty database. Stop the API and UI with Ctrl-C in their terminals; because the UI serves a build, re-run bun run build after any change.

Common snags ​

SymptomFix
API crash-loops: Environment validation failed: APP_ENV_JWT_SECRETBlank in .env.example; set APP_ENV_JWT_SECRET=$(openssl rand -hex 32) in the app's api/.env.
App API: relation … does not existYou skipped bun run db:migrate in api/.
App can't reach its DBIts Postgres isn't up (docker compose up -d hrm-db hrm-redis), or APP_ENV_DATABASE_URL uses :5432 instead of the mapped host port :15434.
App won't load on DevYour local API + UI must be running; My Apps allows the local URL automatically — register, then reload the Dev Shell.
Registered, but the path isn't /hrmSelf-service prefixes your Dev username → /<you>-hrm, a private draft. That's expected; open that path.
No My Apps in the sidebarFlip the sidebar End-user → Developer toggle. Missing entirely? Your Dev account lacks the developer role — request it from the platform team.
Blank frame, console errors about HMR or /node_modules/.vite/…The UI is running on bun run dev. The Dev Shell is a production host — run bun run build && bun run preview instead.
Nothing loads, and the console says the resource was blockedNot Chrome. An HTTPS Shell loading http://localhost is refused as mixed content by some browsers — open the Dev Shell in Chrome.
UI changes don't show uppreview serves a build, not a live server — re-run bun run build and refresh.
"Authentication Error — URL NOT FOUND" in the ShellVITE_API_URL is missing its trailing /api, so token exchange 404s. Fix ui/.env, then re-build.
App mounts but every API call goes nowhereui/.env didn't exist when you built. Create it and bun run build again — VITE_* is inlined at build time, not read at startup.
App loads but calls fail (CORS)The app API's APP_ENV_CORS_ORIGINS must include https://veni.dev.venizia.ai.
"not signed in" / token rejectedAPP_ENV_SHELL_JWKS_URL still points at localhost — set it to the Dev Shell API and restart the API.
CLI install fails to download (401/403)The installer's sign-in didn't complete, or the PAT you passed is invalid — re-run it and approve the code in the Dev Shell.
veni <cmd> → Not signed in — run veni login first.No token saved on this machine. veni login --shell https://shell-api.dev.venizia.ai, or set VENI_TOKEN for one run.

See also ​