Volter World

0016: Browsers are scenario state

Status: accepted. Date: 2026-10-04.

The owner's decision is that “what we want is for the state of the browser to be something we can load into”, “this means that a world could have many browsers”, and “we always have default browser states being an optional start”. A browser state is “the frontend version of the scenario”. Also: “nothing is a board feature - the board is a view of worlds”.

A World's browser is a browser profile: “that simplifies the profile actually since it gives it something known to anchor to instead of making decisions”. Its interface anchors to what a Chrome profile holds, in Playwright's portable form: { storageState, context }.

A scenario comprises the handlers in force, default data and browser states. A World holds zero or more named browsers, each holding Playwright storageState at real vendor domains and origins, including optional cookie partitionKey, Chromium ancestor metadata and IndexedDB snapshots, plus the profile subset of BrowserContextOptions: permissions, geolocation, locale, timezoneId, userAgent, viewport, deviceScaleFactor, isMobile, hasTouch, colorScheme, reducedMotion, extraHTTPHeaders and offline. Playwright owns their names and value shapes; proxy, base URL, credentials and recording are execution options, outside the profile. Missing context reads as {}; legacy top-level cookies/origins state reads as the profile's storageState. Playwright 1.61.1's storageState carries no session storage, so the profile leaves it out. The state names no person. A seed makes it through the twin's own sign-in requests and an HTTP cookie jar; hosted setup can load it directly through the same World HTTP endpoint. The kernel issues no vendor session for display. Browser state is bookkeeping like the clock: outside log, diff, changesets and push, inherited by branches and recreated by reset through the seed.

Loading is one way, like loading world.env into a process. Local consumers read the whole profile file and create a browser context with newContext({ ...profile.context, storageState: profile.storageState }), adding the World's existing proxy and CA for execution. Only the current World materializes files under .volter/browsers/, independently of its env output. Seeds read existing state through @volter/world-core/browser and create empty state only when absent, so seeds compose; context(options) sets the profile's settings without changing its storageState. The subpath installs no process hooks. Hosted pages use independent browser-and-site hostnames; a private version marker loads matching cookies and local storage on first navigation and keeps the previous load's names and paths for replacement. IndexedDB remains in native storageState for Playwright loading. The ordinary page-access session controls World access, independently of the twin's credentials. After loading, sign-in, sign-out and other activity are the twin's ordinary requests. Nothing launches a browser or synchronizes its later state back into the World. The World applies the profile's Accept-Language header to forwarded hosted requests, using locale when no explicit header is set. Permissions, time zone, location, device settings and other context emulation take effect where a browser is created from the profile (Playwright or a dedicated browser), not inside a board frame.

Real cookie-domain behavior holds at real vendor hostnames through the proxy and CA. A hosted World's relabelled sites load parent-domain cookies as one host-only copy per matching site, with no synchronization between copies. A page on one relabelled site calling another site of the same browser has no page-access session there and is refused; each site opens through its own World page pass. Names that collide with another site/browser address are refused. Sites that cannot fit the DNS label limit are skipped; a browser is refused only when no site fits, with the reason. The HTTP door bounds input to 32 browsers and one MiB per state body.

A page is listed for each browser whose address can be made, including an empty signed-out browser. If any browser address cannot be made, it also has one plain copy at its ordinary claimed-site address or vendor screen path, or with the reason it cannot open here, as when the World has none. The console displays those facts, grouping and labelling frames by name. Saved board keys without a browser alias only the first browser by name, with plain fallback frames retaining their own keys; other copies are new frames. Canonical contracts: architecture, HTTP API, and seed and reset.

View Markdown source