Volter World

CLI

volter is the user's command: a noun, then a verb. volter world … acts on the world of the current directory; volter twin <vendor> … acts on one twin, in a world or on its own; volter remote … names the worlds this one pushes to and fetches from. volter-world is the operator's command and names worlds and configs explicitly. Both come from @volter/world (volter) and @volter/world-runtime (volter-world).

The volter section below is checked against the command's own help text by scripts/docs-reference.test.ts: every verb the command knows appears here.

volter world

Every verb finds the world by walking up from the current directory to the nearest .volter/world.json, and acts on the checked-out branch.

Global flags:

flag meaning
--world <dir> the world root, when the cwd is not inside it
--branch <name> act on that branch instead of the checked-out one
--json machine-readable output, where a verb offers it

Lifecycle

verb does
volter world init [--install] [--name <world>] [--allow-unknown] [--force] detect the app's vendors from its manifests and env names (in an app with no twins installed yet, name the twins for them and install them with the app's package manager: asked at a terminal, at once with --install); write .volter/world.json, the handlers, the seeds and the ignore file. Byte-deterministic for a repo and a catalog
volter world init --bare <org>/<world> a world with no app: a shared world for a team, or a world standing in for a vendor
volter world up [--sandbox] [--no-seed] start the twins on this branch. A branch that has run before resumes with its state; a fresh branch loads the default data
volter world run [--verbose] -- <command...> run the command inside the world: the twins' URLs, the fake credentials and the SDK redirect in its env. Exits with the command's code
volter world activate print the script that activates the world in the current shell: eval "$(volter world activate)"
volter world shell a subshell with the world active
volter world serve [--port <p>] [--host <h>] [--console-port <c>] serve this world on a URL, under /<org>/<world>/<vendor>/…, for apps and scripts; prints the token that opens it and writes it to .volter/token. On loopback (the default) it is the same local front as view, without opening the browser: the console it prints opens with no token. A non-loopback --host, or --console-port, serves it for others, and its console (its own origin, port p+1 by default) asks for the token
volter world view [--port <p>] [--host <h>] [--no-open] [--no-origins] serve this world to step into: its HTTP API, each twin's mirror, the branches made of it and, with @volter/world-console installed, the console, opened in the browser at the world's own origin (http://<world>--<org>.localhost:<port>/-/console/<org>/<world>, where its browser session lives; --no-origins serves every world on one origin). On loopback the browser never needs a token: the World's own page opens its session, after a restart or a rotated token too (a non-loopback --host is a World served for others, and its console asks for one; with --no-origins the browser is opened with the token in the URL's fragment). Anything that can reach the port can open that session, so never forward or expose it; see the architecture's "A local World asks for no token". Branches it makes live under .volter/branches/ until their time runs out
volter world console [<https://host/org/world>] [--port <p>] the console on this machine for a World served elsewhere (a hosted World), on two local origins as serve has: the console (port p), its endpoints forwarded to the host, and the Worlds (port p+1), forwarding a twin's mirror and the session endpoint; defaults to this world's origin, and needs no world when a URL is given; open the World with its token; needs @volter/world-console
volter world status [--json] the world, the branch, whether it runs, the origin, the base, unpushed changes, each twin's URL and root
volter world down [--purge] stop the twins; the branch's state stays. --purge deletes it if no dependent local branch references it

State

verb does
volter world log [--receipts] [--json] every write the app made, across the twins, oldest first; --receipts adds each change's receipt
volter world diff [--json] the changes since the base, grouped by twin
volter world seed load the default data
volter world reset back to the default data: forget the branch's changes, boot, seed

Branches

verb does
volter world branch list branches; * marks the checked-out one
volter world branch <name> [--at <instant|twin@n,…|twin@view:n,…>] a new branch from here — or from any point in the history: an instant, or a position within the current or named view per twin — checked out; the current branch stops. Nothing is copied
volter world checkout <name> switch to a branch: it resumes with its state, the current one stops
volter world replay <changeset> --into <branch> feed a changeset's changes into another branch's twins, in order, with the same ids; replaying twice is a no-op

Time

verb does
volter world clock show the world's clock: the frozen instant every twin stamps from, or the wall clock when none is set
volter world clock set <iso> set it; every twin stamps from it until it moves, and so does the World's application, whose time then stands still (a World serving an application moves time with shift)
volter world clock advance <N s|m|h|d> move a set clock forward: 30d, 12h
volter world clock shift <N s|m|h|d> move a World forward while its time keeps running (a World serving an application, which follows the World's time)
volter world clock clear return the World to the machine's time

Remotes and changesets

verb does
volter world clone <url> --token <token> record the world at <url> as origin, remember the token, and bring its whole history in
volter world fetch [<remote>] [--token <token>] cache the remote's current snapshot without changing reads (clone before branching to inherit its origin); pull integrates origin history, and named changeset rebase can use the fetched snapshot
volter world origin [--json] the remote this world clones from and pushes to; default data when it has none
volter world changeset [<name>] -m "<message>" cut the unpushed changes into a changeset, named from the message unless given
volter world push [<remote>] [<changeset>] [--token <token>] [--force] send changesets to the remote, oldest first, and move the base; refused on drift
volter world pull [--token <token>] fetch and integrate the origin snapshot, preserving inherited local layers and naming conflicts
volter world rebase [<changeset>] without a name, move onto the local base's current position; with a changeset, integrate the fetched origin snapshot and re-check that changeset. Both name conflicts by record and field

Deploying

On a world whose twins have a root. The receipts land on the changes.

verb does
volter world verify <changeset> run the world's checks over the changeset and record the result
volter world approve <changeset> --as <principal> [--note <text>] sign the changeset's current hash
volter world deploy [<changeset>] perform landed changes against each twin's root, by its policy: every deployable changeset, or the named one

Tokens come from ~/.config/volter/credentials.json (or $XDG_CONFIG_HOME/volter/), written by remote add and clone --token; --token overrides the store for one call.

volter remote

The worlds this world pushes to and fetches from, by name, like git's remotes. A remote is a URL a served world printed, or a path to another world's directory on this machine.

verb does
volter remote add <name> <url|path> [--token <token>] name a remote; origin is the one fetch and push use by default. A path is a world on this machine, reached with no server and no token
volter remote remove <name> forget it
volter remote list every remote, with its URL and whether a token is stored
volter remote add <name> <org>/<world> [--create] a world the hosted platform holds for your org, its address resolved through the platform you signed in to. One that is not there yet is made there with this world's twins: asked at a terminal, or at once with --create (without either, the command stops and names --create). <world> alone names it in your only org

volter login

command does
volter login <platform url> [--no-open] sign the command into the hosted platform as you, through the browser: it shows a code, opens the platform's approval page (where you sign in with your Volter account, making one if you are new), and on approval keeps a personal token named for this machine, for 30 days
volter login <platform url> --token <personal token> the same without a browser, with a token made on the platform under Account (CI)
volter whoami the platform the command is signed into, as whom, and the orgs it reaches
volter logout revoke the command's token at the platform and forget it here

volter open

command does
volter open [<org>/<world>] [--no-open] a World's dashboard: a hosted one (named, or this world's origin on the platform you signed in to) through the platform, which signs you in; otherwise this world's own, as volter world view serves it. The address is printed; --no-open only prints it

volter completion

command does
volter completion bash|zsh|fish|powershell print a script that completes volter's nouns and verbs: eval "$(volter completion bash)" in ~/.bashrc (or zsh), volter completion fish | source, volter completion powershell | Out-String | Invoke-Expression in your profile

Installing and updating

npm install -g @volter/world (or bun add -g), or the site's install script, which checks for Node 22.3 or later (or Bun) and runs the same install: curl -fsSL https://world.volter.ai/install.sh | sh, or irm https://world.volter.ai/install.ps1 | iex in PowerShell. Once a day at most, the command asks the npm registry for the latest version while it works and says in one line on stderr when a newer one is out. It never asks in CI, for --json, or away from a terminal, and VOLTER_NO_UPDATE_NOTIFIER=1 turns it off.

Agents

command does
volter agents install [--claude] [--cursor] [--vscode] [--codex] [--yes] put the volter-world skill and the MCP server into the coding agents found here (or those named): Claude Code (claude mcp add --scope user, else ~/.claude.json; the skill in ~/.claude/skills/volter-world), Cursor (~/.cursor/mcp.json), VS Code (.vscode/mcp.json in this project), Codex (~/.codex/config.toml, the skill's instructions in ~/.codex/AGENTS.md); only its own entries are written, and running it again changes nothing; without --yes it asks first, and at no terminal it only says what it would do
volter mcp the MCP server an agent starts, over stdio: tools world_status, world_init, world_up, world_run, world_down, world_view, world_log, world_diff, world_branch, world_checkout, world_reset, platform_login, platform_whoami, remote_link, world_changeset, world_push (each takes the app's folder as dir), and the prompt get-started; a tool that acts runs volter itself, so it answers and refuses as the command does

volter world init ends by offering volter agents install at a terminal. Use Volter World with a coding agent walks through it.

volter twin

One twin: in the world of the current directory, or on its own.

verb does
volter twin <vendor> the twin in this world: its URL, its root and deploy policy, whether a credential is sealed
volter twin <vendor> root <url> [--deploy auto|gated|hold] [--scope <path>] [--refresh <every>] [--at-most <span>] set the twin's root to the vendor at <url> and its deploy policy; --scope names the one resource the account is (repos/acme/web); --none clears it --scope names the one resource the account is (github: repos/<owner>/<repo>; slack: the channel ids a refresh reads, C123,C456 — a workspace's rate budget is the reason)
volter twin <vendor> credential read a credential from stdin and seal it beside the world; never readable back
volter twin <vendor> refresh [--force] observe the root now — the twin observes, the kernel folds what changed; throttled to the root's atMost (else the twin's) unless --force
volter twin <vendor> serve [--port <p>] [--read-only] serve the twin at http://127.0.0.1:<p> without a world; --read-only refuses every write
volter twin <vendor> mirror [--port <p>] the twin's UI mirror: its live state in a vendor-styled dashboard
volter twin <vendor> conformance check the twin against the vendor's spec contract

volter-world

The operator's surface. Every verb takes the world's name and, where a config is needed, its path. --root <dir> is the world root (default: the cwd). The verbs the user surface wraps are listed first, then the ones only an operator needs. Write the env file as --env-file=<path>: Node reads a separate --env-file <path> pair from any program's arguments and exits when that file does not exist yet, which it does not before the first up writes it.

The same verbs, addressed explicitly

volter-world init <name> --repo <path> [--out <dir>] [--force] [--allow-unknown] [--acknowledge vendor=reason]... [--json]
volter-world up <config> --env-file=<path> [--name <name>] [--mode local|share|sealed] [--isolation process|colocated|worker] [--keep-state]
volter-world down <name> [--grace-ms <ms>] [--purge]
volter-world status <name> [--json]
volter-world env <name> -- <command...>
volter-world log <name> [service...] [--no-follow] [--json] [--requests]
volter-world diff <name> [--json]
volter-world seed <name> [--entry <file>] [--cwd <dir>]
volter-world reset <name> [--entry <file>] [--cwd <dir>]
volter-world branch <name> <new> [--env-file=<path>]
volter-world checkout <name>
volter-world fetch <name> [--remote <name>] --key <token>
volter-world origin <name>
volter-world activate <name>
volter-world shell <name>
volter-world serve <name> [--port <p>]
volter-world changeset create <name> <changeset> [--verifier "<service> <type>:<id> <field> <op> [value]"]...
volter-world changeset push <changeset> --key <token> [--to <remote>] [--force]

Review and deploy

volter-world changeset show|list|status <changeset>
volter-world changeset verify <changeset>
volter-world changeset approve <changeset> --as <principal> [--note <text>]
volter-world changeset rebase <changeset>
volter-world changeset replay <changeset> --into <world>
volter-world deploy <name> [<changeset>]
volter-world twin <name> <vendor> root <url> [--deploy auto|gated|hold] | credential | refresh

The world itself

volter-world clock <name> show | set <iso> | advance <N s|m|h|d> | shift <N s|m|h|d> | clear   the world's clock (frozen, or running after shift; its application follows it)
volter-world urls <name> [--json]        every service's URL
volter-world url <name> [service]        one service's URL, bare
volter-world app-url <name> [--set <url> | --detect <pid|port>] [--host <name>...]   the app's URL; --host: a hostname it answers as in production, routed to it inside the World (`*.example.com`: every name below, as a DNS wildcard)
volter-world doctor <name> [--verify-public]
volter-world doctor-prereqs --require local-execution
volter-world run <config> --env-file=<path> [--owner <label>] [--mode ...] [--keep] [--verbose] -- <command...>   a disposable world around one command
volter-world resources [--root <repo>] [--json]   reservations, owner labels and registered attachments
volter-world prune [<name>] [--root <repo>] [--apply] [--json]   preview or delete stopped instance files
volter-world list [--json]
volter-world outdated <name> | audit <name>   each twin's pinned, mounted and catalog version; the catalog's verdicts
volter-world fake-env <NAME...>          structurally valid fake values for env names
volter-world inspect-project [path]      read-only discovery of an app's vendors
volter-world migrate-config <config>     backed-up, atomic format-1 to format-2 migration
volter-world covers <name> --repo <path> check detected vendors and connections against a config or instance

Reaching the world from elsewhere

volter-world attach [<world-ref>] [--owner <label>] [--via env|direct] [--verbose] [-- <command...>]
volter-world manifest <name>
volter-world route <name> add|rm|ls [host]
volter-world reflect <name> --target-ip <ip> [--port <p>] [--resolver-port <p>]
volter-world share <name> [--service app] [--verify /path | --no-verify] [--provider cloudflare-quick|command]
volter-world unshare <name> [--service app]

attach <url> [--token <t>] -- <command> runs the command against a world served elsewhere: the world's twin URLs, its endpoint variables and its key in the environment, the injector preloaded, and a loopback listener for each of the world's streams (its TCP twins: smtp, PlanetScale's MySQL wire) with the variables its client reads pointed there, so a command in any language connects to 127.0.0.1 (HTTP API, the attach manifest).

volter world run, volter-world run, attach --via env and env suppress the injector's informational routing banner by default, including in child processes. Pass --verbose before -- to show it. An admitted VOLTER_TWIN_INJECT_QUIET environment setting is preserved unless --verbose overrides it (1 hides the banner, 0 shows it). Routing, warnings and errors are unchanged.

A config can use runtime.environment.strip: ["*"] to discard the caller's inherited environment, including caller Node preloads. Declare needed variables such as PATH and HOME in runtime.environment.values. World still supplies its vendor URLs, credentials and injection to services and commands run within it. Named filters and prefix filters such as HERMES_* remain available. This filters environment inheritance; it does not isolate files or OS credentials.

covers checks detected SDKs, vendor endpoints and native database connections. For example, a PlanetScale HTTP twin does not cover Prisma's separate MySQL connection. Database URL schemes identify native connections; Prisma schema evidence and unresolved clients also appear. Native coverage requires the app's endpoint variable to be wired to a declared service. External endpoint discovery stays unknown until up records it. Unknowns fail by default; --allow-unknown leaves them visible and explicitly accepts them. Configuration-driven or dynamically selected clients can remain unknown. This static check does not prove application behavior or that two interfaces share state; verify those with an app scenario.

init classifies repository evidence by usage and saves discovery.selection; covers applies the same saved selection from the config or running instance. Excluded evidence stays visible but does not fail coverage. Declared twins are checked for routing even when discovery does not find them.

volter-world up --keep-state boots over the state the World's directory already holds instead of starting it empty: the way a World carried elsewhere with its data (a browser tab's image of it) comes up.

volter-world up, run, env and local attach --via env accept --owner <label> to identify the task using the world. Commands started by env or local attach --via env inherit the world's label unless overridden; each command has its own record. resources shows registered commands and identifies untracked consumers as unknown. The label describes ownership; it does not grant access. Finish active commands before down; uncertain command records also prevent teardown. volter-world consumers retire <world> [--consumer <id>] resolves an uncertain record whose runner, command and process group are all gone on this host (a runner killed before it recorded completion), and keeps any other with its reason; it never runs on its own. prune only deletes files after a successful teardown, preserving source configs and seeds. resources reports actual filesystem free bytes and lifecycle ownership. Its JSON schema version 2 distinguishes observed capacity from declarations; it exposes no synthetic reserved or admission-available totals. Legacy records are listed for migration, never subtracted from free space or removed by inspection. Unreadable unrelated records do not block startup. An unfinished lifecycle blocks replacement/pruning of that instance until verified teardown. Runtime v3 accepts config resources with a deprecation warning; it does not turn declarations into OS limits. Hosted Worlds with legacy declarations require reviewed migration first. Stop a legacy installation with its pinned old runtime before upgrading all its entrypoints; resume retained state with volter world up, not a fresh operator up/run. Keep old ownership records until verified cleanup. Mixed-version ownership of one instance is unsupported. run cleans up when its caller is killed, provided its cleanup process survives; other registered commands remain protected. up and run --keep require explicit teardown. Prune removes stopped instance data separately, so command logs remain available after a failed run. list, status and resources show instance creation and last observed command use, including its source and partial coverage. Command heartbeats indicate a command's presence, not user interaction or vendor traffic; its latest observation survives command completion. Foreground runs contribute their start and finish times. Inspection does not refresh use, and a new instance starts with unknown use. Legacy, activated-shell and remote use remain unknown; an old timestamp does not prove that a world is safe to stop.

The hosting product

Many worlds on one host, and the platform in front of it (architecture, "The hosted product"; the guides host worlds for a team and self-host the platform).

volter-host serve

@volter/world-host serves worlds under one URL by <org>/<world>, and provisions, rotates and removes them through its admin endpoints (HTTP API, "The hosting product"). It prints the admin token and, when @volter/world-console is installed beside it, the dashboard's URL. A user never needs it: a served world is the same thing for one team.

Flag Meaning
--dir <worlds> required: the directory of bare worlds, one per <org>/<world> (volter world init --bare)
--host <h> the address to bind; 127.0.0.1 by default
--port <p> the port to bind; one the system picks by default
--url <origin> the origin the host is reached at when that differs from its bind address (a container behind a port map, a proxy): every world's base URL and the printed addresses use it
--console-port <c> the dashboard's own port (it is served on a listener of its own, so no twin's script shares its origin); the host's port + 1 by default
--console-url <origin> the origin the dashboard is reached at, as --url is for the host; on the same site as --url, or its links into the twins' screens are refused
--no-origins no origin of its own per world: every world's pages on the host's origin (on a loopback host each world is <world>--<org>.localhost by default)
--trust <platform origin> repeatable: a platform whose passes open these worlds for a person, over https or loopback http; none, and only tokens do
--world-origins <domain> each world at an origin of its own under the domain (<world>--<org>.<domain>, a wildcard name and certificate pointing at the host), which a browser session and a pass need on a host reached at --url

volter-platform serve

@volter/world-platform is where people and orgs are: sign-in through one access provider, orgs, members, invitations, tokens, the hosts it makes Worlds on, and opening a World for a person with a pass. Its endpoints are the platform API. It prints its address, the provider, whether it bills, and the operator token (<dir>/admin).

Flag Meaning
--dir <state> required: the platform's state — platform.db (SQLite: sessions, tokens, its directory for oidc and github, the enrolled hosts, the audit log), and the key it signs passes with
--host <h> the address to bind; 127.0.0.1 by default
--port <p> the port to bind; one the system picks by default
--url <origin> the origin people reach it at (behind a proxy); the provider's callback is <origin>/-/sign-in/callback. The bind address by default
--provider volter|oidc|github the access provider (below); oidc when OIDC_ISSUER is set, else volter
--site <origin> the product's site: its docs and legal pages are linked, and making an org asks for its terms. Absent, no terms are asked for
--mail-from <sender> the sender of the platform's mail (invitations it keeps, a member added, a World deleted, billing notices); a sender the Resend account behind RESEND_API_KEY has verified. Volter World <noreply@volter.world> by default
--support-to <address> where the Help form's requests are mailed; without it the platform shows no Help form
--client-ip-header <name> the header the deploy's own proxy sets to the client's address: cf-connecting-ip on Cloudflare, or x-forwarded-for behind a proxy that appends to it (its last entry is read). The rate limit keys a request without a token on it; unset, no request names its own address and those requests share one limit, and a platform on a public address says so when it starts
--backup-bucket <bucket> archive the state to this S3 bucket nightly, the database as a consistent snapshot (credentials from AWS_*); a restore is put in place at the next start
--backup-at <HH:MM> the backup's time of day, UTC; 00:00 by default
--tick-every <seconds> the billing tick's period, where the platform bills; 3600 by default, 0 never
--deliver-every <seconds> how often due webhook deliveries are attempted; 5 by default

Its environment:

Names For
VOLTER_ISSUER, VOLTER_CLIENT_ID, VOLTER_CLIENT_SECRET --provider volter: Volter Identity (https://id.volter.ai by default) and the client registered for this platform there
OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_NAME, OIDC_TRUST_EMAIL_DOMAINS --provider oidc: the issuer, its client, the sign-in button's name, and the domains (comma-separated) in which an address the issuer does not mark verified still counts, for an issuer that sends no email_verified (Microsoft Entra)
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_URL, GITHUB_API_URL --provider github: the OAuth app, and for GitHub Enterprise Server its web address (https) and API (<GITHUB_URL>/api/v3 by default)
RESEND_API_KEY send the platform's mail through Resend; without it every mail is written to the log instead
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, AWS_ENDPOINT_URL --backup-bucket's S3 (AWS_ENDPOINT_URL for an S3-compatible store)
POLAR_ACCESS_TOKEN, POLAR_SERVER Volter's cloud only: bill through Polar with Volter's biller (@volter/world-billing, which is not published). Set where that biller is not installed, the platform refuses to start

volter-world --help prints every flag.

Retiring names

volter remote serve is the hosting product's verb under its old name; it answers for one release beside volter-host.