# Technical Documentation: andrewyng/openworker > ℹ️ **Provenance:** Hybrid Fusion: `andrewyng/openworker` (README + 3 In-Tree Chapters) · [CodeWiki Reference](https://codewiki.google/github.com/andrewyng/openworker) · Recency: Active (< 180 days) ## 1. Project Overview & Quickstart (andrewyng/openworker) # OpenWorker **[openworker.com](https://openworker.com)** · [Download](#download) · [Issues](https://github.com/andrewyng/openworker/issues) [](https://trendshift.io/repositories/91434?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-91434) > **Beta** - OpenWorker is in open beta: fully usable, updates itself, and we're actively polishing rough edges. [Issues](https://github.com/andrewyng/openworker/issues) welcome. **AI that gets your everyday tasks done.** OpenWorker is an open-source AI coworker that lives on your desktop and delivers **finished work**, not just chat: a polished document, a Slack reply with the numbers, an updated calendar, a triaged inbox. It runs on your machine and doesn't lock you into any model: bring your own API key for OpenAI, Anthropic, Google, or an open-weight provider, or run fully local with Ollama. Your data leaves your machine only through the model and integrations *you* choose. [](https://openworker.com) ## Download [**⬇ macOS (Apple Silicon)**](https://download.openworker.com/mac) macOS 12+ · signed & notarized · auto-updates [**⬇ Windows 10/11 (x64)**](https://download.openworker.com/windows) builds are not yet code-signed, so SmartScreen will warn; signing is in progress Open the app, add a model key (or point it at Ollama), and ask for something real. ## How it works 1. Tell OpenWorker the outcome you want - "prepare a customer brief," "untangle my calendar," "draft a report," "check where the release stands across Jira and GitHub." 2. It breaks the task into steps and works across your desktop, files, and connected apps. 3. Before anything consequential - sending a message, changing a calendar, running a command - it checks in and you approve or redirect. 4. You get the finished deliverable, not a to-do list. Under the hood: ```text ┌────────────────────────────────────────────────┐ │ OpenWorker desktop app │ native shell + GUI ├────────────────────────────────────────────────┤ │ local agent server (Python) │ engine · tools · connectors - built on aisuite ├───────────────┬────────────────┬───────────────┤ │ your files │ your tools │ your model │ everything runs with your keys, │ & terminal │ 25+ connectors │ any provider │ on your machine └───────────────┴────────────────┴───────────────┘ ``` ## What it can do - **Produce real deliverables** - documents, spreadsheets, reports, and web pages land as files you can open and share. - **Work from Slack** - mention `@OpenWorker` in a channel; a session opens on your desktop, the work happens with your tools, and the answer comes back as a thread reply. - **Use your everyday tools** - 25+ integrations including GitHub, Slack, Jira, Notion, Linear, HubSpot, Outlook, monday.com, Gmail, and Google Calendar, plus your **terminal and local files**. Any tool reachable over [MCP](https://modelcontextprotocol.io/) plugs in too, with per-tool control. - **Run on a schedule** - automations for recurring work: a morning brief, a weekly report, a standing watch over a channel. Runs land in the app with full transcripts. - **Ask before acting** - writes, sends, and shell commands are approval-gated. Unattended runs park their asks in an inbox instead of acting on their own. ## Bring your own model Model access is yours: pick a provider, paste your key, switch anytime. Supported out of the box: **OpenAI · Anthropic · Google Gemini · Inkling (Thinking Machines) · GLM (Z.ai) · DeepSeek · Kimi (Moonshot) · Qwen · MiniMax · Mistral · Grok (xAI)** - plus open-weight models via **Together** and **Fireworks**, and fully local models via **Ollama**. A curated model list marks what we've verified for tool-calling work. Adding any model string works at your own risk. ## Privacy OpenWorker is local-first. Everything lives on your machine: the agent loop, your conversations, connector tokens, and model keys - all in the app's local secret store. The only cloud piece is a small service that brokers OAuth handshakes for connectors. You can always use the App without signing-in - use the connectors via manually-created credentials/API-keys. ## Run from source Prerequisites: Python 3.10+, Node 20+, and (for the desktop shell) the Rust toolchain via [rustup](https://rustup.rs/). ```shell git clone https://github.com/andrewyng/openworker cd openworker # 1. One-time bootstrap - creates the Python venv at .venv # (on Windows, run from Git Bash or WSL) bash packaging/setup_dev_env.sh # 2. Start the local agent server .venv/bin/openworker-server --cwd ~/some/project --port 8765 # (Windows: .venv\Scripts\openworker-server.exe) # 3. In a second terminal, start the UI cd surfaces/gui npm install npm run dev # browser UI on the Vite dev port ``` The standalone server creates a per-launch token at `/sidecar-8765.token`; Vite reads that user-only file when it starts. For direct API calls, send its value in the `X-OpenWorker-Token` header. The desktop app uses an in-memory launch token instead and never writes it to disk. To run the full desktop app instead of the browser UI, replace step 3 with `npm run tauri dev` (from `surfaces/gui/`) - the Tauri shell launches the window and supervises the server itself. Tests: `.venv/bin/pytest` (server), `npm test` and `npm run e2e` in `surfaces/gui` (GUI unit + hermetic end-to-end). Desktop bundles are built with `packaging/build_dmg.sh` / `packaging/build_windows.ps1`. ## Repository layout | Directory | What's in it | |---|---| | `coworker/` | Python backend - agent engine, model providers, connectors, MCP client, memory, automations | | `surfaces/gui/` | Desktop app - React UI + Tauri shell that supervises the server | | `stt/` | Speech-to-text sidecar (Rust) for voice input | | `packaging/` | Installer builds (macOS DMG, Windows), auto-update manifest, dev bootstrap | | `docs/` | Design specs and decision logs | | `tests/` | Backend test suite | ## Built on aisuite OpenWorker's engine is built on [**aisuite**](https://github.com/andrewyng/aisuite), a lightweight Python library providing a unified chat-completions API across LLM providers and an agents layer with tools, toolkits, and MCP support. If you want to build your own agent harness rather than use ours, start there; this repo is a working reference for what aisuite can carry. OpenWorker was originally developed inside the aisuite repository before moving to its own home here; thanks to the aisuite contributors whose work it builds on. ## Contributing Contributions and bug reports are welcome - open an [issue](https://github.com/andrewyng/openworker/issues) or a pull request. The app updates itself, so fixes reach installs quickly. For any PR, please attach screenshots of what was broken and how it is fixed now. We will shortly add features that you can contribute to. Please note that we are actively developing based off a internal list and goal, so we may not approve PRs that add features that are already under-development or deviates from our vision. ## License MIT - see [LICENSE](LICENSE). ## 2. In-Tree Documentation Chapters (andrewyng/openworker) ## File: README.md # OpenWorker **[openworker.com](https://openworker.com)** · [Download](#download) · [Issues](https://github.com/andrewyng/openworker/issues) [](https://trendshift.io/repositories/91434?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-91434) > **Beta** - OpenWorker is in open beta: fully usable, updates itself, and we're actively polishing rough edges. [Issues](https://github.com/andrewyng/openworker/issues) welcome. **AI that gets your everyday tasks done.** OpenWorker is an open-source AI coworker that lives on your desktop and delivers **finished work**, not just chat: a polished document, a Slack reply with the numbers, an updated calendar, a triaged inbox. It runs on your machine and doesn't lock you into any model: bring your own API key for OpenAI, Anthropic, Google, or an open-weight provider, or run fully local with Ollama. Your data leaves your machine only through the model and integrations *you* choose. [](https://openworker.com) ## Download [**⬇ macOS (Apple Silicon)**](https://download.openworker.com/mac) macOS 12+ · signed & notarized · auto-updates [**⬇ Windows 10/11 (x64)**](https://download.openworker.com/windows) builds are not yet code-signed, so SmartScreen will warn; signing is in progress Open the app, add a model key (or point it at Ollama), and ask for something real. ## How it works 1. Tell OpenWorker the outcome you want - "prepare a customer brief," "untangle my calendar," "draft a report," "check where the release stands across Jira and GitHub." 2. It breaks the task into steps and works across your desktop, files, and connected apps. 3. Before anything consequential - sending a message, changing a calendar, running a command - it checks in and you approve or redirect. 4. You get the finished deliverable, not a to-do list. Under the hood: ```text ┌────────────────────────────────────────────────┐ │ OpenWorker desktop app │ native shell + GUI ├────────────────────────────────────────────────┤ │ local agent server (Python) │ engine · tools · connectors - built on aisuite ├───────────────┬────────────────┬───────────────┤ │ your files │ your tools │ your model │ everything runs with your keys, │ & terminal │ 25+ connectors │ any provider │ on your machine └───────────────┴────────────────┴───────────────┘ ``` ## What it can do - **Produce real deliverables** - documents, spreadsheets, reports, and web pages land as files you can open and share. - **Work from Slack** - mention `@OpenWorker` in a channel; a session opens on your desktop, the work happens with your tools, and the answer comes back as a thread reply. - **Use your everyday tools** - 25+ integrations including GitHub, Slack, Jira, Notion, Linear, HubSpot, Outlook, monday.com, Gmail, and Google Calendar, plus your **terminal and local files**. Any tool reachable over [MCP](https://modelcontextprotocol.io/) plugs in too, with per-tool control. - **Run on a schedule** - automations for recurring work: a morning brief, a weekly report, a standing watch over a channel. Runs land in the app with full transcripts. - **Ask before acting** - writes, sends, and shell commands are approval-gated. Unattended runs park their asks in an inbox instead of acting on their own. ## Bring your own model Model access is yours: pick a provider, paste your key, switch anytime. Supported out of the box: **OpenAI · Anthropic · Google Gemini · Inkling (Thinking Machines) · GLM (Z.ai) · DeepSeek · Kimi (Moonshot) · Qwen · MiniMax · Mistral · Grok (xAI)** - plus open-weight models via **Together** and **Fireworks**, and fully local models via **Ollama**. A curated model list marks what we've verified for tool-calling work. Adding any model string works at your own risk. ## Privacy OpenWorker is local-first. Everything lives on your machine: the agent loop, your conversations, connector tokens, and model keys - all in the app's local secret store. The only cloud piece is a small service that brokers OAuth handshakes for connectors. You can always use the App without signing-in - use the connectors via manually-created credentials/API-keys. ## Run from source Prerequisites: Python 3.10+, Node 20+, and (for the desktop shell) the Rust toolchain via [rustup](https://rustup.rs/). ```shell git clone https://github.com/andrewyng/openworker cd openworker # 1. One-time bootstrap - creates the Python venv at .venv # (on Windows, run from Git Bash or WSL) bash packaging/setup_dev_env.sh # 2. Start the local agent server .venv/bin/openworker-server --cwd ~/some/project --port 8765 # (Windows: .venv\Scripts\openworker-server.exe) # 3. In a second terminal, start the UI cd surfaces/gui npm install npm run dev # browser UI on the Vite dev port ``` The standalone server creates a per-launch token at `/sidecar-8765.token`; Vite reads that user-only file when it starts. For direct API calls, send its value in the `X-OpenWorker-Token` header. The desktop app uses an in-memory launch token instead and never writes it to disk. To run the full desktop app instead of the browser UI, replace step 3 with `npm run tauri dev` (from `surfaces/gui/`) - the Tauri shell launches the window and supervises the server itself. Tests: `.venv/bin/pytest` (server), `npm test` and `npm run e2e` in `surfaces/gui` (GUI unit + hermetic end-to-end). Desktop bundles are built with `packaging/build_dmg.sh` / `packaging/build_windows.ps1`. ## Repository layout | Directory | What's in it | |---|---| | `coworker/` | Python backend - agent engine, model providers, connectors, MCP client, memory, automations | | `surfaces/gui/` | Desktop app - React UI + Tauri shell that supervises the server | | `stt/` | Speech-to-text sidecar (Rust) for voice input | | `packaging/` | Installer builds (macOS DMG, Windows), auto-update manifest, dev bootstrap | | `docs/` | Design specs and decision logs | | `tests/` | Backend test suite | ## Built on aisuite OpenWorker's engine is built on [**aisuite**](https://github.com/andrewyng/aisuite), a lightweight Python library providing a unified chat-completions API across LLM providers and an agents layer with tools, toolkits, and MCP support. If you want to build your own agent harness rather than use ours, start there; this repo is a working reference for what aisuite can carry. OpenWorker was originally developed inside the aisuite repository before moving to its own home here; thanks to the aisuite contributors whose work it builds on. ## Contributing Contributions and bug reports are welcome - open an [issue](https://github.com/andrewyng/openworker/issues) or a pull request. The app updates itself, so fixes reach installs quickly. For any PR, please attach screenshots of what was broken and how it is fixed now. We will shortly add features that you can contribute to. Please note that we are actively developing based off a internal list and goal, so we may not approve PRs that add features that are already under-development or deviates from our vision. ## License MIT - see [LICENSE](LICENSE). --- ## File: surfaces/gui/e2e/README.md # E2E tests (Playwright) End-to-end regression tests for the GUI. They drive the real app in Chromium but are **hermetic**: every `/v1` request and the event WebSocket are mocked at the network layer, so tests need **no Python backend**, run deterministically, and never mutate real state. ## Run ```bash npm run e2e # headless npm run e2e:ui # Playwright UI mode (watch/inspect) npx playwright test e2e/settings.spec.ts # a single spec ``` ## Live smoke (not CI) `npm run e2e:live` runs `e2e-live/` (separate `playwright.live.config.ts`) against the **real** backend on :8765. Two flavors, both skip cleanly when the backend is down: - **API-shape smoke** (`api-smoke.spec.ts`) — no model tokens, no creds. Asserts `/v1/health` and `/v1/providers` return the shapes the GUI reads, catching drift between the mocks and the real backend. Cheap enough to run anytime the sidecar is up. - **Full vertical** (`fib.spec.ts`, …) — asks a fresh Cowork session to produce `fib.md` and verifies the file lands on disk. Needs a model configured, is nondeterministic, and costs a few tokens per run. Exercises the vertical the hermetic specs mock: model wiring, the tool/approval loop, file I/O, and WebSocket streaming. The config (`playwright.config.ts`) starts the Vite dev server on port **5199** (dedicated, so it won't clash with a running `npm run dev` on 5173) and reuses it if already up. ## How the mock works `e2e/fixtures.ts` exports a `test` whose `page` has `mockApi()` installed before navigation: - `page.route("**/v1/**", …)` dispatches by pathname + method to fixtures whose shapes mirror the real backend (captured from a live server). Unknown endpoints return an empty-but-valid body. - Mutations are held in per-test in-memory state so they reflect through the real UI on re-fetch: sessions (archive/rename/delete), personas (enable/surface/delete — enable implies surface, matching the backend), inbox items + the routing binding, roots, channel subscriptions. - The session WebSocket (`routeWebSocket`) is a **scripted fake agent** speaking the real `{type, data}` event protocol: `ready` on connect; `user_message` → `turn_start` → deltas → `assistant_message "Echo: "` → `turn_done`; a message containing **"run a tool"** emits `tool_proposed` + `permission_required` and suspends until the client's `approval` decision arrives. This runs the production send/stream/approve code paths with zero model cost. - Seed data worth knowing: the pinned session "Draft the launch note" is the newest (boot-resume target); 7 unpinned "Weekly plan N" cowork sessions exercise the sidebar peek cap; two pending Inbox items (approval on cowork, question on ops) drive the Inbox filters; `acme-notes` is a disabled non-builtin persona for enable/delete flows. Providers are seeded in three states (OpenAI configured+used, Anthropic configured-unused, Z AI unconfigured w/ prefilled endpoint) — `POST /v1/providers` flips `configured` on save, `/verify` fails on a key containing "bad". One automation ("Daily AI News") with a running run — `POST .../run` appends a run, `PATCH`/`DELETE` toggle and remove. ## Adding a spec ```ts import { test, expect } from "./fixtures"; test("…", async ({ page }) => { await page.goto("/"); // interact + assert }); ``` If a flow reads a new endpoint, add its fixture + a route branch in `fixtures.ts` — the catch-all returns `{}`, which will crash components that expect arrays (e.g. persona `recommends`). Prefer `getByRole`, but note some controls (the Sources bar, the ✕ remove) take their accessible name from inner content — target those with `getByTitle`/`getByLabel`. ``` --- ## File: surfaces/gui/README.md # coworker GUI (React + Tauri) A thin client of the coworker server (OpenAI-compatible API + WS event/approval stream). Same codebase runs in a browser (dev) and as the OpenWorker desktop app. ## First time: bootstrap the Python backend A fresh checkout has no server to run — create the venv both flows below expect (from the repo root): ```bash bash packaging/setup_dev_env.sh # → .venv (server + aisuite) ``` ## Run it (browser, two terminals) 1. **Start the server** (needs a model key, e.g. `OPENAI_API_KEY`, in the environment — or add one later in the app's Settings), from the repo root: ```bash ./.venv/bin/openworker-server --cwd /path/to/your/project --port 8765 ``` 2. **Start the UI:** ```bash cd surfaces/gui npm install # first time npm run dev # → http://localhost:5173 ``` Open http://localhost:5173. The UI talks to `http://127.0.0.1:8765` (override with `VITE_COWORKER_HTTP` / `VITE_COWORKER_WS`). Start the server before Vite so the UI can read its per-launch token from `/sidecar-8765.token`; restart Vite if the server is restarted. ## Run the desktop app from source The Tauri shell wraps the same UI and supervises the Python server itself — no separate terminal. It needs the Rust toolchain (`rustup`) plus the venv from the bootstrap step; in dev it finds the server at `.venv/bin/openworker-server` automatically (a packaged sidecar binary is only produced by the release scripts in `packaging/`). ```bash cd surfaces/gui npm install # first time npm run tauri dev # builds the shell, launches the window, starts the server ``` ## Tests ```bash npx tsc --noEmit && npx vitest run # typecheck + unit npx playwright test # hermetic e2e (mocked /v1 + WS, no Python needed) ``` --- METRICS --- - Files Extracted: 4 - Estimated Token Budget: ~5001 tokens - Recency Window: Active (< 180 days) - Canonical Reference: https://codewiki.google/github.com/andrewyng/openworker