Overview
The voltro CLI — every command, grouped by purpose, with the flags that actually matter.
The Voltro CLI is the single entry point for scaffolding, dev, build, and run. It also seeds the framework agent guide into every project — written under BOTH AGENTS.md and CLAUDE.md — so AI coding agents have your framework conventions on tap.
Command quick-reference
The dispatcher routes voltro <command> [args] to the matching subcommand and passes the rest through. The full set:
| Group | Commands |
|---|---|
| Scaffolding | create-project, add-app, list-templates |
| Packages | package (create / publishable / private / status), create-package |
| Dev | dev, codegen, agents-md, env (check / sync / types / turbo), generate (AI app-builder), dashboard (serve the DevTools dashboard standalone; --port, VOLTRO_DASHBOARD_APPS) |
| Build & run | build, start, serve |
| Deploy | deploy (plan — auto-detect the target tier per app + function), serverless (list / dev / serve / build / deploy), static (hosts / deploy), dormancy (single-node scale-to-zero: fronts the app, stops it when idle, wakes on the next request; --idle-grace-ms / --tick-ms) |
| Database | migrate, db (plan / apply / plans / drift / squash / restore-snapshot / migrate / rollback / status / seed) |
| Update | update (--to / --dry-run / --force / --exact) — bump every @voltro/*, install, run the codemods that adapt your source to the new version |
| Data transfer | data (export / import / unpack / inspect / backup / restore) — directory + single-file .vbundle bundles, streaming assets, masking, at-rest encryption |
| Ops / infra | cache (status / flush / invalidate), add (redis), baseline (list / status / set), schedule-manifest, storage (doctor / cors) |
| AI / data | embeddings backfill <table> --text <field> --vector <field> — (re)embed rows the vectorEmbedding() mixin missed (pre-existing rows / a model change); --dry-run to preview |
| Inspect & debug | inspect, logs, traces, workflows, cluster, check |
| Health & surface | doctor — serve preflight + the hand-roll detector (names the shipped primitive at the spot you're rebuilding it); capabilities (--json) — the export surface read from your installed @voltro/*, so it can be verified instead of recalled |
| Harness | test, e2e |
| Cloud | cloud (login / whoami / projects / env / import) |
| Secrets | secret (generate [purpose] — the right var+format per secret; generate alone → a generic secret; list) |
| Meta | agents-md, version, help |
Each command takes an optional path argument (the app directory) — defaults to . when run from inside an app. voltro init scaffolds a project (it delegates to the create-project scaffolder, forwarding --api/--web/--baseline/--cache). voltro secret generate [purpose] prints a cryptographically strong secret — with a purpose (data-transfer, session, bundle-key, field-encryption, storage, inspect) it emits the correct env var + length/format as a paste-ready NAME=value (voltro secret list shows them all); with no purpose, a generic base64url secret. voltro telemetry reports that Voltro collects none. voltro deploy shows the deploy paths — self-host via a baseline + CI, managed via the control-plane client voltro cloud (managed cloud deploy is coming soon — see Voltro Cloud), individual serverless functions (voltro serverless → self-hosted Node, or Cloudflare / Scaleway), or a static site (voltro static → Cloudflare Pages / S3 / Netlify).
Help + version
voltro help prints the command list; voltro version prints the CLI version. These are subcommands, not global flags — there is no global --version / --help parsing in the dispatcher.
Common per-command flags
There is no universal global-flag layer; flags are per-command. The ones that recur:
| Flag | Where it applies |
|---|---|
--format pretty|json |
logs, traces, inspect, cluster, workflows — machine-readable output. |
--no-color |
logs, traces — strip ANSI codes when piping to a file. |
--process <name> |
logs, traces, inspect, cluster — narrow to one running process. |
--force |
agents-md — overwrite existing files. |
Commands like build / start / migrate / codegen parse no flags at all — only an optional path. Check each command's page for its real surface.
Common env vars
The CLI reads:
| Var | Effect |
|---|---|
NODE_ENV |
production / development / test. Affects defaults across many commands. |
DB_DIALECT |
postgres (default) / mysql / mariadb / mssql / sqlite / turso / memory. Picks the SQL backend. |
STORE |
memory / postgres — alternate data-store selector (resolution order: DB_DIALECT → STORE → app.config.ts). |
WATCH |
0 / 1. Toggle filesystem watch in voltro dev. |
VOLTRO_DASHBOARD |
off to disable the auto-launched dashboard. |
VOLTRO_LOG_FORMAT |
pretty / json. Force the logger's output format. |
VOLTRO_LOG_LEVEL |
trace / debug / info / warn / error / fatal. |
VOLTRO_INSPECT |
off to disable the /_voltro/inspect/* HTTP endpoints. |
VOLTRO_INSPECT_TOKEN |
Bearer token for guarded inspect endpoints. |
DB_URL |
Database connection string (falls back to DB_PRIMARY_URL; or the discrete DB_* / PG_* fields). |
VOLTRO_SESSION_SECRET |
Session-cookie signing secret (@voltro/plugin-auth). Rotate with zero downtime: move the old value to VOLTRO_SESSION_SECRET_PREVIOUS for one session lifetime — cookies signed with either secret keep verifying, and previous-key cookies are re-issued under the new one. |
VOLTRO_DATA_TRANSFER_SECRET |
Gates the prod data-transfer endpoints (POST /_voltro/admin/{export,import}); ≥16 chars or the routes don't mount. |
VOLTRO_BUNDLE_KEY |
Passphrase for .vbundle export encryption (voltro data export --encrypt). A DEDICATED key, not the transfer secret. |
VOLTRO_FIELD_ENCRYPTION_KEY |
Key for .encrypted() columns (governancePlugin({ fieldEncryption: true })) — a passphrase or a raw 64-hex AES-256 key. |
VOLTRO_STORAGE_SECRET |
Signs storage grant tokens (private files); falls back to the session secret if unset. |
AI_PROVIDER / AI_MODEL / AI_API_KEY |
Per-provider AI config. |
Generate any of the secret vars above with voltro secret generate <purpose> (see secret) — it picks the right length and format. A lower environment's secrets must always differ from production's.
Workflow patterns
"I'm starting a new project"
pnpx voltro create-project acme --api api-backend --web frontend-landing
cd acme
pnpm install
pnpm dev # turbo runs voltro dev across every app in the project"I want to add a docs site to my existing project"
voltro add-app docs --template frontend-docs --to acme
pnpm install # picks up the new app's deps
pnpm dev # turbo adds the new app to its parallel boot"I changed my schema and want to apply it"
voltro db plan # diff declared schema vs live, color-coded
# review the plan
voltro db apply # execute it (dev)
# `voltro migrate` is an alias of `db apply` — same differ, shorter name (CI / ops)"I want a clean rebuild"
voltro codegen # rewrite the generated rpc group + .framework/*
voltro build # vite build + SSG pre-render
voltro start # production server"Something's wrong — inspect what's running"
voltro inspect rpc # discovered procedures + workflows
voltro inspect routes # web page tree (web apps)
voltro inspect metrics # request rates, p95 latencies
voltro logs --tail 100 # recent structured logs
voltro traces --errors # traces with an errored span
voltro workflows list # recent workflow runs"Did my edit break a binding?"
voltro check runs blast-radius checks over your app's typed graph — dangling
source / target tables, scopes no role grants, unguarded mutations, broken
route bindings, orphan tables — at edit time instead of at runtime. --json
emits LLM-shaped diagnostics so a coding agent can fix-and-repeat; --diff
previews the blast radius of a removal BEFORE you apply it.
It prefers a running api (its manifest is ground truth, including live table
introspection). With none reachable it assembles the same graph from source,
so it works as a pre-commit hook or a CI gate without a second terminal —
--offline forces that path.
voltro check # running api if there is one, else from source
voltro check --offline # never contact a server — the CI form
voltro check --url https://api.example.com # a DEPLOYED app
voltro check --json # { ok, diagnostics: [{ rule, node, breaks, fix }] }
voltro check --diff removeTable:todos # what a proposed removal would break, before applyingrbac/unknown-scope needs a declared scope vocabulary to compare against —
rbacPlugin({ roles }) publishes one automatically. It catches a guard
requiring a scope no role grants, which makes that procedure permanently and
silently uncallable. (With a custom resolvePermissions the vocabulary isn't
exhaustive, so the rule stays quiet rather than flagging correct code.)
Declared vs OBSERVED — reconciled against reality
A query's source and a mutation's targets are not documentation: the
framework routes optimistic patches and decides which subscriptions a write
invalidates from them. A wrong declaration is a live, user-visible bug that
nothing type-checks — the mutation succeeds, the write lands, and the wrong list
fails to update.
voltro dev records what each procedure ACTUALLY touched, into
app.graph.observed.json (gitignored automatically). When that file is present,
check diffs it against the declarations:
observed: 12/34 procedures exercised (35%)
mutation(orders.place) (api/orders/place.mutation.ts)
writes 'inventory' (update) but declares no target for it
subscriptions on that table are not invalidated by this mutation
fix: add { table: 'inventory', op: 'update' } to this procedure's targets
22 unexercised — no recording, so nothing is claimed about themThree things about that output are deliberate:
- Coverage comes first. Three findings at 8% coverage and three at 95% are different claims. Hiding the denominator is how a check starts overstating what it knows.
unexercisedis a third state, not a finding. A procedure no test and no dev session ever ran has no observation — which is not the same as "touches nothing". It is counted and never reported as a problem.- Observed diagnostics never fail the build. An observation is evidence
about the runs that happened, not a proof about the ones that didn't, and
check's exit code gates CI. They are always warnings.
No file → the section is skipped silently. This is not derived by parsing your handlers: a static pass over code that reaches the store through shared helpers, behind conditionals, has a long tail of both false positives and false negatives — and a check that is sometimes wrong is one people stop reading.
The HTTP surface is reachable directly too — e.g. curl -s localhost:4000/_voltro/inspect/rpc | jq (there is no /_voltro/inspect/queries endpoint; it's rpc for procedures, routes for the web page tree, subscriptions for active subscribers).
Where to read next
- Scaffolding — start + grow a project
- Dev — what happens during
voltro dev - Build & start — production paths
- Migrate — schema changes end-to-end
- Update — upgrade the framework + run codemods
- Inspect & test — debugging + harness