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:
- Validates the name (camelCase or kebab-case, no
_, no leading digits). - Picks the next free port from
--port-range. - Renders templates into
apps/<name>/api/+apps/<name>/web/, substituting{{appName}},{{projectName}},{{port}}placeholders. - Writes
apps/<name>/project.jsonrecording the project's port range + app list. - Updates
pnpm-workspace.yamlto include the new project's apps. - Seeds the agent guide for each app (see below).
After scaffolding:
cd <repo-root>
pnpm install
pnpm devThe 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.mdper 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:
- Reads the target project's
project.jsonfor the port range. - Picks the next free port from the range (rejects if the range is exhausted).
- Renders the template into
apps/<project>/<appName>/. - Updates
project.jsonto record the new app.
Example:
voltro add-app docs --template frontend-docs --to acme
voltro add-app admin --template frontend-blank --to acmelist-templates
voltro list-templatesPrints the catalogue. Templates come in three kinds — api, 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 --jsongenerate (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 artifactsDry-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 theaiBuilderflag (off by default → typedFlagDisabled).
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.jsontemplate.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/ existsTo 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 apnpm-workspace.yaml. Without one,pnpm installdoesn't link workspace packages. - Renaming the scaffolded app directory afterwards.
project.jsonrecords the path; rename invalidates discovery. Either re-scaffold with the right name, or updateproject.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 devdoes with the scaffolded app