Launch Fresh Sandboxes from Control Plane Web UI¶
Status: Accepted (Amends ADR 0003, ADR 0040, ADR 0024, and ADR 0025)
We introduce the capability to launch fresh sandboxes—both Repository Sandboxes and Standalone Sandboxes—directly through the Modal Sandbox Runner Control Plane Web UI (sandbox/static/index.html) backed by an authenticated REST endpoint (POST /api/sandboxes in sandbox/web.py).
Context¶
Prior to this change, the Control Plane Web UI supported listing running sandboxes, terminating active sandboxes, capturing filesystem snapshots, and launching sandboxes from existing snapshot images (POST /api/snapshots/{image_id}/launch). However, launching fresh sandboxes required accessing the host terminal CLI (sandbox/main.py) or invoking the machine-to-machine headless API (POST /launch) using Bearer token authentication.
Per ADR 0025, machine-to-machine endpoints (POST /launch, POST /snapshot) use Bearer tokens (MODAL_SANDBOX_AUTH_TOKEN), while browser-based interactions on the Web UI use HTTP Basic Authentication (WEB_UI_USERNAME, WEB_UI_PASSWORD). Because no browser-authenticated endpoint existed for provisioning fresh sandboxes, operators managing sandboxes strictly through the web dashboard could not launch new workspaces without switching to a terminal or managing manual Bearer authorization headers.
Decisions¶
- Authenticated REST Endpoint for Fresh Sandboxes (
sandbox/web.py): - Expose
POST /api/sandboxesmounted on the Web UI router and protected by HTTP Basic Authentication (check_authentication). - Define
FreshSandboxLaunchPayloadsupporting bothmode="repo"andmode="standalone". - Validate input constraints:
mode="repo": requires non-emptyrepoparameter.mode="standalone": requires non-emptynameparameter.
- Delegate provisioning directly to
sandbox.core.launch_sandbox()and resolve workspace profiles viasandbox.profiles.get_client_for_profile(). -
Return standard
LaunchResponsecontaining connection metadata, SSH command, and agent URLs. -
Unified Launch Dialog in Web Dashboard (
sandbox/static/index.html): - Add a primary
+ Launch Sandboxaction button in the Sandboxes tab header toolbar adjacent to the quick filter search input. - Provide a segmented mode switcher at the top of the modal between Repository Sandbox and Standalone Sandbox:
- Repository Mode: displays
Target Repository(-r/--repo, required),Git Branch(-b, defaultmain),App Name(optional, auto-derived from repo slug if blank),--testingorg checkbox, and--full-clonetoggle. - Standalone Mode: displays
Sandbox App Name(--name, required) for booting clean workspaces with an empty repository initialized at/root/<name>.
- Repository Mode: displays
-
Provide shared options across both modes:
- Workspace Profile: dropdown pre-selected to the currently active navbar profile (or active default if "All Profiles" is selected).
- Runtime Mode: Linux VM Sandbox mode checkbox with memory input in GB (defaulting to 1 GB when enabled; Standard container runtime when unchecked).
- Integrated Tooling: checkboxes for T3 Code Server (default enabled), OpenCode, Antigravity CLI, and Modal SDK tooling.
- Cloudflare Ingress: enabled by default (
no_cloudflare=False).
-
Post-Launch Connection Details Feedback:
- On successful fresh launch, reuse the existing Connection Details dialog (
resultModalOpen), presenting the live Sandbox ID, App Name, full SSH command snippet with copy button, and direct T3 Code Server and OpenCode URLs. - Dismissing the modal automatically refreshes the Sandboxes list.
Consequences¶
- Operators can launch fresh repository-backed and standalone sandboxes entirely within the Web Dashboard across all configured Modal workspace profiles.
- Strict separation of authentication schemes (ADR 0025) is maintained: Web UI endpoints use HTTP Basic Auth, while headless machine-to-machine routes retain Bearer token authentication.
- All Python modules remain strictly under the universal <= 500 lines physical budget ratchet (ADR 0027 / AGENTS.md).