← All Guides

Guide

How to Run OpenWorker on Linux

OpenWorker, Andrew Ng's open-source desktop AI coworker, ships installers for macOS and Windows only. There is no AppImage and no .deb. But the part that does the work — the Python agent server — runs on Linux today, and there is a browser UI that does not need the desktop shell at all. Here is the whole setup.

The short version: skip the installer page, clone the repo, run the bootstrap script, and launch the openworker terminal agent. That path needs only Python 3.11+ and git — no Node, no Rust, no Tauri, no desktop session. If you want the graphical interface instead, start openworker-server and open the browser UI on http://localhost:1420.

We ran the setup below on a clean Ubuntu 24.04 container with Python 3.12.3 before publishing it. The bootstrap completes and all three commands install.

Why there is no Linux download

The official downloads are macOS 12+ (Apple Silicon) and Windows 10/11 (x64). The packaging directory upstream has a DMG build script and a Windows PowerShell build script, and no Linux equivalent of either — so no Linux bundle has ever come out of the release pipeline.

It is not for lack of asking. Several open requests cover the same ground: “pls add a linux version” (#232), Linux release artifacts as AppImage and .deb (#173), Linux x64 build support in the release pipeline (#171), and a question about building a .deb or AppImage yourself (#117). A community pull request, #19, adds AppImage packaging along with Linux voice input and keep-awake support; it has been open since 23 July 2026 and is not merged.

None of that blocks you, because the agent engine itself was never the Mac-specific part.

The engine is already Linux-clean

Two things in the repository make this a from-source install rather than a port:

  • Every continuous-integration job upstream runs on ubuntu-latest. The Python backend and the React UI are tested on Linux on every commit — only the shipped installers are Mac and Windows.
  • The bootstrap script is plain python3 -m venv followed by an editable pip install. There is no Homebrew step, no macOS SDK, no code-signing step.

What is genuinely macOS- and Windows-only is the shell: the Tauri desktop window, the packaged auto-updater, and the Rust speech-to-text sidecar used for voice input. The browser UI replaces the window. It does not replace the auto-updater — update calls only do anything inside the desktop shell, so on Linux you update with git pull. Voice input is the remaining gap, and closing it is part of what pull request #19 does.

Prerequisites

  • Python 3.11+ with the venv module — see the warning below
  • Node 20+ and npm — only if you want the browser UI
  • git
  • An API key for a model provider — OpenAI, Anthropic, Google, DeepSeek, Qwen, Mistral and others are supported, or a local model through Ollama
  • Rust is not required unless you want to build the desktop window yourself

On a fresh Ubuntu or Debian box, that is:

sudo apt update
sudo apt install -y python3 python3-venv git curl
The README says 3.10+. Do not believe it on 3.10. The configuration loader imports tomllib, which only entered the standard library in Python 3.11 — but the package metadata still declares requires-python = ">=3.10", so pip installs cheerfully on 3.10 and the failure only shows up later, at import. An upstream pull request to raise the floor to 3.11 is open and unmerged. This matters most on Ubuntu 22.04 LTS, which ships Python 3.10: install 3.11 or newer first, or build the virtual environment with it explicitly. Ubuntu 24.04 (3.12) and Debian 12 (3.11) are fine as they come.
python3 --version   # must report 3.11 or higher

Step 1: Clone and bootstrap

git clone https://github.com/andrewyng/openworker
cd openworker
bash packaging/setup_dev_env.sh

The script creates a virtual environment at .venv, installs the coworker package with its messaging extras, and then imports the package once so a broken install fails loudly instead of silently. When it finishes it prints the path to the environment it just built.

It installs three commands, which is more than the README mentions:

  • openworker — the terminal agent (a TUI)
  • openworker-server — the HTTP agent server the interfaces talk to
  • openworker-connectors — a small connector utility with three subcommands: status, fake and send

Step 2: The fastest Linux path is the terminal agent

The desktop app is what Linux is missing, but it is not the only interface. The openworker command is a terminal UI over the same agent engine. It is a pure Python entry point, and the install completes on a machine with neither Node nor a Rust toolchain present — including a headless one you only ever reach over SSH:

.venv/bin/openworker                     # defaults to the "code" skill in the current directory
.venv/bin/openworker --cwd ~/projects/my-work
.venv/bin/openworker --model "openai gpt-5.5"
.venv/bin/openworker --resume <session-id>

It takes an optional skill name as its first argument, defaulting to code, plus --cwd for the workspace directory, --model for the model id, a permission mode, and --resume to pick a previous session back up. For anyone on Linux who wanted OpenWorker for the agent rather than the window, this is the whole answer — and it works over plain SSH.

Step 3: The browser UI, if you want the graphical version

First start the agent server:

.venv/bin/openworker-server --cwd ~/projects/my-work --port 8765

The --cwd value seeds the default workspace. The server also accepts --host, --model and a --mode of discuss, plan, interactive or auto, none of which the README lists. It is a normal FastAPI application served by uvicorn, and nothing in it needs a desktop session, so it runs fine over SSH on a headless box.

Then, in a second terminal, start the interface:

cd surfaces/gui
npm install
npm run dev

The dev server binds port 1420 with strictPort enabled, so it is always http://localhost:1420 — it will fail rather than drift to another port. Open that in any browser and you get the same React interface the desktop app wraps.

Start the server first. The UI reads its authentication token from a file on disk when the dev server boots. If you start the UI before the agent server, the token does not exist yet and the interface just sits in its startup retry loop. Stop it, start the server, start the UI again.

Where the token lives on Linux

A standalone server writes a per-launch token to its state directory. On Linux that directory is ~/.config/coworker, so for the default port the file is:

~/.config/coworker/sidecar-8765.token

Set COWORKER_STATE_DIR to move it somewhere else. The desktop app never writes this file — it keeps its token in memory — which is why the token file only shows up once you run the server yourself.

For direct API calls, send the value as a header:

curl -H "X-OpenWorker-Token: $(cat ~/.config/coworker/sidecar-8765.token)" \
  http://127.0.0.1:8765/v1/sessions

Browsers cannot set headers on a WebSocket, so the socket carries the same token as a WebSocket subprotocol instead. Anything you build against the API needs to handle both.

Running it on a remote Linux server

This is the step where the setup tends to fail, and the cause is not obvious from the error.

The server pins its allowed browser origins to a fixed list: tauri://localhost, tauri.localhost, http(s)://localhost and http(s)://127.0.0.1, with any port. That is a deliberate defence — it stops any random website you have open from reading your local agent's API. The side effect is that serving the UI from http://your-server-ip:1420 gives the browser an origin that is not on the list, and the requests are refused.

The fix is to keep the origin as localhost by tunnelling both ports over SSH from your own machine:

ssh -N \
  -L 8765:127.0.0.1:8765 \
  -L 1420:127.0.0.1:1420 \
  you@your-server

Then browse to http://localhost:1420 locally. The browser sees localhost, the origin check passes, and the traffic is encrypted end to end — which you want anyway, since that port speaks for an agent with shell and file access. Do not work around this by opening the port to the internet.

What you still do not get on Linux

  • No installer and no auto-updates. You update with git pull and a re-run of the bootstrap script.
  • No voice input. The speech-to-text sidecar is a Rust component built for the packaged desktop app; Linux support for it is part of the unmerged pull request #19.
  • No official Docker image. There is no Dockerfile upstream. The loudest Linux requests are for a desktop build rather than a server one, though issue #187 does ask for an official Umbrel app, which would amount to a self-hosted container package.
  • Still one user, one machine. The token is per launch and the origin allowlist is localhost-only. This is a personal tool that happens to run on Linux, not a multi-user service.

If what you actually want is an agent that never sleeps

Worth being clear about the shape of the thing: OpenWorker is local-first by design. The agent loop, your conversations, your connector tokens and your model keys all live on the machine you run it on. If that machine is a laptop that suspends when you shut it, the agent stops with it. Put openworker-server on a Linux box that stays up, as above, and it keeps running without you — it can work from Slack and run scheduled automations too. What you are signing up for then is the box: you own the updates (there is no auto-updater here), the restarts, the backups and the uptime.

If you would rather not own that, an always-on hosted agent is the shortcut. OpenClaw and Hermes are two open-source frameworks built for exactly that job, and OpenClaw Launch runs either one for you in about 30 seconds, on Linux servers, reachable from any device including the ones OpenWorker has no build for. We do not host OpenWorker itself, and this guide is the honest version of why: the local files and local apps are most of what makes it worth running, and a container of ours has neither.

For a side-by-side of the two approaches, see OpenClaw Launch vs OpenWorker.

Frequently asked questions

Is there an OpenWorker AppImage?

Not an official one. Pull request #19 adds AppImage packaging and has been open since 23 July 2026 without being merged. Until it lands, running from source is the supported path on Linux.

Does OpenWorker work on Ubuntu?

Yes. We ran the from-source install on a clean Ubuntu 24.04 image with Python 3.12.3: the bootstrap script completes and installs all three commands. Upstream continuous integration also runs on Ubuntu on every commit. What is missing on Ubuntu is the packaged desktop window, the auto-updater and voice input.

Which Python version does OpenWorker need?

3.11 or newer, despite the README saying 3.10+. The configuration loader imports tomllib, a standard-library module that only exists from 3.11, while the package metadata still declares >=3.10 — so on Python 3.10 the install succeeds and the import fails afterwards. An upstream pull request to raise the floor is open and unmerged. Ubuntu 22.04 LTS users are the ones who hit this.

Is there an OpenWorker CLI?

Yes, and it is the most useful thing on Linux. The openworker command is a terminal UI over the same agent engine, taking an optional skill name, a --cwd workspace, a --model, a permission mode and --resume for continuing a session. It needs no Node, no Rust and no desktop session. A separate openworker-connectors command offers three subcommands — status, fake and send.

Can I run OpenWorker headless?

Yes — openworker-server is a standalone process with no desktop dependency, and it authenticates with a token, so you can drive it over its HTTP API without any interface at all. Use an SSH tunnel rather than exposing the port.

Why does the UI fail when I open it by server IP?

The browser origin allowlist accepts only localhost, 127.0.0.1 and the Tauri webview origins. An IP or hostname origin is rejected by design. Tunnel ports 8765 and 1420 over SSH so your browser's origin stays localhost.

Do I need Rust to run OpenWorker on Linux?

No, not for the browser UI path. Rust is needed only to build the Tauri desktop shell and the speech-to-text sidecar.

Want an agent that runs when your laptop is shut?

Deploy an always-on OpenClaw or Hermes agent in about 30 seconds — hosted on Linux, reachable from any device, no build steps.

Deploy Now