Vision
Reimagine the post-login landing page (landing/app/templates/index.html) as a retro computer desktop: teams are folders, apps are icons inside them. Double-click a folder to open it; click an app to launch it; right-click an app for a menu with History and Build. Users can open multiple apps at once, each in its own draggable window.
Feasibility verdict: window dressing — no stack changes required
Analysis of the current landing/app confirms the metaphor is a frontend redesign that reuses existing endpoints. Nothing about pods, sessions, routing, or the proxy needs to change:
- Folders already exist — apps live at
apps/{team}/{app-slug}/; catalog.scan_apps() groups by team. Folders = teams.
- All three actions are already routes (
landing/app/templates/index.html:256-258):
- Launch (click) →
GET /run/{team}/{slug} (run pod)
- Build (right-click) →
GET /build/{team}/{slug} (build pod)
- History (right-click) →
GET /versions/{team}/{slug}
- Concurrency is already in the data model —
SessionStore is keyed (user_id, app_slug), so a user can hold multiple simultaneous build sessions for different apps; build pods are uniquely named; run pods are per-(team, app_slug) and already coexist. Nothing enforces one-app-at-a-time.
- Pages are iframe-embeddable — there are no
X-Frame-Options / CSP frame-ancestors headers anywhere in the landing app, so windows can host /run and /build as same-origin iframes. (Build/run pages already nest iframes internally for terminal + preview; 2-deep nesting is fine.)
So this is a real frontend effort (a client-side window manager is heavier than today's server-rendered HTMX catalog), but it is not a change to how the stack operates.
Caveats to handle (not blockers)
- Resource cost of concurrent builds — each build pod requests 250m CPU / 256Mi. Many concurrent build windows multiply cluster load. Consider a soft per-user cap, or scope v1 to "launch/view freely, keep active builds modest." Launching (run pods) is cheaper and shared per-app.
- Background heartbeat throttling —
build.html keeps pods alive via JS heartbeats; browsers throttle timers in hidden/background iframes, so a minimized build window could be idle-reaped by the 10-min cleanup (cleanup.py). The window manager should keep heartbeats firing for open-but-inactive windows, or we accept that minimized builds may reap.
- iframe contract — the CLAUDE.md rule "absolute links break out of the iframe and load the landing page" still holds; the desktop shell must not be the thing that breaks out, and must preserve relative-link behavior for embedded run/build content.
Sub-issues
Non-goals (v1)
- No backend/session/pod/proxy changes — if a proposed feature needs one, it's out of scope for this epic.
- Not necessarily drag-and-drop file management, trash, or a full OS metaphor — just folders, icons, windows, and the context menu.
Vision
Reimagine the post-login landing page (
landing/app/templates/index.html) as a retro computer desktop: teams are folders, apps are icons inside them. Double-click a folder to open it; click an app to launch it; right-click an app for a menu with History and Build. Users can open multiple apps at once, each in its own draggable window.Feasibility verdict: window dressing — no stack changes required
Analysis of the current landing/app confirms the metaphor is a frontend redesign that reuses existing endpoints. Nothing about pods, sessions, routing, or the proxy needs to change:
apps/{team}/{app-slug}/;catalog.scan_apps()groups by team. Folders = teams.landing/app/templates/index.html:256-258):GET /run/{team}/{slug}(run pod)GET /build/{team}/{slug}(build pod)GET /versions/{team}/{slug}SessionStoreis keyed(user_id, app_slug), so a user can hold multiple simultaneous build sessions for different apps; build pods are uniquely named; run pods are per-(team, app_slug)and already coexist. Nothing enforces one-app-at-a-time.X-Frame-Options/ CSPframe-ancestorsheaders anywhere in the landing app, so windows can host/runand/buildas same-origin iframes. (Build/run pages already nest iframes internally for terminal + preview; 2-deep nesting is fine.)So this is a real frontend effort (a client-side window manager is heavier than today's server-rendered HTMX catalog), but it is not a change to how the stack operates.
Caveats to handle (not blockers)
build.htmlkeeps pods alive via JS heartbeats; browsers throttle timers in hidden/background iframes, so a minimized build window could be idle-reaped by the 10-min cleanup (cleanup.py). The window manager should keep heartbeats firing for open-but-inactive windows, or we accept that minimized builds may reap.Sub-issues
Non-goals (v1)