03 / Develop · Build a satellite

Build a satellite ​

One command scaffolds an app that opens inside the Shell, already signed in — no login screen to build, no second URL, no auth code of your own. From there you add what you need, one capability at a time: an API, a database, rules about who may edit, people from other systems, tenants. Each one is a veni enable away.

The worked example is Calendar — a month view that grows into a real, multi-tenant, shipped app. Follow it end to end and you'll have written a calendar; more usefully, you'll have seen every seam the platform gives you.

This page is where you get ready. The building happens on the six pages below — read on.

Set up ​

Four things, once. Get them in place and the first command works on the first try; skip one and it fails quietly — veni create errors when there's no Shell to reach.

  1. Toolchain — Docker (Compose v2), Bun, Node 20.12+ (full list).
  2. A running Shell to develop against. Pick one and use it throughout:
    • Local — bring the whole platform up with Get Started (one command: bash dev-up.sh). The Shell UI lands at http://localhost:5173, its API at :3000.
    • Dev — nothing to run, but you need a Dev account with the developer role (ask the platform team): veni.dev.venizia.ai.
  3. Signed in as a developer. Registering apps is a developer-role action (self-service "my apps"), not something you do as admin. The local seed account is developer@venizia.local / Developer123!.
  4. The veni CLI — one line, no token to create first, against whichever Shell you picked:
bash
curl -fsSL http://localhost:3010/api/cli/install.sh | bash
veni           # prints the command list — add ~/.local/bin to your PATH if "command not found"
bash
curl -fsSL https://veni-builder-api.dev.venizia.ai/api/cli/install.sh | bash
veni           # prints the command list — add ~/.local/bin to your PATH if "command not found"

The installer signs you in as it goes: it prints a short code, opens your browser, and waits while you approve — then saves a 90-day token named after your machine. Nothing to copy-paste, no token to mint by hand. Already have a Personal Access Token and want no browser? -H "X-Veni-Token: veni_…" skips the approval step.

Every command but login, update, uninstall, status and the diagnostics (whoami, doctor, version) needs that token — veni create on a machine that never signed in stops with "Not signed in — run veni login first." (why). No CLI at all? Scaffold in the browser with the Builder UI wizard. Switching Shells later? veni login --shell <url>.

New to terms like federation, token exchange, repository or event bus? Skim Core concepts — it's a one-screen glossary. Everything else you'll pick up as you go.

The path ​

Six pages, in order. Each opens with a requirement the calendar has to meet, resolves it with the platform piece that answers it, ends with a Done when you can check — and hands off to the next. It's one continuous build on one app: start at the first card and keep going.

Only layer 1 is mandatory — stop at any card. veni enable on its own lists every capability, marks what's on, and resolves prerequisites for you (enabling database pulls in api first); veni status shows where you are.

What you end up with ​

Each command writes real files into your app — this is the shape you're building toward. Tags: [create] ships from veni create; [+api] and [+db] are added by veni enable api / veni enable database.

text
calendar/                                # [create] your app — its own repo, database, deployment
├─ veni.json                             # [create] manifest: theme, capabilities, ports, Shell
├─ ui/src/                               # [create] React + Vite, federated into the Shell
│  ├─ federation/shell-entry.tsx         # [create] ./ShellEntry — loaded at /calendar
│  └─ providers/UserProvider.tsx         # [create] gets the Shell token on mount
└─ api/                                  # [+api] Bun + Hono + Ignis backend
   ├─ .env                               # [+api] signing secret · JWKS URL · API port
   ├─ drizzle/                           # [+db] migrations + seed (roles, example perms)
   └─ src/                               # [+api]
      ├─ application.ts                  # [+api] composition root — wire DI at // veni: anchors
      ├─ services/auth.service.ts        # [+api] Shell-token → service-token exchange
      ├─ utils/auth-guards.ts            # [+api] requireAuth / requirePermission / ...
      ├─ services/user.service.ts        # [+db] local users (turns on APP_ENV_DATABASE_URL)
      ├─ models/schema.ts                # [+db] Drizzle tables — yours to define
      └─ repositories/base.repository.ts # [+db] AuditedRepository — created_by fills itself

authz, integration and tenancy add to these rather than new folders — their pages show exactly what.

See also ​

  • Common snags — the quiet failures, keyed by symptom. Bookmark it before you start.
  • Register an app — every way to get a running app into a Shell's launchpad.
  • The veni CLI — every command and flag in one table.