Worlds
A world is the set of twins deliberately selected for a workflow, running together. It need not
include every service used to develop the app. Selection does not grant access to real services;
network and credential policy still apply. This page explains what up starts, what your app
sees, and why worlds are cheap enough to make one per branch, test run, or pull request.
The config and the running world
.volter/world.json is the config: what should exist. Its saved discovery selection determines
which detected uses auto-init proposes; its ordered services declare the selected twins and local
infrastructure. Runtime environment settings provide fake app values. Keep it portable and free of live credentials;
resolved ports, process identities and run timestamps belong to the instance record.
A running world is what exists right now: ports, process ids, log files, the data each twin has
written, the live env. It lives under .volter/worlds/<branch>/ and is never committed. volter world status reads it; volter world down --purge deletes it.
Your app has two dependency manifests. package.json names the code it links; world.json
names selected twins and local infrastructure. The same dependency-management concepts apply
to the second: the registry is the twin catalog, init proposes services, up is the install, and
the running world's record is the lockfile, pinning the version of each twin that served it.
What up does
- Records ownership of this instance before starting services. Checks actual storage and backend failures; local Worlds do not reserve speculative memory or disk capacity.
- Resolves each twin's package from your
node_modules, checks it against the version the config pins, and starts it on a free port. Twins that can share a process do; the rest get their own. - Waits until every twin is actually serving, not merely bound.
- Writes the live env to
.volter/world.env: each twin's URL under the name its SDK reads (STRIPE_TWIN_URL), the fake credentials, and the preload that redirects the SDKs. - The first time a branch comes up, loads the default data.
up returns when the world is ready. Nothing runs after it that you did not ask for: there are
no startup hooks and no supervisor. What comes next is volter world run.
The lower-level operator command volter-world up <config> starts a fresh instance and does
not automatically seed it. Its caller supplies the seed after every boot. The product command
volter world up resumes a stopped branch and seeds only a fresh branch.
What your app sees
volter world run -- <command> starts the command with the live env. Two things in that env matter:
- The URLs.
STRIPE_TWIN_URLand its siblings, one per twin, in case your app or your tests want to address a twin directly. - The injector.
NODE_OPTIONS=--require @volter/world-core/injectpatcheshttp,httpsandfetchinside the process, so a client built forapi.stripe.comreaches the twin. Your code constructs its SDK exactly as in production and never learns the difference.
For a vendor whose SDK reads an endpoint from the environment instead, the world sets that variable. For a tool that is not a Node process at all, the world can run an ambient proxy with a scoped CA; see route a CLI through the world.
Sandbox mode
volter world up --sandbox makes the redirected clients refuse any destination that is not a twin, so
an app cannot accidentally reach a real vendor from inside the world. This is a cooperative
boundary at the process level. It governs Node clients and processes that honor the proxy env; it
does not govern raw sockets or binaries that ignore both. When the claim you need is that nothing
left the machine, run the world inside a network boundary that enforces it.
Why worlds are cheap
Branches share parent history and record their own changes; checkpoints make reads efficient. Identical immutable payloads written through BlobStore can share physical bytes on the same filesystem. These savings do not eliminate the cost of running services, databases, binaries, logs or new payloads. Inspect actual capacity and configure enforceable limits in the execution backend. The model explains branching; the CLI reference explains resources and prune.
Branches
A branch is a pointer into the world's history, made by volter world branch <name> from the
branch you are on: it starts exactly where that branch stands, history included, and records its
own changes from there. Local parent history is referenced; a remote parent’s history is cached.
Changes made on a branch stay on it. One branch runs at a time, because your app's env names one set of twins;
checkout stops the current branch and resumes the other with its state.
Stopping
volter world down sends every service a SIGTERM to its whole process group, waits a grace period
(five seconds by default) for it to exit, and SIGKILLs whatever remains, so a twin that
mishandles the signal is escalated. Failure to confirm exit keeps cleanup unresolved. An external service is not signalled; its own
down command runs instead. --purge deletes the branch's directory only after every process is
confirmed dead and no dependent local branch references its history. Remove dependent branches
first; ordinary down can still stop parent compute. A failed up rolls back what it started
under the same contract.
The local CLI records the lifetime of commands started by attach --via env and volter-world env. Stop those commands before
stopping their world; an active or uncertain command record prevents teardown. Resource inspection shows
their owner labels while keeping untracked consumers explicitly unknown. After successful
teardown releases ownership, pruning can remove disposable instance files. Inspection,
stopping and pruning are separate steps; a running world is never pruned to make room.
The disposable volter-world run command owns startup, its command and teardown. A separate
cleanup process watches a private connection to its caller and cleans up if that caller is killed.
Cleanup requires that process to survive. Cancellation stops
startup before rollback, and reaches the command's process group on POSIX with a five-second
grace period. Other registered commands keep the World alive until they finish.
Unconfirmed cleanup retains its lifecycle evidence and diagnostics. up and run --keep remain
persistent until explicit teardown. Successful teardown makes the retained instance files
eligible for prune; it does not delete them automatically.
Sharing a world
A running world can be exposed for a teammate or a webhook to reach: volter-world share <branch>
puts one service behind a tunnel, verifies the public URL answers before recording it, and
unshare takes it down. The world's config names which services may be shared and through which
provider; a Cloudflare quick tunnel is the default. For a world several machines use as one
account, the durable answer is a remote, which holds history and
keys rather than a running process.
The clock
The World clock can be frozen at an explicit instant and advanced for history or TTL tests. When no frozen clock is set, it uses wall time. Set the same starting instant and advances for each replay that requires identical timestamps.