Scaffolding

create-project, add-app, list-templates — boot new code with the framework's conventions baked in.

The scaffolder generates new projects + new apps from templates. Each template is a dogfooded reference; what you scaffold is the same shape the Voltro Cloud team uses.

create-project

voltro create-project <name> [flags]

Bootstraps a new project under apps/<name>/ with selected templates.

Flag Default Notes
--api <templateId> prompts, then api-backend API template. Use none for web-only projects. Also accepts --api=<id>.
--web <templateId> prompts, then frontend-blank Web template. Use none for api-only. Also accepts --web=<id>.
--cache=redis off Wire the Redis cache backend at scaffold time — sets cache: 'redis' in app.config.ts and injects the redis service + CACHE_* env into the active baseline's infra.
--baseline=<bare|compose|helm> prompts (or skip) Deploy baseline to scaffold (bare / compose / helm). Without it, the interactive prompt lists the available ids.
--port-range <start>-<end> 5190-5199 Port range for web apps in this project. Persisted in project.json. Also accepts : / .. separators.
--no-input false Skip prompts; suitable for CI / scripted scaffolding.

What it does:

  1. Validates the name (camelCase or kebab-case, no _, no leading digits).
  2. Picks the next free port from --port-range.
  3. Renders templates into apps/<name>/api/ + apps/<name>/web/, substituting {{appName}}, {{projectName}}, {{port}} placeholders.
  4. Writes apps/<name>/project.json recording the project's port range + app list.
  5. Updates pnpm-workspace.yaml to include the new project's apps.
  6. Seeds the agent guide for each app (see below).

After scaffolding:

cd <repo-root>
pnpm install
pnpm dev

The seeded agent guide

create-project / add-app (and voltro dev on first boot) seed a guide that teaches AI coding agents the framework's conventions. It's generated, not a monolith:

  • Root AGENTS.md + CLAUDE.md — a slim always-loaded core (mental model, the primitive rubric, file conventions, the browser/server boundary, naming, anti-patterns) plus an index listing the workspace's installed plugins and linking the deep, on-demand topic docs.
  • Nested AGENTS.md + CLAUDE.md per app area (api/, api/database/, web/) — type-specific notes an agent loads only when working there; a scaffolded app's file points at its template's doc.
  • .claude/skills/* — Claude Code skills for the common how-tos.

Existing files are never overwritten; voltro agents-md --force refreshes them. Protect a hand-maintained file from --force with a voltro:agents-md:keep HTML comment at the top.

add-app

voltro add-app <appName> --template <templateId> [--to <projectName>]

Adds another app to an existing project. Works for any kind — api, web, or serverless. A web app gets the next free port from the project's range; a serverless app has no server, so it gets no port (run it with voltro serverless).

Flag Default Notes
--template <templateId> (required) Template to scaffold. voltro list-templates for the catalogue.
--to <projectName> auto-detected Target project. Required when >1 project exists.

What it does:

  1. Reads the target project's project.json for the port range.
  2. Picks the next free port from the range (rejects if the range is exhausted).
  3. Renders the template into apps/<project>/<appName>/.
  4. Updates project.json to record the new app.

Example:

voltro add-app docs --template frontend-docs --to acme
voltro add-app admin --template frontend-blank --to acme

list-templates

voltro list-templates

Prints the catalogue. Templates come in three kindsapi, web, and serverless (a bundle of *.serverless.ts functions deployed on their own):

id                    kind        summary
--------------------  ----------  --------------------------------------------
api-backend           api         Minimal Voltro backend (schema + query + mutation).
api-backend-mail      api         + @voltro/plugin-mail + a React-Email template.
api-backend-storage   api         + @voltro/plugin-storage (public + private objects).
api-backend-mariadb   api         MariaDB binlog CDC + storage, tenant-aware.
api-durable           api         Durable + reactive: workflow, trigger, cron, subscriber, aggregate.
api-ai                api         RAG agent: vectorEmbedding + search tool + model loop.
api-data-advanced     api         Advanced schema: relations, FTS, dbEnum, encrypted, caching.
api-auth              api         Real user auth: plugin-auth sessions + cookie strategy.
api-rest              api         Public REST API: defineRestRoute + plugin-openapi (Swagger).
api-saas              api         SaaS bundle: billing + notifications + analytics + presence.
api-observability     api         Metrics + errors + tracing + a @voltro/testing unit test.
api-webhooks          api         First-class webhooks: signature-verified incoming + outgoing emit.
frontend-blank        web         Empty React + layout shell.
frontend-app          web         Fullstack reactive loop — wired to an api (useSubscription + useMutation).
frontend-landing      web         Static marketing page — zero JS on the wire.
frontend-static-blog  web         SSG blog: getStaticPaths + islands + per-post meta.
frontend-spa          web         Pure client-rendered SPA (no backend, no SSR).
frontend-ssr          web         Server-rendered pages: ssr + isr (revalidate, swr).
frontend-contact      web         Static page + a serverless email form.
frontend-docs         web         Catch-all docs site with i18n.
changelog             web         Release-notes site (MDX + RSS).
edge-functions        serverless  A library of *.serverless.ts functions (8 types).

See the App templates catalogue for what each demonstrates + a picks-for table. For programmatic use, add --json:

voltro list-templates --json

generate (AI app-builder)

voltro generate "<prompt>" turns a natural-language prompt into framework artifacts — queries, mutations, tables — constrained to what your app can actually express. It reads the committed capability manifest (app.manifest.generated.json, emitted by voltro dev) as the grammar, asks the model for an app graph + the files that realise it, and gates every candidate through the real voltro check before anything is written. A structurally-invalid proposal is re-prompted with its diagnostics (the errors-as-LLM-API loop), never written.

voltro generate "add a comments table with a list + create"          # dry-run: prints the proposal
voltro generate "add a comments table with a list + create" --write  # applies the accepted artifacts

Dry-run by default — artifacts hit disk only with --write, and only ever a proposal that passed voltro check. Generation is also capped (file count + total bytes). Run voltro dev once first so the manifest exists.

Requires a model provider (AI_PROVIDER / AI_MODEL + the provider key, same as agents). The cloud dashboard exposes the same builder for proposal review (apps.generateAppGraph), behind the aiBuilder flag (off by default → typed FlagDisabled).

Template tokens

Templates contain {{token}} placeholders that the scaffolder substitutes:

Token Example value
{{appName}} dashboard
{{capAppName}} Dashboard
{{projectName}} acme
{{capProjectName}} Acme
{{port}} 5191

Apply across both file content AND file/directory names — a template file named {{appName}}.entity.ts or a dir pages/{{appNameSnake}}/ renders to your project's names. When writing your own template, use these freely; the substitution is global.

Writing a custom template

Drop a directory into voltro-templates/apps/<your-id>/:

voltro-templates/apps/my-template/
├── template.json
├── package.json
├── app.config.ts
├── src/
│   ├── pages/
│   │   └── index.tsx
│   └── …
└── tsconfig.json

template.json declares the metadata:

{
  "id":      "my-template",
  "kind":    "web",
  "summary": "My custom template — does X.",
  "tags":    ["marketing", "minimal"]
}

kind is one of api / web / serverless. A serverless template ships a functions/ dir of *.serverless.ts files (no app.config.ts, no pages) and is added with voltro add-app. Now voltro list-templates shows it; voltro create-project --web my-template (or --api) uses it, and any kind is added with voltro add-app <name> --template my-template.

For private templates (in your own repo), set VOLTRO_TEMPLATES_PATH=/path/to/my/templates and the CLI walks there instead of the default location.

Idempotency

The scaffolder refuses to overwrite an existing directory:

voltro create-project acme   # fails if apps/acme/ exists

To force, delete the directory first. The framework intentionally doesn't have a --force flag — accidental data loss is the kind of thing that happens once + ruins your day.

Anti-patterns

  • Scaffolding into a non-Voltro repo. The scaffolder writes to apps/<project>/ + expects a pnpm-workspace.yaml. Without one, pnpm install doesn't link workspace packages.
  • Renaming the scaffolded app directory afterwards. project.json records the path; rename invalidates discovery. Either re-scaffold with the right name, or update project.json + every cross-package import by hand.
  • Editing the templates dir directly to "fix" a scaffolded app. Templates are starting points. After scaffolding, the app is yours — edit IT, not the template (unless the template itself has a bug).

See also

  • App templates — the catalogue with picks-for table
  • Dev — what voltro dev does with the scaffolded app