Architecture

open-bot is three moving parts, orchestrated by Docker Compose:

┌──────────────────────────── Docker host ────────────────────────────┐
│                                                                     │
│  ┌─────────────── Control plane (open-bot) ───────────────────────┐ │
│  │  Bun server :8787                                              │ │
│  │  • sqlite (users, sessions, cron, plugins, media, settings)    │ │
│  │  • dashboard API + EventHub (WS /api/events)                   │ │
│  │  • starts/stops desktop + viking containers                    │ │
│  └──────────────┬──────────────────────────┬──────────────────────┘ │
│                 │ docker API               │ docker API             │
│  ┌──────────────▼───────────┐   ┌──────────▼──────────────────┐    │
│  │ Desktop (per user)       │   │ OpenViking (per user)       │    │
│  │  opencode server :4096   │   │  memory server :1933        │    │
│  │  thread screen (Xvfb)    │   │  embeddings + VLM           │    │
│  │  agent CLIs + skills     │   └─────────────────────────────┘    │
│  └──────────────────────────┘                                      │
└─────────────────────────────────────────────────────────────────────┘
                                │
                          Browser dashboard

Control plane

A single Bun process (apps/control). Owns:

  • Auth — HttpOnly ob_session cookie for browsers; Authorization: Bearer <llm token> for desktop agents.
  • Database — sqlite via drizzle (see the configuration reference for the schema migrations).
  • Orchestration — creates desktop containers per user, boots OpenViking, restarts desktops.
  • EventHub — a WebSocket at /api/events that fans live events (session.created, media.changed, projects.changed, reports.changed, plugin.notice, ...) to the dashboard.

Details in Control plane.

Desktop container

One container per user. Runs the OpenCode server (port 4096, Basic auth), a virtual thread screen (Xvfb + openbox, VNC + CDP), and the agent's seed skills and CLIs. The agent is a conversational bot — the seed AGENTS.md shapes it, and plugins can inject more. Details in Desktop containers.

OpenViking

Per-user memory server (port 1933): persistent context, preferences, project docs, and skills, searched semantically before each turn. Details in OpenViking setup.

Request flow (a chat turn)

  1. Browser posts the prompt; control plane resolves the user's desktop (starting it if needed).
  2. The prompt goes to the desktop's OpenCode server (prompt_async).
  3. OpenCode runs the agent: tools, CLIs, screen, memory — streaming events back through the EventHub.
  4. On session.idle, chat media are filed into the media vault and plugin hooks may fire.

Enforcement points

LimitEnv / settingDefault
Desktops per instanceMAX_DESKTOPS4
Concurrent thread screensMAX_THREAD_SCREENS3
Desktop idle stopIDLE_MINUTES15
Preview portsPREVIEW_PORT_MIN/MAX4700–4719

The control container never reads the host OpenCode config — all provider auth lives in the desktop or in the control's own sqlite.