Skip to content

desktop: run the server and worker from the published image instead of building on the host - #852

Open
dustywusty wants to merge 10 commits into
dustywusty/local-eval-on-upstreamfrom
dustywusty/desktop-runs-images
Open

dustywusty wants to merge 10 commits into
dustywusty/local-eval-on-upstreamfrom
dustywusty/desktop-runs-images

Conversation

@dustywusty

@dustywusty dustywusty commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

OpenBot Desktop starts OpenBot's server and worker as containers from the published server image, instead of downloading Bun, running bun install, building the web app and supervising three host processes. Stacked on #832; needs #851 and a release that includes it.

Review the last six commits. The four before them are copies of #851, so this branch can run on top of #832. #851 is now on main; they drop out of the diff once #832 is updated from main and this branch is rebased onto it.

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.

What changes

  • Install no longer downloads Bun or runs bun install. The self-hosted Intelligence sign-in helper is the only thing on the host that still runs a Bun script; it now prepares Bun and the packages on first use and reuses them after that.
  • Start:
    • Mints the host-access token before compose up. It is still never written to disk; Compose hands it to the server container only.
    • Sets COMPUTER_NETWORK=<project>_default, so per-Bot computers sit on the server's network. On Linux it also sets OPENBOT_SERVER_USER to the install folder's owner.
    • Creates .openbot, then raises server and worker with the other services.
    • Waits up to 180 s for /health on the app and server ports, and stops early if Stop is pressed.
    • Docker's restart policy replaces the desktop's process supervision.
  • Settings (env.rs): Bots call http://server:3001/api/agent-tools/call. The server gets host.docker.internal addresses for local Intelligence, and the browser keeps localhost (via Run OpenBot's server, app and worker from the published server image #851's INTELLIGENCE_BROWSER_GATEWAY_WS_URL). An installed harness gets its container address.
  • Stop names the openbot profile; Compose skips a profile's services unless it is named.
  • Ownership, Status, Restart look at the server container instead of host pids. Restart runs compose restart server worker.
  • Existing installs: the cleanup of old Bun host processes stays on Start and Stop, so an install that ran host processes is moved over on its next Start.
  • About 1,900 lines of host-process spawning, supervision and their tests are removed.

Verification

From desktop/src-tauri: cargo fmt --check and cargo clippy --all-targets -- -D warnings are clean. cargo test --lib --bins: 651 and 184 passed. New tests cover container addresses, harness container URL, project_name, the host token reaching Compose at up, COMPUTER_NETWORK, the .openbot folder, port ownership and the readiness wait.

Not run end to end yet. It needs a release whose server image contains the worker (#851).

Open before this can merge

Done: the minimum-release check (163a20d). An install pinned to a release whose Compose file has no server/worker service is sent back to Install and moved to the latest release, keeping its data volume and KEY_ENCRYPTION_KEY.

Still open:

  • deployment_problem still requires the server/, app/ and worker/ folders and the serve script.
  • The Status page assumes container names start with openbot-.
  • Linux: local Intelligence is not offered there, because host-gateway can't reach k3d's 127.0.0.1-bound ports on Docker Engine.

@dustywusty
dustywusty marked this pull request as ready for review October 27, 2026 22:04
@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-27T22:06:34.849775Z 8995cf0 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8995cf09c0

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread desktop/src-tauri/src/stack.rs
Comment thread desktop/src-tauri/src/main.rs
@guidovizoso

Copy link
Copy Markdown
Collaborator

This is the biggest UX win in the install work: no more host Bun or 20+ minute bun install on Windows. Leaving notes instead of approving, since it's a draft and still has open items.

  • Windows CI: intelligence_bridge::tests::the_owned_app_origin_reaches_these_commands_and_nothing_else panics at src/intelligence_bridge.rs:255 (app (windows), Rust regression tests). Possibly the allow-listed command set after the restart change.
  • The 180 s wait for /health: the window should show calm progress during it ("Starting OpenBot…", with stages) and never an error or a failure-looking state while containers come up, especially on a cold Windows machine pulling images.
  • Minimum release, deployment_problem, the openbot- name assumption, Linux local Intelligence: agree these are needed before merging, as listed.

Related, but not something this PR needs to fix: our bar is that a non-technical person is never asked to install Docker or WSL, or to run a command. Today a Windows machine without WSL ends on "Open PowerShell as an administrator, run wsl --install…" (windows.rs:63-105), and the resumable setup that windows.rs already designs (one UAC prompt → enable features → OpenBot-offered restart → resume) isn't built yet. Since this PR makes the container path the only path, I think that setup should come next, ahead of other install work. The same applies to the "install Docker Desktop" advice in missing_compose.

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.
…n addresses

SERVICES now includes server and worker, and Stop names the openbot profile
they sit behind. The settings point every Bot at server:3001, give the server
host.docker.internal addresses for local Intelligence (the browser keeps the
localhost ones), and give an installed harness its container address. The
macOS Podman overlay publishes the server's two ports on IPv4 only.
… host

Start now hands everything to Compose and waits for the `server` container
to answer `/health` on both the app and API host ports, for up to 180 s.
Docker's restart policy supervises the server and worker, so the host
launch, readiness, pid recording and restart loop are gone.

- The desktop host token is minted before `up` and reaches Compose, which
  names it for the server alone; it is still never persisted.
- COMPUTER_NETWORK is `<compose project>_default` (new
  `stack::project_name`), so Bot computers join the server's network. On
  Linux OPENBOT_SERVER_USER is the deployment folder's uid:gid.
- `.openbot/` is created before `up`, since its bind mount does not
  create it.
- App and server ports count as ours when our container publishes them;
  the pre-spawn port check is gone.
- Ownership for showing, restoring and asking OpenBot is now "this root's
  server container publishes the ports" (`stack::server_publishes`), not
  recorded host pids.
- Status lists server and worker as containers; Restart runs
  `compose restart server worker`.
- What is left of the supervisor polls the server for refused
  connections (`watch_connections`).
- Start no longer requires the host Bun or packages.
- Old Bun host processes from earlier installs are still stopped on Start
  and Stop, which is how an upgrade frees 3001/3010.

Also brings tests left stale by the previous commit up to date
(server/worker in the up list, `--profile openbot` on down).
Installing OpenBot is now pulling images. Bun and bun install are prepared only
when somebody starts the self-hosted Intelligence sign-in, the one thing on the
host that still runs a Bun script, and reused after that.
Rootless Podman maps container root to the person who started it and any
other uid to one of their subordinate ids, so passing the owner's uid:gid
made the server a stranger to the owner-only .openbot sign-in folder.
Docker keeps the owner's numbers; Podman now gets 0:0.
A release from before the server and worker were Compose services has no
server or worker to raise, and its server image has no worker, so keeping
its pin left a working installation unable to start. Such a deployment now
reads as needing installation, Install resolves the latest release instead
of repairing the old pin, and if even the latest still runs the server on
the host the app says so rather than failing inside Compose.
…ring"

The Start screen showed the wait for /health as a step named "Answering",
"waiting for OpenBot to answer". It is the longest step on a cold machine,
so name it for what the person is waiting for and say it can take a few
minutes the first time.
@dustywusty
dustywusty force-pushed the dustywusty/desktop-runs-images branch from 6023929 to 2547772 Compare October 27, 2026 23:34
@dustywusty

dustywusty commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator Author

Thanks — agree on all of it. Status:

Screenshot 2026-10-26 at 3 35 12 PM

The red python harness regressions check is an ag2 test that's failing on main too, so it isn't this PR.

This branch has not been deployed

No deployments
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