Back to Dyad

Cloud Sandboxes Runtime Mode

plans/cloud-sandboxes.md

0.44.021.8 KB
Original Source

Cloud Sandboxes Runtime Mode

Generated by swarm planning session on 2026-02-12

Summary

Add a new "Cloud Sandbox" runtime mode to Dyad that executes user-generated apps in Vercel's cloud sandbox environment instead of on the local machine. This is a Dyad Pro feature that removes local toolchain requirements, provides instant cloud-based previews, and enables shareable preview URLs. Initially supports Vercel Sandbox SDK, with a provider-agnostic interface to support additional providers later.

Problem Statement

Today, Dyad users must run generated apps on their local machine (host mode) or inside Docker containers. Both modes require local compute resources, proper toolchain setup (Node.js, pnpm, Docker Desktop), and can encounter platform-specific issues (port conflicts, PATH issues, Windows file locks). For new users, "getting the app to run" is a significant friction point before they can even evaluate whether the AI-generated code is correct. For advanced users, local execution limits collaboration -- you can't easily share a running preview with a teammate or client.

Cloud sandboxes solve this by offloading execution to a remote, pre-configured environment. The user's machine becomes a thin client: they send code, the cloud runs it, and the preview appears in the same iframe. This removes setup friction, improves reliability, and enables shareable preview URLs.

Target Users

  1. New users who don't have Node.js or Docker installed and want zero-setup app building
  2. Users on constrained machines (low-spec laptops) who can't run local dev servers well
  3. Pro/power users who want instant, reliable previews without local process management
  4. Team users (future) who want to share live previews with teammates or clients

Scope

In Scope (MVP)

  • Add "cloud" to RuntimeMode2Schema enum
  • Runtime mode selector shows "Cloud Sandbox (Pro)" with Pro gate (upgrade prompt for free users)
  • executeAppInCloud() function using Vercel Sandbox SDK for sandbox creation, file upload, and log streaming
  • Proxy cloud sandbox URL through local server (reuse start_proxy_server.ts) for script injection (component selector, visual editing, console capture)
  • "Copy shareable link" button in preview toolbar exposing the direct sandbox URL
  • Cloud icon/badge in preview toolbar to indicate cloud mode
  • Dyad Engine endpoints for sandbox provisioning (authenticates Pro user, manages Vercel credentials)
  • Auto-hibernate sandboxes after 15 minutes of inactivity
  • Maximum 1 concurrent cloud sandbox per user (v1)
  • Stale sandbox reconciliation on Dyad launch (clean up orphans from previous sessions)
  • Batch file sync: collect file changes from an AI turn and push as a batch
  • Cloud-specific error states: network/timeout, auth expiry, usage limits, proxy failure
  • Clear distinction between cloud sandbox (preview) and Vercel Deploy (production) in the UI

Out of Scope (Follow-up)

  • Provider abstraction layer for additional sandbox providers (CodeSandbox, StackBlitz, AWS)
  • Per-app runtime mode override (currently global only)
  • Environment variable forwarding to cloud sandboxes (for database URLs, API keys)
  • Cost/usage tracking dashboard for Pro users
  • Warm sandbox pools for faster cold-start
  • Pre-warming sandboxes before user clicks "Run"
  • Server-side rendering or backend API routes in sandbox
  • Smart cloud-mode suggestions when local errors occur (only for environment-class errors, defer to v2)

User Stories

  1. As a new Dyad user, I want to preview my AI-generated app without installing Node.js, so that I can start building immediately after downloading Dyad.
  2. As a Dyad user on a slow machine, I want to offload app execution to the cloud, so that my laptop doesn't slow down while building.
  3. As a Dyad Pro user, I want to switch between local and cloud runtime with one click in Settings, so that I can choose the mode that works best for my situation.
  4. As a user, I want to see clear feedback when my app is deploying to a cloud sandbox, so that I understand what's happening (Transparent Over Magical principle).
  5. As a user, I want to copy a shareable link to my running cloud preview, so that I can share it with teammates or clients for feedback.
  6. As a user, I want my cloud sandbox to update when the AI edits code, so that the preview experience is responsive.
  7. As a free user, I want to see that cloud sandboxes exist (but are Pro-only), so that I understand the value of upgrading.

UX Design

User Flow

  1. Discovery: User navigates to Settings > General Settings, sees the Runtime Mode selector.
  2. Selection: User selects "Cloud Sandbox (Pro)" from the dropdown.
    • If not Pro: Inline upgrade prompt ("Cloud sandboxes are a Dyad Pro feature. [Upgrade to Pro]"). No further action possible.
    • If Pro: Option activates immediately. No Vercel setup needed from the user.
  3. Building: User returns to chat, builds with AI, clicks "Run" or AI triggers execution.
  4. Provisioning: System creates a Vercel sandbox via Dyad Engine. Loading state: "Starting cloud sandbox..." with a simple spinner. If provisioning takes >5 seconds, show a multi-step stepper: "Creating sandbox..." -> "Installing dependencies..." -> "Starting server..."
  5. Preview: PreviewIframe loads the proxied sandbox URL. All Pro features (component selector, visual editing, console capture) work normally. Cloud icon/badge appears in the toolbar.
  6. Sharing: User clicks "Copy shareable link" in the toolbar. Direct sandbox URL is copied to clipboard. Toast: "Link copied!"
  7. Iteration: AI edits files -> files sync to cloud sandbox -> preview updates.
  8. Stopping: User stops the app or switches apps. Sandbox is torn down. Auto-hibernate kicks in after 15 min of inactivity.

Key States

  • Default (Settings): "Cloud Sandbox (Pro)" option visible in dropdown. Disabled with upgrade prompt for free users. Active for Pro users.
  • Loading: "Starting cloud sandbox..." spinner. Multi-step stepper if >5s.
  • Running: Cloud icon/badge in toolbar. Address bar shows the sandbox path (e.g., /dashboard), NOT the proxy localhost URL. "Copy shareable link" and "Open in browser" buttons both use the direct sandbox URL.
  • Error - Network/Timeout: "Cloud sandbox is taking longer than expected. Check your network connection. [Retry]"
  • Error - Auth/Backend: "Dyad cloud services are temporarily unavailable. Switch to local mode to keep building. [Switch to Local]"
  • Error - Usage Limits: "You've reached your cloud sandbox limit. Switch to local mode to keep building, or wait for your current sandbox to auto-hibernate."
  • Error - Proxy Failure: "Preview proxy failed. [Retry] or [Open direct link]" — escape hatch to direct sandbox URL.
  • Error - Build/Runtime: Same as local mode. "Fix error with AI" flow works identically.
  • Orphan Cleanup (Startup): Brief notification: "Cleaned up 1 cloud sandbox from your last session."

Interaction Details

  • Mode switching: Switching between local/docker/cloud while an app is running shows a confirmation: "Switching runtime mode will stop your currently running app. Continue?"
  • Restart button: Tooltip says "Restart Cloud Sandbox" in cloud mode. Tears down and recreates the sandbox.
  • "Clean Restart": Equivalent to "destroy and recreate sandbox" (vs. "re-upload files to existing sandbox" for normal restart).
  • "Open in browser": Opens the direct sandbox URL (not proxied localhost) in the user's default browser.
  • "Copy shareable link": Copies the direct sandbox URL. Tooltip: "Copy shareable link." Toast on copy.
  • Address bar: Shows the path from the real sandbox URL, never the proxy URL. Consistent with current local mode behavior.
  • Cloud mode is NOT the default for Pro users. Local mode remains the default for everyone. Cloud is opt-in via Settings.

Accessibility

  • Runtime mode <Select> already uses proper form semantics — adding a new option maintains keyboard accessibility.
  • Loading/progress states must have appropriate aria-live regions for screen reader announcements.
  • Cloud icon/badge must have a tooltip and aria-label ("Running in cloud sandbox").
  • "Copy shareable link" button must be keyboard-focusable with proper label.
  • Pro upgrade prompt must be keyboard-navigable and screen-reader-friendly.

Technical Design

Architecture

User (Electron App)
    |
    v
RuntimeModeSelector (Settings)
    |  settings.runtimeMode2 = "host" | "docker" | "cloud"
    v
executeApp() decision point (app_handlers.ts)
    |
    ├── "host"  → executeAppLocalNode() [existing]
    ├── "docker" → executeAppInDocker() [existing]
    └── "cloud"  → executeAppInCloud() [NEW]
                      |
                      v
                Dyad Backend API
                      |  (authenticates Pro user, manages Vercel credentials)
                      v
                Vercel Sandbox SDK
                      |  (create sandbox, upload files, stream logs)
                      v
                Cloud Sandbox Running
                      |  (preview URL: https://<id>.vercel.app)
                      v
                Local Proxy Server (start_proxy_server.ts)
                      |  (injects Dyad scripts, serves to iframe)
                      v
                PreviewIframe (proxied URL: http://localhost:5XXXX)

Two-URL model:

  • appUrl (proxied): http://localhost:5XXXX — used in iframe, has injected scripts for Pro features
  • originalUrl (direct): https://<sandbox-id>.vercel.app — shareable, used by "Copy link" and "Open in browser"

This maps cleanly to the existing appUrlAtom which already stores both appUrl and originalUrl.

Components Affected

  • src/lib/schemas.ts — Add "cloud" to RuntimeMode2Schema enum
  • src/ipc/handlers/app_handlers.ts — New executeAppInCloud() function, cloud branch in executeApp(), file sync hook in editAppFile
  • src/ipc/utils/process_manager.ts — Generalize RunningAppInfo:
    typescript
    interface RunningAppInfo {
      process: ChildProcess | null; // null for cloud
      processId: number;
      mode: "host" | "docker" | "cloud"; // replaces isDocker boolean
      containerName?: string; // docker only
      cloudSandboxId?: string; // cloud only
      cloudPreviewUrl?: string; // cloud only
    }
    
    Use mode string union instead of boolean flags (isDocker, isCloud) for cleaner branching.
  • src/ipc/utils/start_proxy_server.ts — Support proxying to remote HTTPS URLs (currently targets localhost only). Handle SSL, inject Dyad scripts into response HTML.
  • src/components/RuntimeModeSelector.tsx — Add "Cloud Sandbox (Pro)" option. Pro gate with upgrade prompt for free users.
  • src/hooks/useRunApp.ts — Handle cloud preview URL delivery. Emit synthetic app:output with [dyad-proxy-server] format for consistency.
  • src/components/preview_panel/PreviewIframe.tsx — Cloud icon/badge in toolbar. "Copy shareable link" button using originalUrl. "Open in browser" uses direct URL. Conditional UI based on mode.
  • src/components/preview_panel/PreviewPanel.tsx — Cloud-specific loading states, error messages.
  • New: src/ipc/utils/cloud_sandbox_provider.ts — Provider interface and Vercel implementation:
    typescript
    interface CloudSandboxProvider {
      name: string;
      createSandbox(
        appPath: string,
        appId: number,
      ): Promise<{ sandboxId: string; previewUrl: string }>;
      destroySandbox(sandboxId: string): Promise<void>;
      streamLogs(sandboxId: string): AsyncIterable<string>;
      uploadFiles(sandboxId: string, files: FileMap): Promise<void>;
    }
    
  • New: Dyad Engine endpoints — Sandbox CRUD (create, destroy, status). Authenticates Pro subscription, manages Vercel credentials server-side.

Data Model Changes

MVP: No database schema changes. Sandbox state is stored in-memory in the runningApps Map. Sandboxes are ephemeral and don't survive Dyad restarts. On restart, the user simply re-runs the app (creates a new sandbox).

Settings: No new settings fields needed for MVP. The existing runtimeMode2 field gains a new enum value. Pro subscription state is already managed separately.

Future (if sandboxes become long-lived): Add cloudSandboxId and cloudSandboxUrl columns to the apps table for persistence and startup reconciliation.

API Changes

No new IPC contracts needed for MVP. The existing runApp/stopApp/restartApp contracts work as-is. executeApp() routes internally to the cloud implementation.

New Dyad Engine API endpoints:

  • POST /api/sandboxes — Create a sandbox (requires Pro auth)
  • DELETE /api/sandboxes/:id — Destroy a sandbox
  • GET /api/sandboxes/:id/status — Check sandbox status
  • POST /api/sandboxes/:id/files — Upload files to sandbox
  • GET /api/sandboxes/:id/logs — Stream logs (SSE or WebSocket)

Internal provider interface: CloudSandboxProvider as described above, with a Vercel implementation.

Implementation Plan

Phase 1: Schema, UI, and Proxy Upgrades

  • Add "cloud" to RuntimeMode2Schema in schemas.ts
  • Update RuntimeModeSelector.tsx with "Cloud Sandbox (Pro)" option and Pro gate
  • Refactor RunningAppInfo to use mode: "host" | "docker" | "cloud" instead of isDocker boolean
  • Upgrade start_proxy_server.ts to support proxying remote HTTPS URLs with script injection
  • Add cloud icon/badge component for the preview toolbar

Phase 2: Dyad Backend Endpoints

  • Determine if existing Dyad Pro backend can be extended (or if new infrastructure is needed)
  • Implement sandbox CRUD endpoints: create, destroy, status
  • Implement file upload endpoint
  • Implement log streaming endpoint (SSE or WebSocket)
  • Add Pro subscription authentication to all endpoints
  • Add usage limits: max 1 concurrent sandbox, 15-min inactivity auto-hibernate

Phase 3: Core Cloud Execution

  • Define CloudSandboxProvider interface in cloud_sandbox_provider.ts
  • Implement Vercel Sandbox SDK provider against the Dyad Engine endpoints
  • Implement executeAppInCloud() in app_handlers.ts: create sandbox, upload files, stream logs, wire preview URL
  • Add cloud branch to stopAppByInfo() for sandbox teardown
  • Emit preview URL via synthetic app:output for consistency with existing flow
  • Wire proxy server to target the cloud sandbox URL

Phase 4: File Sync and Sharing

  • Hook editAppFile to sync changes to cloud sandbox when in cloud mode
  • Implement batched file sync: collect changes per AI turn, push as single batch
  • Add "Copy shareable link" button in PreviewIframe.tsx toolbar (uses originalUrl)
  • Ensure "Open in browser" uses direct sandbox URL in cloud mode
  • Ensure address bar shows sandbox path, not proxy URL

Phase 5: Lifecycle Management and Error Handling

  • Implement graceful sandbox teardown on Dyad quit (iterate runningApps, destroy cloud entries)
  • Implement stale sandbox reconciliation on Dyad startup
  • Add cloud-specific error handling: network/timeout, backend unavailable, usage limits, proxy failure
  • Add mode-switching confirmation when app is running
  • Add "Restart Cloud Sandbox" tooltip and clean restart behavior
  • Add note in Publish panel distinguishing sandbox from production deployment
  • Handle Pro subscription expiry while sandbox is active

Testing Strategy

  • Unit tests: Mock CloudSandboxProvider. Test executeApp() routing, stopAppByInfo() cloud branch, file sync triggering, batched upload logic.
  • E2E tests: Use a fake cloud sandbox server (similar to existing IS_TEST_BUILD pattern that stubs Vercel API to localhost:3500). Test full flow: select cloud mode → run app → see preview → copy link → stop app.
  • Integration tests: Test file sync (write file via editAppFile, verify upload call). Test sandbox lifecycle (create, restart, stop). Test proxy with remote HTTPS target.
  • Manual testing: Preview panel UX with remote URLs, component picker/visual editing through proxy, latency feel, error states, Pro gate behavior.

Risks & Mitigations

RiskLikelihoodImpactMitigation
Dyad Engine dependency — if Engine is down, cloud sandboxes are brokenMediumHighMonitoring, clear error messages ("Dyad cloud services temporarily unavailable"), fallback to local mode suggestion
Orphaned sandboxes consuming Dyad's cloud resourcesHighHighAuto-hibernate after 15 min, max 1 concurrent sandbox, startup reconciliation, graceful teardown on quit
Proxy server complexity increases (HTTPS remote target, script injection)MediumMediumIncremental upgrade to existing proxy, thorough testing of script injection with remote content
User confusion between cloud sandbox (preview) and Vercel Deploy (production)MediumMediumClear labeling in UI, note in Publish panel, distinct icons
File sync failures leave preview showing stale contentMediumMediumSurface sync failures as app:output stderr messages, "Fix with AI" flow still works
Pro subscription expires during active sandboxLowMediumGraceful teardown with clear message, fall back to local mode
Vercel Sandbox SDK rate limits or API changesLowHighAbstract behind provider interface, monitor API usage, maintain relationship with Vercel

Open Questions

  • Dyad Engine integration: Sandbox management will be implemented in Dyad Engine (the existing backend service). Specific endpoint design and Vercel SDK integration details need to be worked out.
  • Vercel Sandbox SDK specifics: What are the exact API methods, rate limits, and pricing? Detailed SDK documentation review needed before Phase 3.
  • Environment variables: How will apps that need DATABASE_URL, Supabase keys, etc. work in cloud mode? Deferred to follow-up, but needs a clear user-facing message in v1 ("Environment variables may not be available in cloud sandbox mode").
  • restartApp with removeNodeModules: What's the cloud equivalent? Destroy and recreate vs. re-upload to existing sandbox? Needs decision during Phase 5.

Decision Log

DecisionReasoning
Vercel Sandbox SDK as the first cloud providerReal-time file sync and instant rebuilds. Existing Vercel relationship. SDK purpose-built for interactive development.
Proxy through localhost for iframe previewPreserves all Pro features (component selector, visual editing, console capture) via script injection. Trade-off: proxied URL isn't directly shareable, but "Copy link" button provides the direct URL.
Dyad Pro feature (Dyad manages infrastructure)Simplifies UX (no Vercel account setup needed), controls costs, creates Pro upsell opportunity. Requires Dyad Engine for sandbox management.
Shareable URLs in MVPHighest-value, lowest-effort differentiator of cloud mode. "Copy link" button is ~10 lines of code.
Global runtime mode for v1Consistent with existing Docker mode. Simpler data model and UI. Per-app override deferred to v2.
In-memory sandbox state for MVPSandboxes are ephemeral. No DB migration needed. Revisit if sandboxes need to survive restarts.
mode string union over boolean flagsmode: "host" | "docker" | "cloud" is cleaner than isDocker + isCloud boolean flags. Easier to extend.
Cloud mode is opt-in, not defaultLocal mode remains default for all users including Pro. Cloud mode is slower for iteration and requires internet.
Batch file sync per AI turnAvoids thundering herd of 5-20 individual uploads during multi-file AI responses. Reduces API calls and prevents mid-batch rebuilds.
Auto-hibernate after 15 minPrevents orphaned sandboxes from running up Dyad's cloud costs. Balance between convenience and cost control.

Generated by dyad:swarm-to-plan