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_DIALECTSTOREapp.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 applying

rbac/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 them

Three 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.
  • unexercised is 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).