# 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.

```json
{
  "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:

```json
{
  "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

```bash
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.
