The full frame server: one binary, one config, one start command.
frame-host --config frame.toml boots the entire stack in a single process:
- the embedded liminal component ([
embedded]) — liminal's TCP wire listener, browser WebSocket listener, and health endpoint, running in-process on liminal's own threads (no child process, no side-by-side server); the host owns its lifecycle but not its bytes; - the frame-core host authority ([
runtime]) — the host-owned capability table reached only through [frame_core::capability::HostCapabilityFacade], the component registry, and supervised lifecycle, around the class-(b) client-native graph view under theframe:graph-view@v1contract (D10); - the console HTTP server ([
server]) — the static browser bundle,GET /frame/config.json, and the same-origin/frame/bus/*health proxy routes ([bus_proxy]).
Per ruling D3 the browser is a bus PARTICIPANT: the served page connects
to the embedded bus directly over the WebSocket transport. This host
never proxies or terminates that feed; /frame/config.json is DERIVED at
runtime from the embedded component's real bound WebSocket address
(served as busEndpoint), so the page's endpoint and the server's
address can never drift.
Console-first (D9): every component lifecycle transition and capability denial is logged to stdout as it happens.
The embedding seam
frame-host is also a library: an embedding application supplies an
[AppSpec] (its component installs, stated runtime policy, readiness
proof, and fact announcements) and [run_application] boots the whole
stack around it — [app] is this binary's own composition riding the
same seam. The [announcer] publishes the host authority's real events
(lifecycle transitions, capability denials, application facts) on
[frame].channel over its OWN native participant connection: the page
server still carries zero feed bytes (D3) — the host is a node on the
bus, never a proxy in front of it.