* feat(desktop): migration engine for Tauri → Electron handoff
Implements the infrastructure needed to move users from Tauri to Electron
without losing state or Launchpad/Dock presence. Zero user impact on its
own — this becomes live only when paired with a final Tauri release that
calls the snapshot writer and installs Electron.
What lands here:
- Unify app identity with Tauri. electron-builder appId goes from
com.differentai.openwork.electron → com.differentai.openwork so macOS
reuses the same bundle identifier (no duplicate Dock icon, no new
Gatekeeper prompt, same TCC permissions).
- Unify userData path. Electron's app.setPath("userData", ...) now points
at the exact folder Tauri uses (~/Library/Application Support/com.differentai.openwork
on macOS, %APPDATA%/com.differentai.openwork on Windows, ~/.config/
com.differentai.openwork on Linux). An OPENWORK_ELECTRON_USERDATA env
var override is available for dogfooders who want isolation.
- Filename compat. On first launch, Electron copies Tauri's
openwork-workspaces.json → workspace-state.json (leaves the legacy
file in place for rollback safety).
- electron-updater wiring. New deps + IPC handlers
(openwork:updater:check / download / installAndRestart). Packaged-only.
Publish config points at the same GitHub release as Tauri.
- Migration snapshot plumbing.
* Tauri Rust command `write_migration_snapshot` serializes an
allowlist of localStorage keys to app_data_dir/migration-snapshot.v1.json.
* `apps/app/src/app/lib/migration.ts` has matching
writeMigrationSnapshotFromTauri() / ingestMigrationSnapshotOnElectronBoot().
* Scope: workspace list + selection only
(openwork.react.activeWorkspace, .sessionByWorkspace,
openwork.server.list/active/urlOverride/token). Everything else is
cheap to redo.
* Electron main exposes openwork:migration:read / ack IPC; preload
bridges them under window.__OPENWORK_ELECTRON__.migration.
* desktop-runtime-boot.ts ingests the snapshot once on first launch,
hydrates empty localStorage keys, then acks.
- Updated prds/electron-migration-plan.md with the localStorage scope
decision and the remaining work (last Tauri release ships the UI
prompt + installer downloader).
Verified: `pnpm --filter @openwork/app typecheck` ✓,
`pnpm --filter @openwork/desktop build:electron` ✓, `cargo check`
against src-tauri ✓.
* fix(desktop): emit relative asset paths for Electron packaged builds
Packaged Electron loads index.html via file:// (Contents/Resources/app-dist/
index.html inside the .app bundle), but Vite was building with the default
base: '/' which resolves /assets/*.js to the filesystem root. Result: a
working dev experience (Vite dev server on localhost:5173) and a broken
packaged .app that renders an empty <div id="root"></div>.
The Tauri shell doesn't hit this because Tauri serves the built HTML
through its own tauri:// protocol which rewrites paths. Electron's
file:// loader has no such rewriter.
Fix: electron-build.mjs sets OPENWORK_ELECTRON_BUILD=1 when invoking
vite build, and vite.config.ts flips base to './' only when that env
var is set. Dev server and Tauri builds unchanged.
Discovered while manually exercising the Electron prod-build migration
flow (packaged app launch, snapshot ingest, idempotency, updater IPC).
Latent since PR #1522 landed the packaged build path; never caught
because dogfood ran via dev:electron which uses the Vite dev server.
---------
Co-authored-by: Benjamin Shafii <benjamin@openworklabs.com>
OpenWork is the open source alternative to Claude Cowork/Codex (desktop app).
Core Philosophy
- Local-first, cloud-ready: OpenWork runs on your machine in one click. Send a message instantly.
- Composable: desktop app, Slack/Telegram connector, or server. Use what fits, no lock-in.
- Ejectable: OpenWork is powered by OpenCode, so everything OpenCode can do works in OpenWork, even without a UI yet.
- Sharing is caring: start solo on localhost, then explicitly opt into remote sharing when you need it.
OpenWork is designed around the idea that you can easily ship your agentic workflows for your team as a repeatable, productized process.
Tip
Looking for an Enterprise Plan? Speak with our Sales Team today
Get enhanced capabilities including feature prioritization, SSO, SLA support, LTS versions, and more.
Alternate UIs
- OpenWork Orchestrator (CLI host): run OpenCode + OpenWork server without the desktop UI.
- install:
npm install -g openwork-orchestrator - run:
openwork start --workspace /path/to/workspace --approval auto - docs: apps/orchestrator/README.md
- install:
Quick start
Download the desktop app from openworklabs.com/download, grab the latest GitHub release, or install from source below.
- macOS and Linux downloads are available directly.
- Windows access is currently handled through the paid support plan on openworklabs.com/pricing#windows-support.
- Hosted OpenWork Cloud workers are launched from the web app after checkout, then connected from the desktop app via
Add a worker->Connect remote.
Why
Current CLI and GUIs for opencode are anchored around developers. That means a focus on file diffs, tool names, and hard to extend capabilities without relying on exposing some form of cli.
OpenWork is designed to be:
- Extensible: skill and opencode plugins are installable modules.
- Auditable: show what happened, when, and why.
- Permissioned: access to privileged flows.
- Local/Remote: OpenWork works locally as well as can connect to remote servers.
What’s Included
- Host mode: runs opencode locally on your computer
- Client mode: connect to an existing OpenCode server by URL.
- Sessions: create/select sessions and send prompts.
- Live streaming: SSE
/eventsubscription for realtime updates. - Execution plan: render OpenCode todos as a timeline.
- Permissions: surface permission requests and reply (allow once / always / deny).
- Templates: save and re-run common workflows (stored locally).
- Debug exports: copy or export the runtime debug report and developer log stream from Settings -> Debug when you need to file a bug.
- Skills manager:
- list installed
.opencode/skillsfolders - import a local skill folder into
.opencode/skills/<skill-name>
- list installed
Skill Manager
Works on local computer or servers
Quick Start
Requirements
- Node.js +
pnpm - Rust toolchain (for Tauri): install via
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - Tauri CLI:
cargo install tauri-cli - OpenCode CLI installed and available on PATH:
opencode
Local Dev Prerequisites (Desktop)
Before running pnpm dev, ensure these are installed and active in your shell:
- Node + pnpm (repo uses
pnpm@10.27.0) - Bun 1.3.9+ (
bun --version) - Rust toolchain (for Tauri), with Cargo from current
rustupstable (supportsCargo.lockv4) - Xcode Command Line Tools (macOS)
- On Linux, WebKitGTK 4.1 development packages so
pkg-configcan resolvewebkit2gtk-4.1andjavascriptcoregtk-4.1
One-minute sanity check
Run from repo root:
git checkout dev
git pull --ff-only origin dev
pnpm install --frozen-lockfile
which bun
bun --version
pnpm --filter @openwork/desktop exec tauri --version
Install
pnpm install
OpenWork now lives in apps/app (UI) and apps/desktop (desktop shell).
Run (Desktop)
pnpm dev
pnpm dev now enables OPENWORK_DEV_MODE=1 automatically, so desktop dev uses an isolated OpenCode state instead of your personal global config/auth/data.
Run (Web UI only)
pnpm dev:ui
All repo dev entrypoints now opt into the same dev-mode isolation so local testing uses the OpenWork-managed OpenCode state consistently.
Arch Users:
sudo pacman -S --needed webkit2gtk-4.1
curl -fsSL https://opencode.ai/install | bash -s -- --version "$(node -e "const fs=require('fs'); const parsed=JSON.parse(fs.readFileSync('constants.json','utf8')); process.stdout.write(String(parsed.opencodeVersion||'').trim().replace(/^v/,''));")" --no-modify-path
Architecture (high-level)
- In Host mode, OpenWork runs a local host stack and connects the UI to it.
- Default runtime:
openwork(installed fromopenwork-orchestrator), which orchestratesopencode,openwork-server, and optionallyopencode-router. - Fallback runtime:
direct, where the desktop app spawnsopencode serve --hostname 127.0.0.1 --port <free-port>directly.
- Default runtime:
When you select a project folder, OpenWork runs the host stack locally using that folder and connects the desktop UI. This lets you run agentic workflows, send prompts, and see progress entirely on your machine without a remote server.
- The UI uses
@opencode-ai/sdk/v2/clientto:- connect to the server
- list/create sessions
- send prompts
- subscribe to SSE events(Server-Sent Events are used to stream real-time updates from the server to the UI.)
- read todos and permission requests
Folder Picker
The folder picker uses the Tauri dialog plugin. Capability permissions are defined in:
apps/desktop/src-tauri/capabilities/default.json
OpenCode Plugins
Plugins are the native way to extend OpenCode. OpenWork now manages them from the Skills tab by
reading and writing opencode.json.
- Project scope:
<workspace>/opencode.json - Global scope:
~/.config/opencode/opencode.json(or$XDG_CONFIG_HOME/opencode/opencode.json)
You can still edit opencode.json manually; OpenWork uses the same format as the OpenCode CLI:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-wakatime"]
}
Useful Commands
pnpm dev
pnpm dev:ui
pnpm typecheck
pnpm build
pnpm build:ui
pnpm test:e2e
Troubleshooting
If you need to report a desktop or session bug, open Settings -> Debug and export both the runtime debug report and developer logs before filing an issue.
Linux / Wayland (Hyprland)
If OpenWork crashes on launch with WebKitGTK errors like Failed to create GBM buffer, disable dmabuf or compositing before launch. Try one of the following environment flags.
WEBKIT_DISABLE_DMABUF_RENDERER=1 openwork
WEBKIT_DISABLE_COMPOSITING_MODE=1 openwork
Security Notes
- OpenWork hides model reasoning and sensitive tool metadata by default.
- Host mode binds to
127.0.0.1by default.
Contributing
- Review
AGENTS.mdplusVISION.md,PRINCIPLES.md,PRODUCT.md, andARCHITECTURE.mdto understand the product goals before making changes. - Ensure Node.js,
pnpm, the Rust toolchain, andopencodeare installed before working inside the repo. - Run
pnpm installonce per checkout, then verify your change withpnpm typecheckpluspnpm test:e2e(or the targeted subset of scripts) before opening a PR. - Use
.github/pull_request_template.mdwhen opening PRs and include exact commands, outcomes, manual verification steps, and evidence. - If CI fails, classify failures in the PR body as either code-related regressions or external/environment/auth blockers.
- Add new PRDs to
apps/app/pr/<name>.mdfollowing the.opencode/skills/prd-conventions/SKILL.mdconventions described inAGENTS.md.
Community docs:
CODE_OF_CONDUCT.mdSECURITY.mdSUPPORT.mdTRIAGE.md
First contribution checklist:
- Run
pnpm installand baseline verification commands. - Confirm your change has a clear issue link and scope.
- Add/update tests for behavioral changes.
- Include commands run and outcomes in your PR.
- Add screenshots/video for user-facing flow changes.
Supported Languages
Translated READMEs: translated_readmes/, available in English, 简体中文, 繁體中文, 日本語.
The App is available in the following languages: English (en), Japanese (ja), Simplified Chinese (zh), Vietnamese (vi), Brazilian Portuguese (pt-BR).
For Teams & Businesses
Interested in using OpenWork in your organization? We'd love to hear from you — reach out at ben@openworklabs.com to chat about your use case.
License
MIT — see LICENSE.
