Drop a file.
The runtime wires it in.
Every capability is a typed descriptor discovered by file convention. Name a file *.query.ts, *.mutation.ts, *.workflow.tsx — the CLI’s discovery walker finds it on next boot and wires it into the typed RPC group. No import barrels, no registration, no codegen command to remember.
// Drop a file with the right suffix — that's it.
todos.list.query.ts → useSubscription
todos.create.mutation.ts → useMutation
sendEmail.action.ts → useAction
order.fulfil.workflow.tsx → useWorkflow
nightly.cron.tsx → scheduled
stripe.webhook.tsx → signed inbound
// Each: a browser-safe descriptor + a .server executor.
// The discovery walker wires it in on next boot.The primitive set, by file suffix.
Descriptor + server executor
Every procedure is two files: a browser-safe descriptor (name, effect/Schema, metadata) and a server-only executor (*.server.ts — DB, SDKs, secrets). The browser-safe rule is transitive, so your schemas ship to the client without dragging node internals with them.
The core quartet
query (live reactive read → useSubscription), mutation (atomic transactional write → useMutation), action (one-shot external I/O → useAction), stream (server→client push → useAgentStream). Input, output and errors are all effect/Schema.
Durable & scheduled
workflow (durable multi-step), cron (scheduled), trigger (domain event → fan-out), subscribe (per-table post-commit reaction), aggregate (materialised query). The durable ones survive deploys, retries and crashes.
AI & tools
agent (persisted AI chat → useAgent), tool (model-callable function), reaction (a change fires an agent behind mandatory spend guards). Agents auto-migrate their thread + message tables, tenant-scoped.
HTTP, webhooks & email
route (public raw-HTTP endpoint), webhook (signed inbound + durable outbound), email (React-Email template), plus seed and startup hooks — the same discovery model, different suffix.
Unique RPC tags, checked at boot
Every descriptor has a globally-unique dotted name (todos.list → todosListRpc). Collisions fail boot; there is no hand-written per-endpoint SDK, and voltro dev regenerates the typed client on every change.
Convention over registration.
The discovery walker does the wiring
You never maintain a registry or an import barrel. The CLI walks the tree, finds every file with a known suffix, and wires it into the generated RPC group — types flowing to the client through Vite’s module graph. The one rule to respect: a descriptor and everything it imports must stay browser-safe, so server-only code lives in the *.server file next to it.
Primitives are the surface of the runtime.
Open the framework. See it for yourself.
Every primitive on this page is in the framework today. Clone the starter, run `voltro dev`, and have it on screen in two minutes.