* fix(packaging): build pywhispercpp at the portable x86-64 baseline Every packaged channel shipped a libggml-cpu compiled for AVX2+FMA: the manylinux PyPI wheel itself carries -mavx2 -mfma -mbmi2 code, so any package that bundles it dies with SIGILL when whisper.cpp loads a model on a pre-Haswell CPU (the reporter's i5-3337U). GGML_NATIVE=OFF alone is not the portable baseline either; while the native default is on, ggml turns every GGML_* SIMD option on, so each is pinned off. - Snap: force the sdist (PIP_NO_BINARY) with the flag floor via CMAKE_ARGS in the part's build-environment. - Flatpak: extend the module's CMAKE_ARGS with the same floor. - Native .deb/.rpm: the build still vendors the wheels, then rebuilds libggml-cpu alone from the same hash-pinned sdist and swaps it into the vendored copies, asserting no AVX/FMA survives; the container image gains cmake, g++, make and binutils. - AppImage: extract the pinned-sdist reinstall into a shared helper and route every CPU-only fallback of the Vulkan path through a new baseline rebuild at the same floor; the Vulkan compile keeps its own flags via the same helper. Keeping the wheel on those paths was the bug's exact binary. Fixes #957 * style(tests): apply black/isort to the new packaging guards * fix(native): keep the wheel's libggml providers, alias its base/gomp sonames Swapping the whole libggml set for the baseline build broke the import smoke: the wheel's auditwheel-mangled core lib doubles as the extension's __cxa_call_terminate provider, and its NEEDED entries are the mangled names. Swap only libggml-cpu, and satisfy the baseline library's own unmangled NEEDEDs (libggml-base.so.0, libgomp.so.1) with aliases of the vendored copies, which carry no generated SIMD and are the same upstream version. Fail closed when the vendored set has restructured instead of silently shipping the AVX2 wheel. * fix(packaging): fail builds that lose the speech engine, unblock the ISA assert Greptile findings on the baseline work: - A failed baseline rebuild in the AppImage returned success after remove_appdir_pywhispercpp, so the bundle would ship with no speech engine at all while logging that the wheel was kept. Propagate the failure through every CPU-only fallback so the build stops instead. - The native libggml-cpu assertion used grep -q under pipefail, where grep's early exit SIGPIPEs objdump and the pipeline reports a miss, letting an AVX2 library through. Read the full disassembly instead. * fix(installer): build pywhispercpp from sdist on the CPU path install_cpu_pywhispercpp let pip pick the manylinux wheel, whose libggml-cpu is compiled for AVX2+FMA and SIGILLs on pre-Haswell CPUs (#957). Pass --no-binary pywhispercpp like the Vulkan/CUDA paths so the sdist compiles against this machine's own instruction set. * fix(installer): install C++ toolchain on distros that ship without one Forcing the pywhispercpp sdist on the CPU path needs a compiler, and the fedora, mageia, alpine, void and solus package maps did not request one. Add gcc-c++/make (rpm), build-base (alpine), base-devel (void) and gcc/g++/make (solus) so source installs compile on minimal systems. --------- Co-authored-by: Jatin K Malik <jatinkrmalik@gmail.com>
Vocalinux Flatpak Packaging
Manifest and AppStream metadata for building Vocalinux as a Flatpak.
VocaHQ remote (auto-update)
The recommended install is the self-hosted VocaHQ OSTree remote — the
Homebrew-tap analogue — which release.yml signs and publishes to
VocaHQ/vocalinux-flatpak (GitHub Pages) on every stable v* tag:
flatpak install https://vocahq.github.io/vocalinux-flatpak/com.vocalinux.Vocalinux.flatpakref
flatpak update # each new release arrives here
The .flatpakref adds the vocahq remote and resolves the GNOME runtime
through Flathub via RuntimeRepo= — the manual equivalent is remote-add
for flathub then vocahq, then flatpak install vocahq com.vocalinux.Vocalinux. Only the app is ours; org.gnome.Platform//50
still comes from Flathub. One-time repo/key setup:
docs/FLATPAK_REMOTE.md.
GitHub Release bundles
Each v* GitHub Release attaches Vocalinux-<version>-x86_64.flatpak and
Vocalinux-<version>-aarch64.flatpak as a no-remote fallback:
# once: Flathub remote + GNOME runtime (the app itself is not on Flathub)
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
flatpak install flathub org.gnome.Platform//50
flatpak install --user ./Vocalinux-<version>-x86_64.flatpak
flatpak run com.vocalinux.Vocalinux
Bundles do not auto-update — the VocaHQ remote above is the path for
that. Vocalinux is not on Flathub (submission
flathub/flathub#9368 closed on
policy grounds; we are not re-submitting). Local flatpak-builder remains for
contributors (below).
Current Scope
The manifest ships the default whisper_cpp engine only. VOSK is omitted because
the PyPI package is wheel-only (no sdist), so a Flathub-ready VOSK build would
need to compile VOSK and its native deps from source.
Global keyboard shortcuts use evdev (/dev/input).
Text injection prefers the RemoteDesktop portal
(org.freedesktop.portal.RemoteDesktop NotifyKeyboardKeysym — keysyms, so
non-US layouts survive) and falls back to wl-copy + ydotool Ctrl+V
(instant paste into native Wayland apps) when the portal is unavailable.
Character-by-character ydotool type is only a fallback. xdotool remains
for pure X11/XWayland clients.
Permissions: --socket=wayland (clipboard), --socket=x11 (xdotool fallback),
--device=all (evdev hotkeys + uinput for the ydotool fallback; Flatpak has
no narrower uinput flag).
Local Build
# one-time runtime/SDK
flatpak install flathub org.gnome.Platform//50 org.gnome.Sdk//50
# from repo root — add flags as needed:
# --user --install install for the current user
# --repo=repo export a local repo (then bundle or lint)
# --compose-url-policy=full --mirror-screenshots-url=https://dl.flathub.org/media
flatpak-builder --force-clean build-dir packaging/flatpak/com.vocalinux.Vocalinux.yml
flatpak run com.vocalinux.Vocalinux --debug
# single-file bundle (after a --repo=repo build)
flatpak build-bundle repo vocalinux.flatpak com.vocalinux.Vocalinux
# elsewhere: flatpak install --user vocalinux.flatpak
Lint (needs org.flatpak.Builder):
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest packaging/flatpak/com.vocalinux.Vocalinux.yml
flatpak run --command=flatpak-builder-lint org.flatpak.Builder builddir build-dir
flatpak run --command=flatpak-builder-lint org.flatpak.Builder repo repo # if you used --repo=repo
Prefer flatpak run after --install for GUI testing. On GNOME runtimes with
glycin loaders, flatpak-builder --run can fail to load themed SVG icons for an
uninstalled stable app ID; it is still fine for non-GUI smokes:
flatpak-builder --run build-dir packaging/flatpak/com.vocalinux.Vocalinux.yml \
python3 -c 'from pywhispercpp.model import Model; print("pywhispercpp ok")'
Python Dependencies
python3-dependencies.yaml is generated from requirements/runtime.txt, the
hash-pinned export just lock writes out of uv.lock. Refresh it whenever the
dependency set changes:
just flatpak-deps # rewrite the manifest (needs PyPI)
just flatpak-deps-check # report drift, change nothing
just lock runs the first of those itself, so a normal dependency change needs
no extra step.
The script resolves each package's URL by looking up the digest uv already
recorded, so the bytes this build downloads are the bytes in uv.lock, not
merely the same version number. It takes a universal wheel where one exists and
the sdist otherwise; an ABI-tagged wheel would pin the build to one SDK Python.
This replaced a flatpak-pip-generator invocation whose package list was typed
out on the command line. Nothing regenerated it and no test compared it to
anything, so it drifted: by 2026-09-10 ten of its fifteen shared packages were
behind the lock, pydub and lxml were still built four months after #705
deleted them for having no imports, and pywhispercpp sat at 1.4.1 under the
project's own >=1.5.0. The project is installed here with
pip3 install --no-deps, so nothing inside the build could notice.
tests/test_flatpak_packaging.py is what notices now, and it runs offline.
Two things in that file are hand-written and the script preserves them, because
no generator produces them: pywhispercpp's Vulkan build, which injects a version
into setup.py (the sdist ships no version.txt, setup() takes no version=
argument, and setuptools-scm has no git tree to read in the sandbox), and the
symlinking of whisper.cpp's shared libraries onto the loader path.
python3-build-dependencies.yaml is a small hand-maintained helper so
--no-build-isolation builds can import mesonpy before NumPy is built.
Channel: VocaHQ remote + GitHub Releases, not Flathub
Flathub is not pursued. The submission,
flathub/flathub#9368, was closed
on 2026-07-23 on policy grounds. See
#167 for the channel decision,
#784 for release bundles, and
#785 for the self-hosted
remote. Do not re-submit. The vocahq remote, local builds, and GitHub
Release .flatpak assets are the supported paths.
Manifest Details
- Runtime / SDK:
org.gnome.Platform//50,org.gnome.Sdk//50 - Mic:
--socket=pulseaudio· GPU:--device=dri· models:--share=network - Input:
--device=all(evdev hotkeys + ydotool/uinputfallback) - Injection: RemoteDesktop portal first; packaged
wl-copy,ydotool/ydotoold, plusxdotool/xselfallback - Display:
--socket=wayland(clipboard) and--socket=x11(xdotool fallback) - IBus:
--talk-name=org.freedesktop.IBus - Tray:
--talk-name=org.kde.StatusNotifierWatcher
Config and models use Flatpak XDG dirs under ~/.var/app/com.vocalinux.Vocalinux/.