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
devor
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/stateendpoint 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.