03 / Develop · veni CLI

The veni CLI ​

veni is the platform's command-line tool — it scaffolds a new app, grows it one capability at a time (veni enable), runs it, and registers it with a Shell. It's served by Veni builder and talks to it: the Builder URL, the Shell, and your token are saved at install time.

Run any command from anywhere inside the app — the app root is found by walking up to veni.json, so veni add from ui/ behaves exactly like veni add from the root.

Install ​

One line, no token required — the installer signs you in through the browser (the same device flow as veni login):

bash
curl -fsSL https://veni-builder-api.dev.venizia.ai/api/cli/install.sh | bash
# Open this URL to approve:  https://veni.dev.venizia.ai/cli?code=WDJB-MJHT
# Signed in.
# Installed veni to /home/you/.local/bin/veni

Already hold a veni_ PAT? Bring it and skip the browser: -H "X-Veni-Token: <token>" on the curl, or VENI_TOKEN=veni_… in front of it. Full install detail — local Builder, VENI_BIN_DIR, what lands where — is in Get the veni CLI.

Put ~/.local/bin on your PATH, then check the install:

bash
veni            # prints the full command list
veni doctor     # bun/curl/tar, config, builder, shell, token, PATH — each ✓ or ✗ with a fix

Installing it to start a new app? Do it as part of Build a satellite → Set up, which lists the other prerequisites and hands off to the walkthrough that runs veni create.

Signing in ​

Every command that acts on an app needs a saved token. veni login gets one:

bash
veni login                              # signs in to the saved Shell
veni login --shell http://localhost:3000  # or a specific one

It shows a URL and a code, opens your browser, and saves the minted veni_ token. veni whoami says who you are and where; veni doctor says whether the token still works.

These commands run signed out, because they're what you need when you are: login, whoami, doctor, status, version, update, uninstall. Everything else stops with "Not signed in — run veni login first."

Commands ​

App state — theme, enabled capabilities, ports, the registered Shell — lives in veni.json at the app root; every command reads and writes it.

Setup ​

CommandWhat it does
veni loginSign in via the browser and save the token. --shell <url> picks the Shell (default: saved, else http://localhost:3000).
veni create <name>Scaffold a new app locally in ./<name> — UI-only by default. Flags below.
veni installInstall the app's API + UI dependencies (alias: i).
veni devRun every service the app has — API + UI — and forward their output; Ctrl-C stops all.

veni create flags — with none of them given, it prints the capability tour and asks for a theme:

FlagEffect
--api / --no-apiInclude the API service / skip the question
--db / --no-dbConfigure a database (pulls api automatically) / skip the question
--no-uiLeave out the UI (UI is included by default)
--theme <brand>Brand to apply, skipping the theme prompt
-y, --yesAccept the defaults, ask nothing
bash
veni create billing --api --db --theme veni
# Creating app "billing"  ·  capabilities: ui, api, database  ·  veni theme ...
# Created app "billing" (veni theme). API on port 3012, UI on port 3013.
# Next: cd billing && veni install && veni dev

Ports are picked for you: a free API/UI pair (UI = API + 1) plus a Postgres host port, avoiding both live listeners and ports already claimed by sibling apps.

Build ​

CommandWhat it does
veni enable <capability>Grow the app: api, database, storage, email, authz, integration, tenancy. Prerequisites are auto-pulled in order. --dry-run prints what it would write.
veni enableList every capability and mark what's on (✓ on · + available · — needs a prerequisite).
veni add <component…>Add shared-UI components from the app's theme. --overwrite replaces changed files without asking.
veni theme <brand>Switch the brand theme — overwrites ui/src/themes/tokens.css and records the choice.
veni themeShow the current theme and the available brands.

The theme comes from veni.json and nowhere else — veni add --theme no longer exists, because an app that mixes themes shows up as a styling bug rather than an error. Switch the whole app with veni theme <brand>, then add.

bash
veni add dialog
# theme: veni
# veni add dialog  ->  2 component(s)
#   + components/ui/button.tsx      # registryDependencies are pulled in
#   + components/ui/dialog.tsx
#   + dep   radix-ui@^1.4.3
# 2 added.

If a file already exists, add compares content: identical is a silent no-op, different asks you — [o]verwrite [s]kip [d]iff [a]ll [n]one, defaulting to keeping your file. With no terminal to ask in (CI, an agent), differing files are skipped and reported; --overwrite answers "all" up front. New npm deps are installed for you.

Ship ​

CommandWhat it does
veni registerRegister the app with a Shell, rewrite api/.env (JWKS/gRPC/CORS), and record the Shell in veni.json.
veni statusShow app state: capabilities, theme, ports, Shell.

veni register flags:

FlagDefault
--shell <url>The saved Shell, else http://localhost:3000
--shell-ui <url>Derived from --shell (needed when your Shell UI isn't at the conventional host)
--user <name> / --password <pass>Log in as this user instead of using the saved token
--token <jwt|veni_…>Use this token instead of the saved one
--slug <name>VITE_SERVICE_ID from ui/.env
--api-url <url> / --ui-url <url>Derived from the app's ports

A personal token is opaque, so the CLI can't see your roles: it registers through the developer self-service route and the app lands as a private draft until an admin publishes it. Pass --user or a session --token to take the admin route.

bash
veni status
# veni app: billing
#
#   theme         veni
#   ports         api 3012  ·  ui 3013
#   shell         http://localhost:3000
#   capabilities  ✓ui  ✓api  ✓database  ·authz  ·integration  ·tenancy

Toolchain ​

CommandWhat it does
veni whoamiWho you're signed in as, and against which Shell and Builder
veni doctorCheck this install and everything it talks to; exits non-zero when something is wrong
veni --versionThe installed toolchain version, compared against what the Builder serves (alias: version)
veni updateRe-pull the latest toolchain in place, keeping your saved config
veni uninstallRemove the global install and its launcher
bash
veni --version
# veni 9f2c1ab40e77  (server: 4d81e0c2aa19 — run `veni update`)

Environment ​

VariableEffect
VENI_SHELL_URLDefault Shell for login / register
VENI_BASEBuilder API to pull the toolchain and catalog links from
VENI_TOKENToken for one run, overriding the saved one
VENI_BIN_DIRWhere the installer drops the veni launcher (default ~/.local/bin)
VENI_HOMEWhere the toolchain is installed (default ~/.local/share/veni)

What the scaffold gives you ​

veni create gives a UI baseline — it federates into the Shell and is signed in for free, no login code. You add the rest with veni enable, and each layer ships the platform standard already wired, to use as generated rather than hand-rolled:

  • veni enable api — the token handshake (Shell RS256 → service HS256 exchange, JWKS verify, the jwt strategy, the UI's exchange + 401 retry) and the guards in utils/auth-guards (requireAuth, requirePermission, requireAdmin, requireOwnerOrAdmin). Identity works without a database (SSO-only). Never hand-roll a login, session, or JWT verify.
  • veni enable database — local-user provisioning, the roles + permissions tables, a working seed, and a test that covers the contract. You call the guards and seed your own codes.
  • veni enable storage: StorageClientService, which stores files in the platform storage app for each organization. It uses Shell installation tokens and the pod's own ServiceAccount token, so there is no secret to create. See Backend · File storage.
  • veni enable email: EmailClientService, which sends transactional email through the Shell and the organization's own SMTP (the platform's when it has none), with the same pod token as storage. See Backend · Email.
  • authz · integration · tenancy — developer-authored: enabling records the intent in veni.json and prints the next steps and the doc link.

Common snags ​

SymptomFix
"Not signed in — run veni login first."Run veni login (or set VENI_TOKEN for one run).
veni: command not found after install~/.local/bin isn't on your PATH — export PATH="$HOME/.local/bin:$PATH", or re-install with VENI_BIN_DIR set to a directory that is.
Not inside a veni app — cannot …cd into the app folder (the one holding ui/ and veni.json), or create one with veni create <name>.
veni add says the theme doesn't ship a componentComponents resolve from the app's theme only, with no fallback. Check veni theme, and refresh a stale CLI with veni update.
--theme is no longer supported from veni addSwitch the whole app instead: veni theme <brand>.
No theme recorded for this appveni theme <brand> — components are themed, so add has nothing to install from until one is set.
veni update says No Builder URL for this installveni login saves the Shell but never the Builder. Re-run the installer, or VENI_BASE=<base>/api veni update.
The Builder refused the download during veni updateThe token expired — veni login, then veni update again.

Where it's used ​

  • Build a satellite — the full flow: veni create → veni enable … → veni install → veni dev → veni register.
  • Register an app — the veni register path (vs. the no-CLI Shell UI).

See also ​