Volter World

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.