Skip to content

Add initial Linux desktop packaging support - #551

Closed
luislobo wants to merge 1 commit into
andrewyng:mainfrom
luislobo:initial-linux-support
Closed

Add initial Linux desktop packaging support#551
luislobo wants to merge 1 commit into
andrewyng:mainfrom
luislobo:initial-linux-support

Conversation

@luislobo

@luislobo luislobo commented Aug 25, 2026

Copy link
Copy Markdown

Summary

  • add an apt-based Linux desktop dependency installer for Ubuntu/Debian Tauri builds
  • add a Linux packaging script that bundles the Python sidecar from the repo .venv and builds Tauri Linux bundles
  • align the dev venv bootstrap with documented tests and packaging by installing bedrock, PyInstaller, typer, and tzdata
  • fix Linux .deb sidecar resolution so installed apps use /usr/lib/OpenWorker/sidecar before falling back to the source .venv
  • document Linux setup and record the local/VM smoke test findings

Linux notes

  • Linux desktop builds require WebKit/Tauri native packages such as libsoup-3.0-dev, libwebkit2gtk-4.1-dev, libayatana-appindicator3-dev, libclang-dev, and cmake.
  • The Linux packaging script defaults ggml/whisper.cpp CPU feature flags to portable values. This avoids building an app tied to the build host CPU and fixes a clean VM case where AVX2 was exposed without FMA.
  • Remaining known Linux limits: voice input is explicitly unsupported on Linux, keep-awake is a no-op on Linux, and official update/download manifest handling still only covers macOS/Windows.

Verification

  • Local Ubuntu 24.04.4: full backend suite passed after adding bedrock deps: 1,861 passed, 1 skipped.
  • Local Ubuntu 24.04.4: GUI unit tests passed: 134 tests.
  • Local Ubuntu 24.04.4: GUI E2E passed on Chromium: 221 tests.
  • Clean Ubuntu 24.04 VM via Vagrant: setup_dev_env, selected backend tests, npm install, GUI unit tests, Vite build, and packaging/build_linux.sh deb all passed.
  • Clean VM produced: surfaces/gui/src-tauri/target/release/bundle/deb/OpenWorker_0.2.1_amd64.deb.
  • Local host: installed the rebuilt .deb with apt and launched /usr/bin/openworker-desktop from /tmp.
  • Local host: installed app spawned /usr/lib/OpenWorker/sidecar/openworker-server and loaded health/settings/sessions/personas plus websocket endpoints.

Commands run

  • bash -n packaging/setup_dev_env.sh && bash -n packaging/install_linux_desktop_deps.sh && bash -n packaging/build_linux.sh && git diff --check
  • .venv/bin/pytest tests/test_config.py tests/test_environment.py tests/test_bedrock_provider.py -q
  • npm test -- --run
  • Vagrant Ubuntu 24.04 clean smoke: bash packaging/setup_dev_env.sh; selected pytest; npm install; npm test -- --run; npm run build; packaging/build_linux.sh deb
  • bash packaging/install_linux_desktop_deps.sh
  • bash packaging/setup_dev_env.sh; npm install; packaging/build_linux.sh deb
  • sudo apt-get install -y ./surfaces/gui/src-tauri/target/release/bundle/deb/OpenWorker_0.2.1_amd64.deb
  • RUST_BACKTRACE=1 RUST_LOG=debug /usr/bin/openworker-desktop

@luislobo
luislobo marked this pull request as draft August 25, 2026 22:28
@luislobo
luislobo force-pushed the initial-linux-support branch from 4e4de2f to 9509d17 Compare August 25, 2026 22:37
@hughsheehy

Copy link
Copy Markdown

Nice work on this — I independently built basically the same thing (a build_linux.sh that creates deb and appimage) on my own Ubuntu box before finding this PR, I suspect yours is more complete than mine.

One thing I did tackle that's flagged here as a known gap: voice input. It was gated to macOS/Windows only, but the underlying engine (cpal/ALSA + whisper-rs) is already cross-platform — un-gating voice_input_compatibility() for Linux was a small change, and I've confirmed it working end-to-end (model download, mic capture, dictation) on Ubuntu. Happy to open that as a small follow-up PR once this one lands, if useful.

If anyone wants to try a Linux build in the meantime: .deb/AppImage on my fork (unofficial, built from this same idea + the voice un-gating).

@luislobo
luislobo force-pushed the initial-linux-support branch from 9509d17 to 1e025ba Compare September 1, 2026 20:30
@luislobo

luislobo commented Sep 1, 2026

Copy link
Copy Markdown
Author

@hughsheehy Thanks — and sorry for the slow reply. Yes please, that follow-up would be very welcome.

Your read on the voice gating matches what I found: ocw-stt has no platform gating at all (stt/src/lib.rs only has a #[cfg(test)]), and both cpal and whisper-rs are already cross-platform, so the only thing keeping Linux out is the hardcoded false in the #[cfg(not(any(target_os = "macos", target_os = "windows")))] arm of voice_input_compatibility() in surfaces/gui/src-tauri/src/lib.rs. Nice that you confirmed it end-to-end on Ubuntu rather than just assuming ALSA would behave.

I'm deliberately keeping this PR scoped to packaging only so the review surface stays small — a build script plus the .deb sidecar path fix is a much easier thing for a maintainer to say yes to than packaging plus a behavior change. So the un-gating is yours; please open it as a separate PR whenever suits you, either after this lands or in parallel if you'd rather not wait. Happy to review and test it on my side when you do.

One thing worth carrying over into that PR: voice_input_compatibility() returns a (supported, device_summary, compatibility_reason) triple, and the macOS/Windows arms both do a real capability check (Apple Silicon + macOS 12+, x64 + build 19045+) rather than returning a flat true. It'd be good if the Linux arm did something equivalent — at minimum reporting whether an input device actually enumerates, so a machine with no working ALSA/PulseAudio capture device gets a useful compatibility_reason instead of a failure at record time.

I've just rebased this onto current main (it had drifted 33 commits behind) and taken it out of draft. Note the CI run here is sitting at action_required, which is the first-time-contributor approval gate rather than a real failure — it needs a maintainer to approve the workflow run before anything actually executes.

@luislobo
luislobo marked this pull request as ready for review September 1, 2026 20:30
@luislobo

luislobo commented Sep 1, 2026

Copy link
Copy Markdown
Author

@hughsheehy — quick heads-up before you put time into that follow-up, because I'd rather point you at this than have you redo it.

I went through the other open Linux PRs and #19 (@rmanicardi, opened 2026-07-23) already does the voice un-gating, and does it well. It replaces the #[cfg(not(any(target_os = "macos", target_os = "windows")))] arm of voice_input_compatibility() with a runtime cpal probe for a reachable input device, so voice is offered on Linux desktops with audio and cleanly disabled on headless boxes, containers without ALSA, and WSL without an audio sink — rather than a flat true. It also replaces the Linux keep-awake no-op with a real systemd-inhibit --mode=block guard, which is a gap I'd listed as a known limit in my own report and hadn't touched.

That's essentially the note I left above about doing a real capability check, already implemented. It's been sitting unreviewed since July, which is probably just the same review backlog everything Linux-related here is stuck in.

So I think your end-to-end Ubuntu confirmation is worth more aimed at #19 than at a new PR: a second person saying "I built this and dictation works — model download, mic capture, the lot" on an unreviewed seven-week-old PR is harder to ignore than a fourth PR touching the same lines. If you find gaps in it, that's useful too.

Related, there's a consolidation thread on #171 about which of #19 / #173 / #470 / #551 should be the base for Linux support — worth weighing in there if you have a view, since you've actually run this stuff.

@luislobo

luislobo commented Sep 1, 2026

Copy link
Copy Markdown
Author

Closing this in favour of @Nikish-codes's #470, which is the better base.

I built the AppImage from this branch today and found that my sidecar fix doesn't work for AppImage. It resolves the absolute path /usr/lib/OpenWorker/sidecar, which is correct for an installed .deb and wrong inside an AppImage, where the payload sits at $APPDIR/usr/lib/... beneath a /tmp/.mount_XXXXXX prefix. Every candidate the resolver tries misses, and it falls through to the CARGO_MANIFEST_DIR dev fallback that gets baked into the binary at compile time — so the shipped artifact points at a path in my home directory and stalls at "Starting coworker…" anywhere else. #470 resolves via Tauri's resource_dir(), which is correct across deb/rpm/AppImage.

#470 is also distro-aware in its dependency installer where this PR is apt-only, and it's been independently verified on Fedora 44 by @marbetschar. @niutech suggested on #173 that it was superseded by #470 — that's one reader's read rather than its author standing down — but consolidating on #470 still looks like the right move to me.

The one piece of this PR that #470 lacks — defaulting the GGML_* CPU flags to a portable build, after a clean VM exposed avx2 without fma and broke the whisper.cpp compile — I've sent over as Nikish-codes#2. The full reasoning and my recommendation for the base are on #171.

@hughsheehy — thanks again for the offer here, and sorry to close the PR you commented on. Nothing is lost: #19 already does the voice un-gating you described, and your end-to-end Ubuntu confirmation is worth more there than it was here. #470 for packaging, #19 for voice.

@luislobo luislobo closed this Sep 1, 2026
@luislobo
luislobo deleted the initial-linux-support branch September 1, 2026 23:33
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.

3 participants