Interfaces
Web console
Start the console stack and understand its authenticated RPC and narrow HTTP boundaries.
On this page+−
Start the stack
The stack launcher checks Docker, starts or restarts the gateway, rebuilds stale SPA assets, builds sandbox-console, and starts it with the current gateway token.
bin/start-sandbox-console-stack
# open http://127.0.0.1:7880Use --skip-gateway to keep an existing gateway, --skip-spa to keep packaged assets, or --bind HOST:PORT to change the console listener. The default remains loopback because browser authentication is out of scope.
Browser to gateway RPC
The browser never invokes a CLI or MCP server. Management, command, file read/write/edit/blame, and observability requests go to POST /api/rpc. The console validates the route against the public catalog, keeps the gateway token server-side, and forwards authenticated RPC through the shared operation client.
| Console route | Purpose |
|---|---|
POST /api/rpc | Single public operation; SSE when requested for streamed logs |
GET /api/catalog | Merged public management, runtime, and observability catalogs |
GET /api/sandboxes/<id>/health | Proxy a daemon liveness probe |
POST /api/sandboxes/<id>/files/list | Proxy the HTTP-only directory listing |
Limited daemon HTTP
Every sandbox has a daemon_http endpoint separate from authenticated daemon RPC. Its exact allowlist is GET /health, POST /files/list, and application forwarding below /forward/.
Direct HTTP paths for file read/write/edit/blame, observability, and export return 404. file_list is the single HTTP-only operation exception; use gateway RPC through CLI, MCP, or /api/rpc for the public catalogs.
Access a sandbox server from the host
Suppose a ready sandbox is serving a webpage on port 8000. First inspect the sandbox to discover the daemon HTTP endpoint published on the host, then start the server in a shared command session. This example requires python3 in the sandbox image and jq on the host.
export SANDBOX_ID=eos-abc
DAEMON_HTTP=$(
sandbox-manager-cli inspect_sandbox --sandbox-id "$SANDBOX_ID" |
jq -er '.daemon_http | select(. != null) | "http://\(.host):\(.port)"'
)
SERVER=$(
sandbox-runtime-cli --sandbox-id "$SANDBOX_ID" \
exec_command --yield-time-ms 1000 \
"python3 -m http.server 8000 --bind 127.0.0.1 --directory ."
)
COMMAND_SESSION_ID=$(
printf '%s\n' "$SERVER" | jq -er '.command_session_id'
)On the host, open the daemon endpoint with the shared forwarding prefix. The daemon removes that prefix before passing the request to the sandbox server, so the application receives / here.
APP_URL="$DAEMON_HTTP/forward/shared/8000/"
curl --fail --show-error "$APP_URL"
printf 'Open in a browser: %s\n' "$APP_URL"Do not open http://127.0.0.1:8000/ on the host; that targets the host itself. Use the random daemon_http port returned by inspect_sandbox and the /forward/shared/8000/ path. Stop the example server by sending Ctrl-C to its command session:
sandbox-runtime-cli --sandbox-id "$SANDBOX_ID" \
write_command_stdin --command-session-id "$COMMAND_SESSION_ID" \
--yield-time-ms 1000 $'\003'Shared servers may bind to 127.0.0.1 or 0.0.0.0. A server attached to an isolated workspace session must bind to 0.0.0.0 and use /forward/isolated=<workspace-session-id>/<port>/ instead.
Preview routing
Shared previews use /s/<id>/shared/<port>/.... Workspace-isolated previews use /s/<id>/isolated=<workspace-id>/<port>/.... The console rewrites these to the daemon’s forwarding allowlist and supports streaming bodies and protocol upgrades.
Configuration and security
--config-yaml outranks SANDBOX_CONSOLE_CONFIG_YAML when selecting an optional console section. Bind and assets resolve with flag, then environment, then YAML/default precedence. Gateway socket and token discovery is separate.
Preview documents have an opaque origin and cannot call /api/*. The token stays outside the browser. See configuration for defaults and the namespace architecture for the runtime boundary.
