Skip to content

Run OpenBot's server, app and worker from the published server image - #851

Merged
dustywusty merged 4 commits into
mainfrom
dustywusty/compose-server-worker
Oct 27, 2026
Merged

dustywusty merged 4 commits into
mainfrom
dustywusty/compose-server-worker

Conversation

@dustywusty

@dustywusty dustywusty commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Lets OpenBot run its own server, app and worker from the published server image, so a first install of OpenBot Desktop needs only Docker. Nothing changes for anyone until something starts the new services. The desktop half is a separate draft stacked on #832.

Today and proposed

Screenshot 2026-10-27 at 11 18 15 AM

Bun is still installed on first use of the self-hosted Intelligence sign-in, the one host script left.

Why

Today the desktop downloads OpenBot's source, downloads Bun, runs bun install, builds the web app with Vite and runs the server, app and worker as host processes. On a fresh Windows 11 VM, bun install was still running 20+ minutes in, and the run timed out at 30 minutes. Every release already publishes ghcr.io/copilotkit/openbot-server with the API and the built app inside it (APP_DIST_DIR). The desktop never used it for those processes, and the worker was missing from it.

What

  • server/Dockerfile: ships worker/src, worker/package.json and worker/node_modules. The last one holds the isolated install's link to @openbot/shared; without it the worker's first import fails. The image still starts the API by default, and bun ../worker/src/index.ts runs the worker.
  • docker-compose.yml: new server and worker services from that image, behind an openbot profile. scripts/start.sh and a plain docker compose up -d don't start them, so developers keep their host server.
    • The server reads the same .env a host server reads. Every address is overridden with a service name (postgres, agent-computer, supervisor, agent-langgraph, agent-harness).
    • PORT and SERVER_PORT are both pinned to 3001. .env carries the host port, and the server refuses to start when the two disagree.
    • NODE_ENV is cleared, as it is for a host server: production refuses AGENT_COMPUTER_ALLOW_PRIVATE_HOSTS, which a local OpenBot needs.
    • APP_PORT and SERVER_PORT are both published to container 3001, loopback only. The desktop's host-access broker calls SERVER_PORT.
    • Secrets are named one by one. OPENBOT_DESKTOP_HOST_TOKEN goes to the server only.
    • ./.openbot is bind-mounted for the Google and xAI sign-in file, which the server renews itself (temp file plus rename).
    • The user is settable, so Linux can run the server as the host user.
    • The worker gets its three settings and sits on the data network only.
  • INTELLIGENCE_BROWSER_GATEWAY_WS_URL (server, toolkit): the browser opens the Intelligence gateway itself, at the URL /info gives it. A server in a container reaches local Intelligence at host.docker.internal, which the browser on the host can't resolve. When this setting is set, /info gives the browser this URL instead; the server's runner and channel sockets stay on INTELLIGENCE_GATEWAY_WS_URL. Unset, nothing changes.

The Bots keep host.docker.internal as their default tool URL, because start.sh's server is on the host. Whoever starts server sets OPENBOT_TOOL_URL=http://server:3001/api/agent-tools/call.

Verification

  • bunx biome check, bun run typecheck: clean.
  • Worker tests 19/19. Toolkit 63/63, including the new intelligence-browser-gateway.test.ts. Server config.test.ts 143/143.
  • Compose tests that don't need Docker pass: profile, image, ports, addresses, networks, host token, sign-in mount. They fail when the profile or the SERVER_PORT pin is removed.
  • Worker in the image: I rebuilt the runtime stage's /app layout from the Dockerfile's COPY list and ran bun ../worker/src/index.ts. The sweep loop started. With worker/node_modules removed it failed with Cannot find module '@openbot/shared/work-owner'.
  • The full server suite fails the same 135 tests with and without this change (TEST_DATABASE_URL unset, network guard, live providers).

Not verified locally (Docker isn't available on the machine this was written on). CI needs to cover:

  • The new docker compose config test in tests/compose.test.ts (addresses the server's Bots and endpoints from inside the network), which checks the :+ and container-address interpolation.
  • That a missing ./.openbot doesn't trip Compose for other services.
  • An actual image build.

The server image already carries the API and the built app. Add worker/src and
its node_modules (the isolated install's link to @openbot/shared), so the same
published image can run the worker with `bun ../worker/src/index.ts`.

Nothing uses it yet; this is step 1 of running OpenBot Desktop's server, app and
worker as containers instead of building them on the customer's machine.
OpenBot's own server (the API and the built app it serves) and the routines
worker, from the published server image, behind an `openbot` profile so
scripts/start.sh and a plain `docker compose up -d` keep running them on the
host as before.

The server reads the same .env a host server does, with every address
overridden to a service on the compose network, PORT and SERVER_PORT both
pinned to 3001 (the server refuses to start when they disagree), NODE_ENV
cleared so a local OpenBot may still reach private addresses, and the app and
server host ports both mapped to it on loopback. The worker gets its three
settings and sits on the data network only.

Bots keep their host.docker.internal tool URL by default; whoever starts the
server service points them at server:3001.
The runtime sends the browser the gateway's /client socket in /info, and the
browser opens it itself. A server in a container reaches local Intelligence at
host.docker.internal, which the browser on the host cannot resolve, while the
browser's localhost is the container from inside it.

INTELLIGENCE_BROWSER_GATEWAY_WS_URL, when set, is the address /info (and a
trajectory grant) gives the browser; the server's own runner and channel
sockets stay on INTELLIGENCE_GATEWAY_WS_URL. The compose server service sets it
to the deployment's own gateway URL and reads its container address from
INTELLIGENCE_CONTAINER_GATEWAY_WS_URL.
A Google or xAI sign-in leaves .openbot/model-oauth.json on the host, and the
server reads and renews it itself (temp file plus rename, and a .lock folder
beside it), so the folder is bind-mounted rather than the file. Not created by
Compose, which would make it root-owned on Linux. The user is settable so the
Linux desktop can run the server as the host user who owns that 0600 file.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T18:40:54.148966Z 4a6f528 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@guidovizoso guidovizoso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Groundwork for #852, and nothing changes until something starts the new services. Approving so we can cut a release with the worker in the image.

@dustywusty
dustywusty merged commit 022fc2d into main Oct 27, 2026
36 of 38 checks passed
@dustywusty
dustywusty deleted the dustywusty/compose-server-worker branch October 27, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants