Issue #348 — Phase 1 Implementation
Mini setup server + multi-select backend onboarding
Issue #348
This walkthrough covers the concrete changes in this PR.
1 What Changed
✗ Before
npm run dev → runs Docker mode by default
- Fails if Docker isn’t installed
- Step 1: “Check Backend” — just verifies connection, single backend
- No way to run Local + Docker simultaneously
✓ After
npm run dev → always works (local mode, no Docker needed)
- Step 1: “Choose Backend” — multi-select Local + Docker
- Mini setup server bridges frontend ↔ Docker lifecycle
- Docker is started on-demand through the UI
2 Architecture
npm run dev
├─ Vite dev server :3001
├─ Local agent-server :18000 (always started)
├─ Automation backend :18001
├─ Ingress proxy :8000 (routes all traffic)
├─ Mini Setup Server :18099 ← NEW
│ ├─ GET /setup/status → { dockerInstalled, dockerRunning, dockerBackendRunning }
│ ├─ POST /setup/docker → Start Docker backend, returns { host, port }
│ └─ DELETE /setup/docker → Stop Docker backend
│
└─ [spawned on demand by setup server]
Docker agent-server :18002
The ingress proxy routes /setup/* to the setup server,
so the browser frontend accesses it via the same origin.
Why a setup server?
- The browser cannot spawn Docker containers
- The Node.js
npm run dev process can
- A tiny HTTP server (~110 lines) bridges the gap
127.0.0.1 only — not network-exposed
- Reuses Docker logic from existing
dev-docker.mjs
3 Onboarding Flow
Step count stays at 4. The key change is Step 1:
Step 0
Choose Agent
→
changed Step 1
Choose Backend
→
Step 2
Setup LLM
→
Step 3
Say Hello
| Before (CheckBackendStep) | After (ChooseBackendStep) |
| Purpose | Verify single backend is reachable | Pick one or both backends (Local + Docker) |
| Local | Always used (if running) | Always selected, always running |
| Docker | Requires npm run dev:docker | Started on-demand from UI via setup server |
| Multi-backend | ✗ | ✓ Both in dropdown simultaneously |
4 UI Mockup — Choose Backend
Agent Canvas — Onboarding
Step 2 of 4
Choose your backend
Select one or both — you can always change this later in Settings.
✓
Default
Local Backend
Runs the agent directly on your machine. No Docker needed.
✓ Zero-config, local credentials, local tools
✗ Unsandboxed — full filesystem access
Confirmation mode enabled by default.
✓
Recommended
Docker Backend
Runs inside a Docker container for isolation.
✓ Sandboxed — can’t affect host environment
✗ Requires Docker Desktop
Workspace directory
/Users/you/projects
Start Docker Backend
5 What happens when the user clicks “Next”
If only Local is selected
Nothing to do — local backend is already running since npm run dev. Proceeds immediately.
If Docker is selected
- User enters workspace directory and clicks “Start Docker Backend”
- Frontend calls
GET /setup/status to check Docker availability
- If Docker is available, calls
POST /setup/docker with { projectPath }
- Setup server spawns Docker container on port 18002
- Shows “Docker backend started” confirmation
- “Next” button becomes enabled once Docker is running or Local is selected
6 Setup Server API
| Endpoint | Method | Response |
/setup/status |
GET |
{ dockerInstalled, dockerRunning, dockerBackendRunning, dockerBackendPort } |
/setup/docker |
POST |
Body: { projectPath } → { status, host, port, url } |
/setup/docker |
DELETE |
{ status: "stopped" } |
All endpoints return JSON with CORS headers. The ingress proxy routes /setup/* to the setup server, so the frontend uses the same origin.
7 Files Changed
| File | Status | Change |
scripts/setup-server.mjs |
new |
Mini HTTP server for Docker lifecycle (~110 lines) |
scripts/dev-with-automation.mjs |
modified |
Import + start setup server; add /setup route to ingress |
src/api/setup-service.ts |
new |
Frontend API client for setup server endpoints |
src/.../steps/choose-backend-step.tsx |
new |
Multi-select backend UI (Local + Docker) |
src/.../onboarding-modal.tsx |
modified |
Swap CheckBackendStep → ChooseBackendStep |
src/i18n/translation.json |
modified |
21 new i18n keys for backend selection UI |
walkthrough.html |
new |
This document — visual walkthrough of the changes |
8 Key Code Snippets
// Endpoints served on 127.0.0.1:18099
GET /setup/status → isDockerInstalled() + isDockerRunning() + isDockerBackendRunning()
POST /setup/docker → startDockerBackend(projectPath, { sessionApiKey })
DEL /setup/docker → stopDockerBackend()
// Docker lifecycle reuses the same image + mount logic as dev-docker.mjs:
docker run --rm --name agent-canvas-dev-docker-backend \
-v $PROJECT_PATH:/projects \
-v ~/.openhands:/home/openhands/.openhands \
-v ~/.claude:/home/openhands/.claude \
-p 18002:8000 \
ghcr.io/openhands/agent-server:1.22.0-python
+ import { startSetupServer, DEFAULT_PORT as SETUP_SERVER_PORT } from "./setup-server.mjs";
// In main():
+ // 7. Start setup server (lets the frontend manage Docker lifecycle)
+ startSetupServer({ port: SETUP_SERVER_PORT, sessionApiKey: config.sessionApiKey });
// In startIngress():
+ "--route", `/setup=http://127.0.0.1:${SETUP_SERVER_PORT}`,
- import { CheckBackendStep } from "./steps/check-backend-step";
+ import { ChooseBackendStep } from "./steps/choose-backend-step";
<Slide index={1} currentStep={currentStep}>
- <CheckBackendStep onBack={goBack} onNext={goNext} />
+ <ChooseBackendStep onBack={goBack} onNext={goNext} />
</Slide>
9 Backend Comparison
|
Local |
Docker |
| Sandbox | ✗ None | ✓ Container |
| Confirmation Mode | ✓ On by default | Optional |
| File Access | Entire filesystem | Mounted dir only |
| Prerequisites | None (uvx only) | Docker Desktop |
| How Started | Always (via npm run dev) | On demand (via setup server) |
| Port | :18000 | :18002 |
Summary of Changes
- New:
scripts/setup-server.mjs — ~110 line HTTP server that manages Docker lifecycle for the frontend
- New:
src/api/setup-service.ts — Frontend API client for /setup/* endpoints
- New:
choose-backend-step.tsx — Multi-select backend step (replaces CheckBackendStep in onboarding)
- Modified:
dev-with-automation.mjs — Starts setup server + routes /setup/* through ingress
- Modified:
onboarding-modal.tsx — Uses new ChooseBackendStep
- 21 new i18n keys for the Choose Backend UI
Not in scope (future work): Agent auto-discovery, ACP session listing, conversation agent tags. See agent-canvas #405 and software-agent-sdk #3236.