Volter World

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

  1. Records ownership of this instance before starting services. Checks actual storage and backend failures; local Worlds do not reserve speculative memory or disk capacity.
  2. 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.
  3. Waits until every twin is actually serving, not merely bound.
  4. 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.
  5. 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_URL and 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/inject patches http, https and fetch inside the process, so a client built for api.stripe.com reaches 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.