Domain logic lives in packages/core, configuration in packages/config, and integration adapters at explicit boundaries. UI components do not spawn project processes directly. SQLite is the local source of truth and MySQL the hosted source of truth, generated from one canonical Prisma schema. Redis supplies hosted queues and coordination only.

#External source boundary

GEngine and game projects are external checkouts registered by absolute path. The local UserApp test host is Studio-owned infrastructure under packages/userapp-host, not a separate checkout or registered project. The built-in GEngine adapter reads the protected GEngine source and never writes into it. Project access mode is enforced before runtime, terminal, or source mutation operations. Trusted projects and plugins execute inside the worker trust boundary; neither is a hostile-code sandbox.

#Local UserApp integration

GEngine is not modeled as a normal web server. Runtime integration has three layers:

  • GEngine source inspection: read-only discovery of mod identifiers, AppContent asset

paths, commands, and contract evidence.

  • Local UserApp host: the Studio-bundled host, automatically selected from

packages/userapp-host and started through the canonical Local UserApp runtime profile on loopback port 3100. An explicit external path remains an advanced compatibility override.

  • Project development clients: registered game projects keep their own detected dev or

start process. Vite clients receive stable Studio-managed worker ports and exact AppContent mappings; browser traffic reaches them through one authenticated, same-origin runtime gateway rather than published host port ranges.

  • Project server-module overlays: a project-owned manifest may map generated server modules

onto a relative GEngine module target. The sandbox resolves canonical overlay files before the protected GEngine source without modifying either checkout. Studio fingerprints source, output, and the loaded runtime version; builds and reloads remain explicit operator actions.

  • AppContent clients: exact sessions reported by the host's /api/state endpoint and

embedded from its /app/<app-id>/<asset-path> route only after the mapped development client is ready.

Persistent runtime users are stored as typed simulated-player profiles, while saved session metadata owns user/app assignments, lifecycle, AppContent client records, and bounded chat history. Starting a session provisions those stable profiles into the transient UserApp host. Owner, Manager, Player, and Bot capabilities are mapped at the host boundary; bots do not require iframe clients.

All host operations target the canonical Local UserApp runtime profile. Active execution and queued-start deduplication are profile-scoped rather than merely project-scoped, which prevents a game Vite process from being mistaken for /api/state. The Sessions workspace is mounted in the persistent Studio shell so client-side navigation does not destroy live iframe documents.

Session startup rejects missing or stale project server output. Active sessions can either reload the rebuilt modules in the existing host process or restart their dedicated host. Source watching updates readiness state only and never performs an automatic backend build.

Process stdout/stderr is kept in a bounded execution log buffer. The session log API merges that history with live UserApp /api/debug/logs entries and derives source tabs from actual profiles and runtime app IDs.

#Contracts

Contracts remain owned by each app source. Studio discovers event evidence from the selected registered project or protected GEngine source and reports provenance. Source scanning does not create a formal payload schema. Projects may add versioned contract metadata for strict validation without coupling app knowledge to Studio.

#Modes

  • STUDIO_MODE=local: SQLite with no Docker or database server, loopback web/worker

services, hot reload, optional explicit authentication bypass, native project processes, local UserApp API, and shell access.

  • STUDIO_MODE=hosted: Keycloak required, Redis/BullMQ required, local bypass rejected,

source and terminal execution restricted to the worker container. The loopback UserApp debug integration is a local-development feature unless an equivalent explicitly trusted hosted boundary is configured.