Config
.volter/world.json is the committed, portable intent for a World. volter world init writes
format 2; up accepts format 2 and legacy unversioned files. Resolved ports, process identities,
minted values and timestamps belong to the ignored instance record. Live credentials never
belong here.
{
"schemaVersion": 2,
"metadata": { "id": "acme-web" },
"discovery": {
"selection": {
"include": [{ "usage": "application" }],
"exclude": []
}
},
"runtime": {
"isolation": "colocated",
"environment": {
"values": { "GITHUB_TOKEN": "twin-fake-github-token" },
"strip": ["HOST_SECRET_*"]
}
},
"services": [
{
"id": "github",
"type": "twin",
"source": { "package": "@volter/twin-github", "version": "2.0.0" },
"execution": { "colocate": { "export": "createGithubTwinServer" } },
"endpoint": { "port": "auto" },
"bindings": { "injectEnv": "GITHUB_TWIN_URL" }
}
]
}
The document
| field | meaning |
|---|---|
schemaVersion |
Required integer 2. It versions this document, independently of twin protocol and package versions. |
metadata |
Required { id, description? }. id is the World name and main branch. |
discovery.selection |
Saved rules used by both initialization and coverage. |
services |
Required ordered array. Service ids are unique; order is startup order. Empty is valid. |
runtime.isolation |
process (default), colocated, or worker. |
runtime.environment.values |
Variables given to services and run. $mint creates a structurally valid throwaway value at boot. An empty value is left unset, so the app's own env files provide it; strip keeps a caller's variable out, and a service's own execution.environment.values can still set one empty. |
runtime.environment.strip |
Caller variables kept outside: exact names, prefixes ending in *, or *. Declared World values still apply. |
runtime.network.egress |
Exact canonical HTTPS origins permitted for real outbound traffic, for example ["https://github.com", "https://api.github.com"]. An empty list denies real external traffic. Twin routing takes precedence; sandbox mode still refuses untwinned traffic. Omission preserves existing routing behavior. This grants no ingress. |
serving |
{ mode?, name?, share? }. Mode is app by default. bare requires name: "<org>/<world>". |
remotes |
World name to URL or path. origin is the default; tokens are stored separately. |
scenario |
Opaque { actors?, fixtures? } metadata recorded for tests; it does not mutate twins. |
provenance.catalog |
{ sha, protocol? }: the catalog birth stamp written by init. |
Unknown structural fields fail validation. At the document or service level, keys beginning with
// are comments; nested sections do not accept comment keys. User-keyed maps and
scenario values are not treated as structural fields.
Selection
Selection contains include and exclude arrays. A selector has usage, vendor, or both:
{
"include": [
{ "usage": "application" },
{ "usage": "deployment", "vendor": "cloudflare" }
],
"exclude": [{ "usage": "dependencies" }]
}
Usages are application, dependencies, build, and deployment. Fields within one selector
must all match; selectors within a list are alternatives; exclusion wins. A vendor is selected
when at least one detected use survives. The default selects application uses only, and init
writes that default so later runs reuse it. A vendor-only selector addresses all uses of that
vendor. Registry destinations are dependency use; twin-declared tools such as Wrangler carry
their declared build or deployment use.
Selection controls automatic proposals and coverage obligations. It does not authorize network access, expose credentials, remove explicitly declared services, or excuse broken routing. An excluded finding remains visible as excluded, never covered.
Regeneration keeps saved service bindings, comments and authored infrastructure stubs. Conflicting
new endpoint claims fail before writing files. Existing seed.ts files retain their contents and
ordering; init reports the imports and calls to add for newly introduced default seeds.
Services
Every service has id and an explicit type: twin, process, or external.
| field | meaning |
|---|---|
description |
Human-readable wiring rationale; ignored by the runtime. |
source.package |
A twin package such as @volter/twin-github, resolved from the World root. |
source.version |
Package constraint: exact or ^major.minor. It also applies to a command-backed checkout twin. |
execution.process |
{ command?, args?, rootArg?, portArg? }. Package twins derive their command and may append args. |
execution.colocate |
{ module?, export, scenarioPath? }: the twin factory used by colocated or worker isolation. |
execution.lifecycle |
External service { up, status?, down, readyWhen? }. |
execution.cwd |
Working directory relative to the World root. |
execution.environment.values |
Variables for this service only. |
execution.preload |
Extra Node preloads. Relative paths resolve from the effective service cwd. |
execution.controlPlane |
World infrastructure: receives declared values but not app-side egress machinery. |
endpoint |
{ port?, portReason?, ready? } for a World-owned listener. A numeric port requires portReason; otherwise use auto. |
bindings.injectEnv |
Export the service URL under one variable, such as GITHUB_TWIN_URL. |
bindings.injectEnvTemplates |
More variables computed from ${url}, ${httpUrl}, ${host}, or ${port}. |
bindings.cliRedirect |
Variables honored by the real vendor CLI, computed from the same templates. |
bindings.discover |
External lifecycle output mappings: { as, source?, jsonPath? } or { as, source?, pattern? }. |
root |
A twin's real-system root, described below. |
signIn |
{ as }: the account a twin's own screens (its mirror) open signed in as, named by its handle, username or email ({ "as": "volter" }). The twin finds that account in the World and mints its screens a sign-in credential through the twin's own HTTP API, scoped to what the screens do, once per account every twelve hours while the World is served; nothing secret is written here. Only a person who may write the World is signed in, at the World's own origin (volter world view); a read-only link, and a World without an origin of its own, show the vendor's own sign-in. Signing out stays signed out in that tab. A twin without support shows its own sign-in. |
A twin has exactly one of source.package or execution.process.command; it may additionally
declare execution.colocate. A process requires a command and cannot declare twin source,
colocation, external lifecycle, or root. An external service requires lifecycle up and down,
uses bindings.discover for outputs, and cannot declare source, process, colocation, endpoint,
preload, or root. Invalid combinations fail before anything starts.
A twin root
root identifies the real vendor account behind a twin on a shared World. The credential is
sealed separately under .volter/credentials/.
| field | meaning |
|---|---|
url |
The vendor API or a served World's twin URL. |
scope |
The one resource the account represents, when the twin requires it. |
deploy |
auto, gated, or hold; defaults to gated. |
refresh |
{ every?, webhook? }: scheduled or webhook refresh posture. |
Sharing
serving.share retains the existing share shape: provider is cloudflare-quick or command;
a custom provider supplies command and optional args; ephemeral records URL lifetime; and
services is an array of { id, verifyPath? } targets declared in this World.
Migration
volter-world migrate-config .volter/world.json
Migration accepts only unversioned format 1. It refuses unknown legacy fields, creates the
byte-for-byte backup world.json.v1.bak, validates a temporary format-2 file, then replaces the
manifest atomically. It preserves service order, path-resolution behavior, roots, remotes,
scenario data, comments and provenance. The old all-signals coverage behavior is materialized
as all four included usages; changing to the application-only default is a separate edit.
Deprecated resources metadata is retained only in the backup and reported as dropped.
Ordinary reads never migrate a file, and running instance records are never rewritten.
The World directory
Beside world.json, committed files include handlers/<vendor>.json, seeds/story.ts, and
checks/*.ts. Running state is ignored: worlds/<branch>/, world.env, token, credentials/,
and current.
The instance record stores actual service URLs, pids, logs, data directories, resolved twin versions, the live environment, and the selection snapshot used at boot. Coverage of a running World uses that snapshot; editing the manifest does not retroactively change it.