# Dreamverse OSS Design ## Overview Dreamverse should ship as a local-first open source application. - The browser talks only to a local Dreamverse control plane on the user's machine. - Provider credentials stay local to that machine. - Dreamverse may provision compute on the user's behalf, but Dreamverse does not host that control path as a service. This keeps the UX simple without turning Dreamverse into a credential-holding hosted platform. ## Goals - Support three compute modes behind one product surface: - local GPU - managed remote GPU via Runpod - managed remote GPU via Modal - Keep prompt rewrite, websocket session state, and generation behavior consistent across providers. - Keep provider API keys out of browser state and out of any hosted service. - Make the existing runtime reusable as the common serving contract. - Minimize provider-specific code and isolate it behind a narrow interface. ## Non-goals - Do not make the frontend call provider APIs directly. - Do not unify providers at the level of SSH, VM, serverless, or pod semantics. - Do not move prompt rewrite logic into the frontend or controller. - Do not require remote compute for the basic product path. ## Current State Today the repo contains two major pieces: - `apps/dreamverse/web/`: Next.js frontend - `apps/dreamverse/dreamverse/`: FastAPI runtime that owns websocket state, prompt rewrite, prompt safety, and GPU-backed generation The current runtime already exposes useful health and streaming surfaces such as `/healthz`, `/readyz`, `/status`, and `/ws`. ## Target Architecture The target open source structure should be: ```text Dreamverse/ ├── apps/dreamverse/ │ ├── web/ # browser UI │ ├── dreamverse/ # current FastAPI websocket/generation runtime │ ├── controller/ # local control plane and provider lifecycle │ ├── providers/ # provider adapters │ ├── tests/ │ │ ├── contract/ │ │ ├── controller/ │ │ └── smoke/ │ └── design.md └── ... ``` Near-term note: - `apps/dreamverse/dreamverse/` is the current runtime implementation. - We can keep the code there initially and rename it to `runtime/` only after the controller lands. ## Trust Model Dreamverse is local-only for control and secrets. - The user launches Dreamverse on their own machine. - Provider API keys are entered into the local app or local CLI. - The controller uses those credentials to provision or connect to compute. - The browser never talks to Modal or Runpod directly. - Dreamverse-hosted infrastructure is not involved. This is the key reason the provider-based path is acceptable for OSS. ## Responsibility Split ### `apps/dreamverse/web` The frontend should own: - UI state, drafts, and local interaction state - websocket event reduction into client stores - selection of compute mode and display of cost/health/status - local forms for provider configuration - sending prompt requests and rewrite requests to the local controller The frontend should not own: - provider credentials after submission - provider API calls - runtime lifecycle - authoritative prompt window after rewrite - prompt safety or generation policy ### `controller` The local controller should own: - provider credential loading and local-only storage - compute mode selection - provisioning, reuse, shutdown, and health monitoring of runtimes - reverse proxying HTTP and websocket traffic from the frontend to the active runtime - user-visible status such as provisioning, ready, failed, and idle shutdown - local persistence for user settings that must survive ephemeral runtimes The controller should not own: - prompt rewrite logic - seed prompt memory semantics - generation queue behavior - provider-specific UI state ### `runtime` The runtime should remain the authoritative owner of: - `/ws` session state - prompt rewrite execution - prompt safety - seed prompt memory and prompt-window state used for generation - generation orchestration and GPU worker lifecycle - websocket event schemas This preserves the current model and avoids splitting state across layers. ## Runtime Contract Provider abstraction should happen around a stable Dreamverse runtime contract, not around infrastructure details. Minimum runtime surface: - `GET /healthz` - `GET /readyz` - `GET /status` - `GET/POST /prompt-system-config` if devtools persists config through the runtime - curated preset routes if those remain runtime-backed - `WS /ws` Important rule: - The controller only needs to know how to reach a healthy runtime. - The runtime remains provider-agnostic. ## Provider Abstraction Use a narrow provider interface: ```python class ComputeProvider(Protocol): async def ensure_runtime(self, spec: RuntimeSpec) -> RuntimeHandle: ... async def wait_until_ready(self, handle: RuntimeHandle) -> None: ... async def stop_runtime(self, handle: RuntimeHandle) -> None: ... ``` `RuntimeHandle` should include: - `provider` - `runtime_id` - `base_url` - `ws_url` - runtime auth headers or tokens if needed - lifecycle metadata - cost or hardware metadata for UI display The controller should work only with `RuntimeHandle`, never with raw SSH hosts or provider-specific payloads after resolution. ## Provider Notes ### Local Local mode should be the reference implementation. - Start the runtime as a local subprocess or connect to an already-running local runtime URL. - Reuse the same runtime contract as remote providers. - Make this the first supported path and the main smoke-test target. ### Runpod Runpod should be treated as pod lifecycle plus runtime reachability. - Prefer prepared images or templates that auto-start the Dreamverse runtime. - Prefer exposed HTTP/TCP ports for steady-state traffic. - Use SSH only for bootstrap fallback, diagnostics, or repair. - Avoid a design where the controller shells into the pod for every action. ### Modal Modal should be treated as deployment-based runtime hosting. - Wrap the Dreamverse runtime in a thin Modal entrypoint if needed. - Reuse the same runtime behavior behind that wrapper. - Do not model Modal as a machine that Dreamverse logs into. - Do not force the websocket runtime into a per-request serverless handler shape. ## Config and Persistence Remote compute may be ephemeral, so mutable user configuration should not live only inside remote runtimes. Keep durable state local to the user's machine unless there is a strong reason otherwise: - provider selection - provider credentials or credential references - default hardware preferences - editable prompt presets - prompt system prompt overrides - idle shutdown policy Runtime-local state should be treated as disposable unless explicitly synced. ## Prompt Rewrite Ownership Prompt rewrite remains runtime-owned even after the controller is added. Frontend responsibilities: - collect the rewrite instruction - build the prompt-window snapshot - display rewrite activity and results Runtime responsibilities: - validate and normalize the prompt window - choose the rewrite system prompt and model settings - execute rewrite - apply safety filtering - replace authoritative seed prompt memory - emit the canonical completion events Controller responsibilities: - proxy the request and response - surface runtime availability and failure state This boundary should not move. ## Recommended Rollout 1. Finish the path reorg so docs and code agree on `apps/dreamverse/web`. 2. Introduce `controller/` as a local-only API/proxy process. 3. Keep `apps/dreamverse/dreamverse/` as the runtime and adapt it behind the controller. 4. Add `local` provider first. 5. Add "bring your own runtime URL" as an escape hatch. 6. Add automated Runpod provisioning. 7. Add Modal deployment support. 8. Rename `apps/dreamverse/dreamverse/` to `runtime/` once the split is stable. ## Implementation Plan The implementation should start with the smallest milestone that gives users a working local GPU setup without forcing the controller/provider architecture into the first patch series. ### Milestone 0: Make local GPU the official baseline Goal: - A user with a working `fastvideo` install can run the Dreamverse backend on a local GPU and connect to it from `apps/dreamverse/web`. Non-goals for this milestone: - no controller process yet - no provider abstraction yet - no Runpod or Modal support yet - no secret-management UI yet Reasoning: - `apps/dreamverse/dreamverse/` already is the real local GPU runtime. - `apps/dreamverse/web` already knows how to talk to a backend over `/ws` and REST rewrites. - The shortest path is to make the existing local path explicit, reliable, and tested before adding another layer. ### Milestone 0 work items #### 0.1 Fix repo path assumptions after the frontend move Current issue: - Some paths still assume `prod-ui/`, but the frontend now lives at `apps/dreamverse/web/`. Required changes: - update prompt/preset path resolution in `apps/dreamverse/dreamverse/config.py` - update docs that still mention `prod-ui` - audit any frontend build settings that assume the old repo root This is prerequisite cleanup. Local GPU mode should not depend on stale monorepo paths. #### 0.2 Make local runtime startup the primary supported entrypoint Required outcome: - one documented backend command - one documented frontend command - one clear env contract for local development Expected shape: ```bash uv pip install -e ".[dreamverse]" dreamverse-server --host 0.0.0.0 --port 8009 cd apps/dreamverse/web npm ci BACKEND_HOST=localhost BACKEND_PORT=8009 npm run dev ``` Optional but useful: - add a small root helper script or Make target for local startup - add a `dreamverse-doctor` or lightweight startup check later #### 0.3 Define the minimum local runtime contract For Milestone 0, the frontend should rely only on the current runtime surface: - `/ws` - `/status` - `/healthz` - `/readyz` - existing prompt/devtools routes Do not add a second local API layer yet unless the current runtime surface is proven insufficient. #### 0.4 Make failure states explicit in the UI Local GPU mode fails in a few predictable ways: - backend not reachable - backend reachable but not ready - `fastvideo` or model runtime missing - no compatible GPU available Minimum implementation: - show a clear connection error when `/ws` or `/status` fails - surface readiness failures in a human-readable way - avoid silent retry loops that hide backend startup failures This is a small UI pass, not a controller project. #### 0.5 Add a minimal local smoke test path At this milestone, local GPU support is "done" only if there is a repeatable test path for the local runtime contract. Minimum test additions: - backend tests for `/healthz`, `/readyz`, and `/status` - a frontend integration test that assumes a reachable backend URL and verifies connection lifecycle behavior - one local smoke script that starts the backend and verifies readiness before the frontend is launched ### Milestone 1: Introduce a thin local controller Goal: - Preserve the same local GPU behavior, but place a stable local control-plane API in front of the runtime. This should happen only after Milestone 0 is stable. Scope: - add `controller/` - proxy `/ws` and the needed REST routes to `apps/dreamverse/dreamverse/` - expose controller-owned status for "backend starting", "runtime ready", and "runtime failed" - optionally spawn the local runtime as a subprocess Non-goal: - do not add remote provider logic yet Reasoning: - the controller earns its complexity only once it stabilizes the local contract that future providers will share ### Milestone 2: Provider abstraction on top of the controller Goal: - Keep the same frontend contract while allowing the controller to resolve a runtime via `local`, then later `runpod` and `modal`. At this point: - define `ComputeProvider` - implement `providers/local.py` - move local-runtime subprocess management behind the provider interface The first provider should be `local`, because it is cheapest to debug and matches the runtime most closely. ## Minimal Code Change Order If we want the shortest path to a working local GPU milestone, the change order should be: 1. Fix `apps/dreamverse/dreamverse/config.py` and any remaining path assumptions from `prod-ui` to `apps/dreamverse/web`. 2. Update `README.md` to document the real local GPU startup flow. 3. Confirm `apps/dreamverse/web` connects cleanly to the local wrapper-backed backend. 4. Improve frontend error handling for backend-not-ready and backend-missing cases. 5. Add a local smoke test and keep existing backend/frontend tests green. 6. Only then introduce `controller/`. ## Test Plan for the Local GPU Milestone ### Backend Keep the current Python test suite as the base: - `apps/dreamverse/dreamverse/tests/test_health_endpoints.py` - `apps/dreamverse/dreamverse/tests/test_mock_server.py` - `apps/dreamverse/dreamverse/tests/test_prompt_enhancer.py` - `apps/dreamverse/dreamverse/tests/test_rewrite_prompt_payload.py` - related config and logging tests Add or tighten tests for: - path resolution in `apps/dreamverse/dreamverse/config.py` - readiness behavior when GPU pool initialization fails - startup error messaging when `fastvideo` is unavailable ### Frontend Keep the current Vitest suite as the base: - websocket reducer tests - prompt-window snapshot tests - integration tests under `apps/dreamverse/web/src/app/` Add or tighten tests for: - connection failure UX when backend is down - readiness failure UX when backend returns non-ready status - backend routing configuration through `BACKEND_HOST` and `BACKEND_PORT` ### Manual smoke path The first manual smoke checklist should be: 1. start `dreamverse-server` 2. confirm `GET /healthz` returns 200 3. confirm `GET /readyz` returns 200 after warmup 4. start `apps/dreamverse/web` 5. confirm the UI opens and the websocket connects 6. submit a prompt and verify the first generation starts This checklist should be written down in the README once the milestone is implemented. ## Test Strategy The test suite should preserve one rule: provider changes must not be able to break prompt rewrite, websocket semantics, or runtime behavior silently. ### 1. Runtime unit and integration tests Keep and expand the current `pytest` coverage in `apps/dreamverse/dreamverse/tests/test_*.py`. Focus areas: - config loading - prompt rewrite payload normalization - prompt enhancement and prompt safety - health/readiness endpoints - websocket session behavior - session logging - mock runtime behavior These tests should remain provider-agnostic. ### 2. Controller unit tests Add a Python test suite for the controller state machine. Key cases: - provider selection and validation - credential loading from local config or env - runtime lifecycle transitions: - idle - provisioning - ready - failed - stopping - idle timeout and cleanup behavior - retry and backoff behavior - HTTP and websocket proxy routing These tests should use fake providers and fake runtimes by default. ### 3. Provider contract tests Each provider should pass the same contract tests. Examples: - `ensure_runtime()` returns a usable `RuntimeHandle` - `wait_until_ready()` surfaces timeout vs readiness correctly - `stop_runtime()` is safe to call twice - provider errors are mapped into stable controller error types Use recorded fixtures or fakes wherever possible to avoid spend in CI. ### 4. Web contract tests The frontend already has useful Vitest coverage under `apps/dreamverse/web/src`. Preserve that and expand around the controller split. Priority areas: - websocket event reduction - prompt-window snapshot construction - rewrite request shaping - compute-status UI - failure and reconnect UX The frontend should mock the local controller API, not provider APIs. ### 5. Cross-layer protocol tests Add contract fixtures that validate shared payloads across layers. Important fixtures: - websocket event payloads - rewrite request payloads - runtime status payloads - controller status payloads These can be simple JSON fixtures validated by both Python and TypeScript tests. They will catch drift earlier than end-to-end tests. ### 6. Smoke tests Add a small number of high-signal smoke tests: - local provider + mock runtime - local provider + real runtime when GPU is available - controller startup + frontend health path These should be cheap enough for routine local use. ### 7. Provider-backed manual or nightly tests Real Modal and Runpod tests should be opt-in. - Do not run them in default CI. - Gate them behind explicit credentials and flags. - Keep them focused on provisioning and reachability, not full product regression. This avoids flaky and expensive CI while still validating real provider flows. ## Testing Recommendations for the Next Step The next practical additions should be: 1. A controller test suite in Python using fake providers. 2. Shared contract fixtures for websocket and rewrite payloads. 3. A smoke test that starts the local controller against the existing mock runtime. I would not add Playwright yet. The current web stack already has Vitest and integration-style component tests, which are cheaper and better aligned with the immediate reorg. Add browser automation only after the controller path is stable.