From da0f45afb78abb845f1b9e507fe6e1d69f58ba38 Mon Sep 17 00:00:00 2001 From: ironbract Date: Tue, 25 Aug 2026 20:58:53 -0400 Subject: [PATCH 01/15] Offer a source-build fallback when Voxtype's binary needs AVX2 voxtype-bin targets the x86-64-v3 baseline (AVX2, FMA, BMI1/2, F16C, MOVBE), so it SIGILLs on older CPUs. The install hook had no capability check, so it always installed the incompatible binary and, on any post-install failure, left a half-installed package behind with set -e. Add omarchy-hw-x86-64-v3 to detect the baseline, gate the install on it, and offer to build the AUR voxtype package from source instead (with a warning about build time and possible performance). Roll back via omarchy-voxtype-remove if setup fails partway through instead of abandoning a broken install. Fixes #8312 Co-Authored-By: Claude Sonnet 5 --- bin/omarchy-hw-x86-64-v3 | 12 +++ bin/omarchy-voxtype-install | 56 ++++++++--- bin/omarchy-voxtype-remove | 6 +- manual/11-text-extraction-dictation.md | 2 + test/shell.d/hw-x86-64-v3-test.sh | 46 +++++++++ test/shell.d/voxtype-install-test.sh | 126 +++++++++++++++++++++++++ 6 files changed, 233 insertions(+), 15 deletions(-) create mode 100755 bin/omarchy-hw-x86-64-v3 create mode 100755 test/shell.d/hw-x86-64-v3-test.sh create mode 100755 test/shell.d/voxtype-install-test.sh diff --git a/bin/omarchy-hw-x86-64-v3 b/bin/omarchy-hw-x86-64-v3 new file mode 100755 index 00000000000..1e120e23dad --- /dev/null +++ b/bin/omarchy-hw-x86-64-v3 @@ -0,0 +1,12 @@ +#!/bin/bash + +# omarchy:summary=Detect whether the CPU supports the x86-64-v3 baseline (AVX2, FMA, BMI1, BMI2, F16C, MOVBE). + +[[ $(uname -m) == "x86_64" ]] || exit 0 + +cpuinfo=${OMARCHY_CPUINFO_PATH:-/proc/cpuinfo} +flags=" $(grep -m1 "^flags" "$cpuinfo" 2>/dev/null | cut -d: -f2) " + +for flag in avx2 fma bmi1 bmi2 f16c movbe; do + [[ $flags == *" $flag "* ]] || exit 1 +done diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index 1fd19f9de6d..7500f2b8ca8 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -3,24 +3,54 @@ # omarchy:summary=Install and configure Voxtype dictation # omarchy:requires-sudo=true -set -e - # Install voxtype and configure it for use. if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then - omarchy-pkg-add wtype voxtype-bin + omarchy-pkg-add wtype || exit 1 - # Setup voxtype - mkdir -p ~/.config/voxtype - cp "$OMARCHY_PATH/default/voxtype/config.toml" ~/.config/voxtype/ + voxtype_pkg=voxtype-bin + if ! omarchy-hw-x86-64-v3; then + gum style --foreground 3 \ + "Your CPU is missing instructions (AVX2/x86-64-v3) that the prebuilt Voxtype binary requires." - voxtype setup --download --no-post-install - if omarchy-hw-vulkan; then - voxtype setup gpu --enable || true + if gum confirm "Build Voxtype from source instead? This can take 20+ minutes and may result in noticeably slower dictation on this CPU."; then + if ! omarchy-pkg-aur-accessible; then + gum style --foreground 1 "The AUR is unreachable right now, so Voxtype can't be built from source. Try again later." + exit 1 + fi + voxtype_pkg=voxtype + else + echo "Skipping Voxtype install." + exit 0 + fi fi - voxtype setup systemd - hyprctl reload >/dev/null - omarchy-restart-shell - omarchy-notification-send -g  "Voxtype Dictation Ready" "Hold F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000 + if [[ $voxtype_pkg == voxtype-bin ]]; then + omarchy-pkg-add voxtype-bin || exit 1 + else + omarchy-pkg-aur-add voxtype || exit 1 + fi + + # Setup voxtype + install_voxtype() { + mkdir -p ~/.config/voxtype + cp "$OMARCHY_PATH/default/voxtype/config.toml" ~/.config/voxtype/ || return 1 + + voxtype setup --download --no-post-install || return 1 + if omarchy-hw-vulkan; then + voxtype setup gpu --enable || true + fi + voxtype setup systemd || return 1 + + hyprctl reload >/dev/null + omarchy-restart-shell + } + + if install_voxtype; then + omarchy-notification-send -g "Voxtype Dictation Ready" "Hold F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000 + else + gum style --foreground 1 "Voxtype setup failed. Rolling back the install." + omarchy-voxtype-remove + exit 1 + fi fi diff --git a/bin/omarchy-voxtype-remove b/bin/omarchy-voxtype-remove index 08634e60e25..16872e3f4ee 100755 --- a/bin/omarchy-voxtype-remove +++ b/bin/omarchy-voxtype-remove @@ -14,8 +14,10 @@ if omarchy-cmd-present voxtype; then systemctl --user disable --now voxtype.service 2>/dev/null || true systemctl --user daemon-reload - # Remove packages and configs - omarchy-pkg-drop voxtype-bin + # Remove packages and configs. voxtype-bin is the prebuilt binary; voxtype + # is the cargo-built fallback offered on CPUs without the AVX2/x86-64-v3 + # instructions voxtype-bin requires. Only one of the two is ever installed. + omarchy-pkg-drop voxtype-bin voxtype rm -rf ~/.config/voxtype rm -rf ~/.local/share/voxtype hyprctl reload >/dev/null diff --git a/manual/11-text-extraction-dictation.md b/manual/11-text-extraction-dictation.md index 2d222a67631..5bc21d88e92 100644 --- a/manual/11-text-extraction-dictation.md +++ b/manual/11-text-extraction-dictation.md @@ -12,4 +12,6 @@ This is very helpful for grabbing addresses out of image footers or phone number Omarchy offers AI dictation via [Voxtype](https://voxtype.io/). You install it via _Install > AI > Dictation_ through the Omarchy menu. By default, it'll load a base English model that takes up 150MB. But you can tweak which model you'd like to use by running `voxtype setup model` in the terminal. And you can tweak all the settings via `~/.config/voxtype/config.toml`. +The prebuilt Voxtype binary requires a CPU with the x86-64-v3 instruction baseline (AVX2, FMA, BMI1/2, F16C, MOVBE — Haswell-era or newer, roughly 2013+). On older CPUs, the installer offers to build Voxtype from source via the AUR instead; this takes 20+ minutes and may run noticeably slower. + Once installed, you dictate by holding down `F9` or by toggling with `Super + Ctrl + X`, and the dictated text will appear in the focused input area. diff --git a/test/shell.d/hw-x86-64-v3-test.sh b/test/shell.d/hw-x86-64-v3-test.sh new file mode 100755 index 00000000000..a4dfec75888 --- /dev/null +++ b/test/shell.d/hw-x86-64-v3-test.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +tmp_dir=$(mktemp -d) +trap 'rm -rf "$tmp_dir"' EXIT + +write_cpuinfo_flags() { + printf 'flags\t\t: %s\n' "$1" >"$tmp_dir/cpuinfo" +} + +hw_x86_64_v3() { + OMARCHY_CPUINFO_PATH="$tmp_dir/cpuinfo" "$ROOT/bin/omarchy-hw-x86-64-v3" +} + +assert_detects() { + local description="$1" + + hw_x86_64_v3 || fail "$description" + pass "$description" +} + +assert_rejects() { + local description="$1" + + if hw_x86_64_v3; then + fail "$description" + fi + pass "$description" +} + +# Ivy Bridge (e.g. i7-3520M): has AVX but not AVX2/BMI/FMA. +write_cpuinfo_flags "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf tsc_known_freq pni pclmulqdq est ssse3 fma cx16 sse4_1 sse4_2 popcnt aes xsave avx f16c rdrand hypervisor lahf_lm" +assert_rejects "Ivy Bridge without AVX2/BMI1/BMI2 does not satisfy x86-64-v3" + +# Haswell and newer: full x86-64-v3 baseline. +write_cpuinfo_flags "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm abm avx2 bmi1 bmi2" +assert_detects "Haswell with the full x86-64-v3 baseline satisfies it" + +write_cpuinfo_flags "fpu vme de pse tsc msr avx avx2" +assert_rejects "AVX2 alone without FMA/BMI1/BMI2/F16C/MOVBE does not satisfy x86-64-v3" + +: >"$tmp_dir/cpuinfo" +assert_rejects "empty cpuinfo does not satisfy x86-64-v3" diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh new file mode 100755 index 00000000000..bd3a0a19f9d --- /dev/null +++ b/test/shell.d/voxtype-install-test.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +source "$(dirname "$0")/base-test.sh" + +test_home=$(mktemp -d) +test_bin=$(mktemp -d) +test_omarchy_path=$(mktemp -d) +log_file=$(mktemp) +confirm_queue=$(mktemp) + +cleanup() { + rm -rf "$test_home" "$test_bin" "$test_omarchy_path" + rm -f "$log_file" "$confirm_queue" +} +trap cleanup EXIT + +mkdir -p "$test_omarchy_path/default/voxtype" +echo "# stub config" >"$test_omarchy_path/default/voxtype/config.toml" + +# gum answers confirm prompts in order from confirm_queue (one "yes"/"no" per +# line), and no-ops for every other subcommand (style, etc.). +cat >"$test_bin/gum" <<'EOF' +#!/bin/bash +if [[ $1 == "confirm" ]]; then + echo "confirm:$2" >>"$TEST_LOG" + answer=$(head -n1 "$CONFIRM_QUEUE") + sed -i '1d' "$CONFIRM_QUEUE" + [[ $answer == "yes" ]] + exit $? +fi +exit 0 +EOF +chmod +x "$test_bin/gum" + +for cmd in omarchy-pkg-add omarchy-pkg-aur-add omarchy-restart-shell omarchy-notification-send omarchy-voxtype-remove; do + cat >"$test_bin/$cmd" <>"\$TEST_LOG" +EOF + chmod +x "$test_bin/$cmd" +done + +cat >"$test_bin/hyprctl" <<'EOF' +#!/bin/bash +exit 0 +EOF +chmod +x "$test_bin/hyprctl" + +cat >"$test_bin/omarchy-hw-vulkan" <<'EOF' +#!/bin/bash +exit 1 +EOF +chmod +x "$test_bin/omarchy-hw-vulkan" + +cat >"$test_bin/omarchy-pkg-aur-accessible" <<'EOF' +#!/bin/bash +exit "${AUR_ACCESSIBLE:-0}" +EOF +chmod +x "$test_bin/omarchy-pkg-aur-accessible" + +write_hw_x86_64_v3() { + cat >"$test_bin/omarchy-hw-x86-64-v3" <"$test_bin/voxtype" <>"\$TEST_LOG" +if [[ \$1 == "setup" && \$2 == "--download" ]]; then + exit $setup_exit +fi +exit 0 +EOF + chmod +x "$test_bin/voxtype" +} + +run_install() { + local answers="$1" + : >"$log_file" + printf '%s\n' $answers >"$confirm_queue" + HOME="$test_home" OMARCHY_PATH="$test_omarchy_path" PATH="$test_bin:$ROOT/bin:$PATH" \ + TEST_LOG="$log_file" CONFIRM_QUEUE="$confirm_queue" AUR_ACCESSIBLE="${2:-0}" \ + bash "$ROOT/bin/omarchy-voxtype-install" +} + +# A CPU with the x86-64-v3 baseline installs the prebuilt binary as before. +write_hw_x86_64_v3 0 +write_voxtype_stub 0 +run_install "yes" +grep -qx 'omarchy-pkg-add:voxtype-bin' "$log_file" || fail "v3-capable CPU installs voxtype-bin" +grep -q '^omarchy-notification-send:' "$log_file" || fail "v3-capable CPU install sends the ready notification" +grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "v3-capable CPU install does not touch the AUR" + +# A CPU missing the baseline, with the user declining the source build, +# installs nothing. +write_hw_x86_64_v3 1 +run_install "yes no" +grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "declining the source build does not install the prebuilt binary" +grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build does not touch the AUR" + +# A CPU missing the baseline, with the user accepting the source build, +# installs the AUR voxtype package instead of voxtype-bin. +write_hw_x86_64_v3 1 +write_voxtype_stub 0 +run_install "yes yes" 0 +grep -qx 'omarchy-pkg-aur-add:voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" +grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "accepting the source build does not install voxtype-bin" + +# If the AUR is unreachable, the source-build offer fails cleanly. +write_hw_x86_64_v3 1 +run_install "yes yes" 1 +grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "an unreachable AUR does not attempt the source install" + +# A failure partway through setup rolls back via omarchy-voxtype-remove +# instead of leaving a half-installed package behind. +write_hw_x86_64_v3 0 +write_voxtype_stub 1 +run_install "yes" +grep -q '^omarchy-voxtype-remove:' "$log_file" || fail "a failed setup step triggers a rollback" + +pass "Voxtype install gates on CPU capability and rolls back on failure" From d850c5644c89d2f6a7a6a28f4aa2930755c4ff91 Mon Sep 17 00:00:00 2001 From: ironbract Date: Tue, 25 Aug 2026 23:24:17 -0400 Subject: [PATCH 02/15] Fix source-build fallback silently installing voxtype-bin instead voxtype-bin declares Provides=voxtype, so yay -S --noconfirm --needed voxtype silently resolved to the repo-provided voxtype-bin instead of building the AUR voxtype package -- defeating the fallback and reinstalling the exact binary that SIGILLs on pre-AVX2 CPUs. omarchy-pkg-aur-add now accepts an optional repo/ prefix (e.g. aur/voxtype) to force resolution from a specific source while still verifying/erroring against the bare package name pacman reports. omarchy-voxtype-install passes aur/voxtype to use it. Verified on real pre-AVX2 hardware: the source build now actually compiles and installs voxtype (not voxtype-bin), and the resulting systemd service starts and runs correctly. --- bin/omarchy-pkg-aur-add | 11 +++- bin/omarchy-voxtype-install | 2 +- test/shell.d/pkg-aur-add-test.sh | 75 ++++++++++++++++++++++++++++ test/shell.d/voxtype-install-test.sh | 2 +- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100755 test/shell.d/pkg-aur-add-test.sh diff --git a/bin/omarchy-pkg-aur-add b/bin/omarchy-pkg-aur-add index 7a152be7fe8..ee1b6c9506b 100755 --- a/bin/omarchy-pkg-aur-add +++ b/bin/omarchy-pkg-aur-add @@ -2,12 +2,19 @@ # omarchy:summary=Add the named packages to the system from the AUR if they're missing. Returns false if it couldn't be done. # omarchy:args= +# +# Each package may be given as a plain name or as "aur/name" to force +# resolution from the AUR even when a same-named package is also provided +# by a sync repo (yay's --noconfirm silently prefers the repo provider in +# that case, which defeats callers that specifically want the AUR build). -if omarchy-pkg-missing "$@"; then +names=("${@#*/}") + +if omarchy-pkg-missing "${names[@]}"; then yay -S --noconfirm --needed "$@" || exit 1 fi -for pkg in "$@"; do +for pkg in "${names[@]}"; do # Secondary check to handle states where pacman doesn't actually register an error if ! pacman -Q "$pkg" &>/dev/null; then echo -e "\033[31mError: Package '$pkg' did not install\033[0m" >&2 diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index 7500f2b8ca8..6b36370dd79 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -28,7 +28,7 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then if [[ $voxtype_pkg == voxtype-bin ]]; then omarchy-pkg-add voxtype-bin || exit 1 else - omarchy-pkg-aur-add voxtype || exit 1 + omarchy-pkg-aur-add aur/voxtype || exit 1 fi # Setup voxtype diff --git a/test/shell.d/pkg-aur-add-test.sh b/test/shell.d/pkg-aur-add-test.sh new file mode 100755 index 00000000000..249e7d0b71e --- /dev/null +++ b/test/shell.d/pkg-aur-add-test.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +set -euo pipefail + +source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" + +test_bin=$(mktemp -d) +state_dir=$(mktemp -d) +log_file=$(mktemp) +trap 'rm -rf "$test_bin" "$state_dir"; rm -f "$log_file"' EXIT + +# pacman -Q only ever knows packages by their real (unprefixed) name -- +# "installed" state is tracked as marker files in $state_dir. +cat >"$test_bin/pacman" <"$test_bin/yay" <>"\$TEST_LOG" +for target in "\${@:3}"; do + touch "$state_dir/\${target#*/}" +done +exit 0 +EOF + chmod +x "$test_bin/yay" +} + +# yay that succeeds but installs nothing -- simulates a sync-repo provider +# silently satisfying the transaction instead of the intended AUR package. +write_yay_noop() { + cat >"$test_bin/yay" <>"\$TEST_LOG" +exit 0 +EOF + chmod +x "$test_bin/yay" +} + +run_aur_add() { + : >"$log_file" + rm -f "$state_dir"/* + PATH="$test_bin:$ROOT/bin:$PATH" TEST_LOG="$log_file" \ + bash "$ROOT/bin/omarchy-pkg-aur-add" "$@" +} + +# An "aur/name" target is passed through to yay as-is (to force AUR +# resolution over a same-named sync-repo provider), but the installed-check +# and error reporting use the bare package name pacman actually knows. +write_yay_installs +run_aur_add "aur/voxtype" || fail "aur/-prefixed target succeeds once pacman reports the bare name installed" +grep -qx 'yay:-S --noconfirm --needed aur/voxtype' "$log_file" || fail "yay is invoked with the full aur/name target" +pass "aur/-prefixed target installs and verifies via the bare package name" + +# A plain name (no prefix) still works as before. +run_aur_add "jq" || fail "unprefixed target still succeeds" +pass "unprefixed target behaves as before" + +# If pacman never reports the bare name as installed, the call fails even +# though yay exited 0 -- guards against a repo provider silently satisfying +# the sync transaction instead of the intended AUR package. +write_yay_noop +if run_aur_add "aur/voxtype"; then + fail "missing bare package name after install is treated as failure" +fi +pass "missing bare package name after install is treated as failure" diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index bd3a0a19f9d..a549b3cd7df 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -108,7 +108,7 @@ grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build write_hw_x86_64_v3 1 write_voxtype_stub 0 run_install "yes yes" 0 -grep -qx 'omarchy-pkg-aur-add:voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" +grep -qx 'omarchy-pkg-aur-add:aur/voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "accepting the source build does not install voxtype-bin" # If the AUR is unreachable, the source-build offer fails cleanly. From c2ec87d65dc7a391c5453f217f6badbe7c1a1933 Mon Sep 17 00:00:00 2001 From: Omabot Date: Wed, 26 Aug 2026 05:34:08 -0700 Subject: [PATCH 03/15] Keep a good Voxtype install when the shell restart fails omarchy-restart-shell was the last command in install_voxtype, so its exit status became the function's, and the new rollback treated it as a failed install: omarchy-voxtype-remove drops the package and deletes ~/.config/voxtype and ~/.local/share/voxtype, taking the 150MB model that had just downloaded with it. It exits non-zero for reasons unrelated to Voxtype -- a locked session, or the shell not answering its ping within two seconds, which is likeliest on exactly the older CPUs this fallback targets, and after a 20+ minute source build. Reloading Hyprland and restarting the shell only load the new bindings, so they belong on the success path rather than inside the rollback boundary. Co-Authored-By: Claude Opus 5 (1M context) --- bin/omarchy-voxtype-install | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index 6b36370dd79..494a050c5f1 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -41,12 +41,14 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then voxtype setup gpu --enable || true fi voxtype setup systemd || return 1 - - hyprctl reload >/dev/null - omarchy-restart-shell } + # Reloading and restarting the shell only picks up the new bindings; both can + # fail for reasons that have nothing to do with Voxtype (a locked session, a + # slow shell), so they sit outside the rollback and never undo a good install. if install_voxtype; then + hyprctl reload >/dev/null + omarchy-restart-shell omarchy-notification-send -g "Voxtype Dictation Ready" "Hold F9 to dictate (or toggle with Super + Ctrl + X)." -t 10000 else gum style --foreground 1 "Voxtype setup failed. Rolling back the install." From 22506147baf2611d621ee65820d6cfcdcb0cb625 Mon Sep 17 00:00:00 2001 From: Omabot Date: Wed, 26 Aug 2026 05:34:17 -0700 Subject: [PATCH 04/15] Report x86-64-v3 as unsupported on non-x86_64 CPUs Exiting 0 on aarch64 said the CPU satisfies an x86 baseline, which the installer reads as "the prebuilt binary is fine" and reaches for voxtype-bin -- an x86_64-only package. Every other omarchy-hw-* detector answers 0 only for a match; unknown hardware exits non-zero. With that, an ARM machine takes the source-build path instead, and the AUR voxtype package builds for aarch64. Co-Authored-By: Claude Opus 5 (1M context) Co-Authored-By: Codex XHigh --- bin/omarchy-hw-x86-64-v3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/omarchy-hw-x86-64-v3 b/bin/omarchy-hw-x86-64-v3 index 1e120e23dad..68b46c70e27 100755 --- a/bin/omarchy-hw-x86-64-v3 +++ b/bin/omarchy-hw-x86-64-v3 @@ -2,7 +2,7 @@ # omarchy:summary=Detect whether the CPU supports the x86-64-v3 baseline (AVX2, FMA, BMI1, BMI2, F16C, MOVBE). -[[ $(uname -m) == "x86_64" ]] || exit 0 +[[ $(uname -m) == "x86_64" ]] || exit 1 cpuinfo=${OMARCHY_CPUINFO_PATH:-/proc/cpuinfo} flags=" $(grep -m1 "^flags" "$cpuinfo" 2>/dev/null | cut -d: -f2) " From df67e748fc2861c233d8a6d39cf7e3ff8d73ef9b Mon Sep 17 00:00:00 2001 From: Omabot Date: Wed, 26 Aug 2026 05:34:38 -0700 Subject: [PATCH 05/15] Show the dictation menu entries for a source-built Voxtype Both entries keyed off voxtype-bin, which the source-build fallback never installs: Remove > AI > Dictation stayed hidden, so the population this fallback exists for had no way to uninstall, and Install > AI > Dictation stayed enabled and would re-run the installer over a working setup -- overwriting ~/.config/voxtype with the default and, on any later failure, rolling the whole thing back. omarchy-cmd-present answers for either package, the way omarchy-voxtype-remove and the Ollama entries already do. Co-Authored-By: Claude Opus 5 (1M context) Co-Authored-By: Codex XHigh --- default/omarchy/omarchy-menu.jsonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default/omarchy/omarchy-menu.jsonc b/default/omarchy/omarchy-menu.jsonc index 59582db7345..808749e4fae 100644 --- a/default/omarchy/omarchy-menu.jsonc +++ b/default/omarchy/omarchy-menu.jsonc @@ -237,7 +237,7 @@ "install.terminal.ghostty": {"icon":"","label":"Ghostty","disabled":"omarchy-pkg-present ghostty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal ghostty'"}, "install.terminal.kitty": {"icon":"","label":"Kitty","disabled":"omarchy-pkg-present kitty","action":"omarchy-launch-floating-terminal-with-presentation 'omarchy-install-terminal kitty'"}, "install.ai.chatgpt": {"icon":"","iconFont":"omarchy","label":"ChatGPT Desktop","disabled":"omarchy-pkg-present openai-codex-desktop","action":"omarchy-launch-floating-terminal-with-presentation omarchy-install-ai-chatgpt"}, - "install.ai.dictation": {"icon":"","label":"Dictation","disabled":"omarchy-pkg-present voxtype-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-install"}, + "install.ai.dictation": {"icon":"","label":"Dictation","disabled":"omarchy-cmd-present voxtype","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-install"}, "install.ai.grok-bot": {"icon":"","iconFont":"omarchy","label":"Grok Bot","disabled":"omarchy-pkg-present grok-bot","action":"omarchy-install-and-launch 'Grok Bot' grok-bot grok-bot"}, "install.ai.lm-studio": {"icon":"","iconFont":"omarchy","label":"LM Studio","disabled":"omarchy-pkg-present lmstudio-bin","action":"omarchy-install-app 'LM Studio' lmstudio-bin"}, "install.ai.ollama": {"icon":"","iconFont":"omarchy","label":"Ollama","disabled":"omarchy-cmd-present ollama","action":"if omarchy-cmd-present nvidia-smi; then ollama_pkg=ollama-cuda; elif omarchy-cmd-present rocminfo; then ollama_pkg=ollama-rocm; else ollama_pkg=ollama; fi; omarchy-install-app Ollama \"$ollama_pkg\""}, @@ -301,7 +301,7 @@ "remove.service.dropbox": {"icon":"","label":"Dropbox","when":"omarchy-pkg-present dropbox","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-service-dropbox"}, "remove.service.tailscale": {"icon":"","label":"Tailscale","when":"omarchy-pkg-present tailscale","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-service-tailscale"}, "remove.ai.chatgpt": {"icon":"","iconFont":"omarchy","label":"ChatGPT Desktop","when":"omarchy-pkg-present openai-codex-desktop","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-ai-chatgpt"}, - "remove.ai.dictation": {"icon":"","label":"Dictation","when":"omarchy-pkg-present voxtype-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-remove"}, + "remove.ai.dictation": {"icon":"","label":"Dictation","when":"omarchy-cmd-present voxtype","action":"omarchy-launch-floating-terminal-with-presentation omarchy-voxtype-remove"}, "remove.ai.grok-bot": {"icon":"","iconFont":"omarchy","label":"Grok Bot","when":"omarchy-pkg-present grok-bot","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-ai-grok-bot"}, "remove.ai.lm-studio": {"icon":"","iconFont":"omarchy","label":"LM Studio","when":"omarchy-pkg-present lmstudio-bin","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-ai-lm-studio"}, "remove.ai.ollama": {"icon":"","iconFont":"omarchy","label":"Ollama","when":"omarchy-pkg-present ollama","action":"omarchy-launch-floating-terminal-with-presentation omarchy-remove-ai-ollama"}, From 1d37f811e9fda79163f799d24563d589a1b4df84 Mon Sep 17 00:00:00 2001 From: ironbract Date: Thu, 27 Aug 2026 09:19:57 -0400 Subject: [PATCH 06/15] Fix aarch64 handling in the x86-64-v3 predicate's test and messaging hw-x86-64-v3-test.sh couldn't exercise the non-x86_64 rejection since it only overrode OMARCHY_CPUINFO_PATH, not the machine check; add an OMARCHY_UNAME_M override and a case asserting aarch64 is rejected even with x86-64-v3 flags present. Also stop telling non-x86_64 machines (e.g. Apple Silicon) their CPU is "missing instructions" or warning of slower dictation when the fallback build there is native, not a degraded compatibility build. Based on a report and fix from @twitchax on #8316, tested on real M1 hardware; applied here and verified against the x86_64 test suite since ARM hardware wasn't available locally. --- bin/omarchy-hw-x86-64-v3 | 3 ++- bin/omarchy-voxtype-install | 13 ++++++++++--- manual/11-text-extraction-dictation.md | 2 +- test/shell.d/hw-x86-64-v3-test.sh | 5 ++++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/bin/omarchy-hw-x86-64-v3 b/bin/omarchy-hw-x86-64-v3 index 68b46c70e27..a4fc9582eab 100755 --- a/bin/omarchy-hw-x86-64-v3 +++ b/bin/omarchy-hw-x86-64-v3 @@ -2,7 +2,8 @@ # omarchy:summary=Detect whether the CPU supports the x86-64-v3 baseline (AVX2, FMA, BMI1, BMI2, F16C, MOVBE). -[[ $(uname -m) == "x86_64" ]] || exit 1 +machine=${OMARCHY_UNAME_M:-$(uname -m)} +[[ $machine == "x86_64" ]] || exit 1 cpuinfo=${OMARCHY_CPUINFO_PATH:-/proc/cpuinfo} flags=" $(grep -m1 "^flags" "$cpuinfo" 2>/dev/null | cut -d: -f2) " diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index 494a050c5f1..b094ef36e05 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -10,10 +10,17 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then voxtype_pkg=voxtype-bin if ! omarchy-hw-x86-64-v3; then - gum style --foreground 3 \ - "Your CPU is missing instructions (AVX2/x86-64-v3) that the prebuilt Voxtype binary requires." + if [[ $(uname -m) == "x86_64" ]]; then + gum style --foreground 3 \ + "Your CPU is missing instructions (AVX2/x86-64-v3) that the prebuilt Voxtype binary requires." + build_prompt="Build Voxtype from source instead? This can take 20+ minutes and may result in noticeably slower dictation on this CPU." + else + gum style --foreground 3 \ + "There's no prebuilt Voxtype binary for your CPU architecture." + build_prompt="Build Voxtype from source instead? This can take 20+ minutes." + fi - if gum confirm "Build Voxtype from source instead? This can take 20+ minutes and may result in noticeably slower dictation on this CPU."; then + if gum confirm "$build_prompt"; then if ! omarchy-pkg-aur-accessible; then gum style --foreground 1 "The AUR is unreachable right now, so Voxtype can't be built from source. Try again later." exit 1 diff --git a/manual/11-text-extraction-dictation.md b/manual/11-text-extraction-dictation.md index 5bc21d88e92..da81b5b0b92 100644 --- a/manual/11-text-extraction-dictation.md +++ b/manual/11-text-extraction-dictation.md @@ -12,6 +12,6 @@ This is very helpful for grabbing addresses out of image footers or phone number Omarchy offers AI dictation via [Voxtype](https://voxtype.io/). You install it via _Install > AI > Dictation_ through the Omarchy menu. By default, it'll load a base English model that takes up 150MB. But you can tweak which model you'd like to use by running `voxtype setup model` in the terminal. And you can tweak all the settings via `~/.config/voxtype/config.toml`. -The prebuilt Voxtype binary requires a CPU with the x86-64-v3 instruction baseline (AVX2, FMA, BMI1/2, F16C, MOVBE — Haswell-era or newer, roughly 2013+). On older CPUs, the installer offers to build Voxtype from source via the AUR instead; this takes 20+ minutes and may run noticeably slower. +The prebuilt Voxtype binary is x86_64 only and requires the x86-64-v3 instruction baseline (AVX2, FMA, BMI1/2, F16C, MOVBE — Haswell-era or newer, roughly 2013+). On an older x86_64 CPU, or on any non-x86_64 machine (e.g. Apple Silicon), the installer offers to build Voxtype from source via the AUR instead; on an older x86_64 CPU this takes 20+ minutes and may run noticeably slower, while on other architectures it's a native build with no expected slowdown. Once installed, you dictate by holding down `F9` or by toggling with `Super + Ctrl + X`, and the dictated text will appear in the focused input area. diff --git a/test/shell.d/hw-x86-64-v3-test.sh b/test/shell.d/hw-x86-64-v3-test.sh index a4dfec75888..92b38e1072f 100755 --- a/test/shell.d/hw-x86-64-v3-test.sh +++ b/test/shell.d/hw-x86-64-v3-test.sh @@ -12,7 +12,7 @@ write_cpuinfo_flags() { } hw_x86_64_v3() { - OMARCHY_CPUINFO_PATH="$tmp_dir/cpuinfo" "$ROOT/bin/omarchy-hw-x86-64-v3" + OMARCHY_CPUINFO_PATH="$tmp_dir/cpuinfo" OMARCHY_UNAME_M="${OMARCHY_UNAME_M:-x86_64}" "$ROOT/bin/omarchy-hw-x86-64-v3" } assert_detects() { @@ -44,3 +44,6 @@ assert_rejects "AVX2 alone without FMA/BMI1/BMI2/F16C/MOVBE does not satisfy x86 : >"$tmp_dir/cpuinfo" assert_rejects "empty cpuinfo does not satisfy x86-64-v3" + +write_cpuinfo_flags "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm abm avx2 bmi1 bmi2" +OMARCHY_UNAME_M="aarch64" assert_rejects "aarch64 is rejected even with x86-64-v3 flags present" From a27badb79336dd4670636b4298216a709ca591ac Mon Sep 17 00:00:00 2001 From: Omabot Date: Fri, 28 Aug 2026 05:28:24 -0700 Subject: [PATCH 07/15] Cover both architecture branches of the Voxtype build prompt The installer's copy branches on `uname -m` while the suite stubbed only the predicate, so on an x86_64 host the non-x86_64 message was unreachable and neither prompt was asserted. Stubbing `uname` lets both branches run on any host; flipping the branch in either direction now fails the file. Co-Authored-By: Claude Opus 5 (1M context) --- test/shell.d/voxtype-install-test.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index a549b3cd7df..e7b0a21fad0 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -58,6 +58,18 @@ exit "${AUR_ACCESSIBLE:-0}" EOF chmod +x "$test_bin/omarchy-pkg-aur-accessible" +# The installer branches its copy on the machine type, so both branches have to +# be reachable from an x86_64 test host. +cat >"$test_bin/uname" <<'EOF' +#!/bin/bash +if [[ $1 == "-m" ]]; then + echo "${TEST_UNAME_M:-x86_64}" +else + exec /usr/bin/uname "$@" +fi +EOF +chmod +x "$test_bin/uname" + write_hw_x86_64_v3() { cat >"$test_bin/omarchy-hw-x86-64-v3" <"$confirm_queue" HOME="$test_home" OMARCHY_PATH="$test_omarchy_path" PATH="$test_bin:$ROOT/bin:$PATH" \ TEST_LOG="$log_file" CONFIRM_QUEUE="$confirm_queue" AUR_ACCESSIBLE="${2:-0}" \ + TEST_UNAME_M="${3:-x86_64}" \ bash "$ROOT/bin/omarchy-voxtype-install" } @@ -116,6 +129,17 @@ write_hw_x86_64_v3 1 run_install "yes yes" 1 grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "an unreachable AUR does not attempt the source install" +# On a non-x86_64 machine nothing is missing and the source build is native, so +# neither message may leak into the other architecture's branch. +write_hw_x86_64_v3 1 +run_install "yes no" 0 x86_64 +grep -qxF 'confirm:Build Voxtype from source instead? This can take 20+ minutes and may result in noticeably slower dictation on this CPU.' "$log_file" || + fail "an x86_64 CPU missing the baseline is warned the source build may be slower" + +run_install "yes no" 0 aarch64 +grep -qxF 'confirm:Build Voxtype from source instead? This can take 20+ minutes.' "$log_file" || + fail "a non-x86_64 machine is not warned about a slowdown that would not happen" + # A failure partway through setup rolls back via omarchy-voxtype-remove # instead of leaving a half-installed package behind. write_hw_x86_64_v3 0 From be3457a66bff540885b1f0c277b5a071ff9623e9 Mon Sep 17 00:00:00 2001 From: omarchybot Date: Thu, 3 Sep 2026 05:24:42 -0700 Subject: [PATCH 08/15] Check a prefixed AUR target by the exact name pacman reports pacman -Q resolves provides, so with voxtype-bin installed "pacman -Q voxtype" answers "voxtype-bin 1.0.0-2" and exits 0. The aur/ prefix was therefore measured against the provider it exists to bypass: on a machine already carrying voxtype-bin, "omarchy-pkg-aur-add aur/voxtype" found nothing missing, never ran yay, and then took that same provider as proof the package had installed, exiting 0 having built nothing. A prefixed target is now checked with "pacman -Qq", which prints the real package name, and compared against the name asked for. Plain targets keep the old provides-resolving check, so no existing caller changes behaviour. The test's pacman stub modelled -Q as exact-name only, which is why the suite was green; it now answers for a provided name the way pacman does. Co-Authored-By: Claude Opus 5 (1M context) --- bin/omarchy-pkg-aur-add | 27 ++++++++++++++---- test/shell.d/pkg-aur-add-test.sh | 49 ++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/bin/omarchy-pkg-aur-add b/bin/omarchy-pkg-aur-add index ee1b6c9506b..0e228097b37 100755 --- a/bin/omarchy-pkg-aur-add +++ b/bin/omarchy-pkg-aur-add @@ -8,16 +8,33 @@ # by a sync repo (yay's --noconfirm silently prefers the repo provider in # that case, which defeats callers that specifically want the AUR build). -names=("${@#*/}") +# pacman -Q resolves provides: with voxtype-bin installed, "pacman -Q voxtype" +# answers "voxtype-bin" and exits 0. A prefixed target is therefore checked by +# the exact name pacman prints back, or the provider the prefix exists to +# bypass satisfies both checks below and nothing is ever built. +installed() { + local name=${1#*/} -if omarchy-pkg-missing "${names[@]}"; then + if [[ $1 == */* ]]; then + [[ $(pacman -Qq "$name" 2>/dev/null) == "$name" ]] + else + pacman -Q "$name" &>/dev/null + fi +} + +missing=0 +for pkg in "$@"; do + installed "$pkg" || missing=1 +done + +if (( missing )); then yay -S --noconfirm --needed "$@" || exit 1 fi -for pkg in "${names[@]}"; do +for pkg in "$@"; do # Secondary check to handle states where pacman doesn't actually register an error - if ! pacman -Q "$pkg" &>/dev/null; then - echo -e "\033[31mError: Package '$pkg' did not install\033[0m" >&2 + if ! installed "$pkg"; then + echo -e "\033[31mError: Package '${pkg#*/}' did not install\033[0m" >&2 exit 1 fi done diff --git a/test/shell.d/pkg-aur-add-test.sh b/test/shell.d/pkg-aur-add-test.sh index 249e7d0b71e..29db8904ae7 100755 --- a/test/shell.d/pkg-aur-add-test.sh +++ b/test/shell.d/pkg-aur-add-test.sh @@ -9,12 +9,21 @@ state_dir=$(mktemp -d) log_file=$(mktemp) trap 'rm -rf "$test_bin" "$state_dir"; rm -f "$log_file"' EXIT -# pacman -Q only ever knows packages by their real (unprefixed) name -- -# "installed" state is tracked as marker files in $state_dir. +# "Installed" state is marker files in $state_dir: the file name is the real +# package name and its contents are the names that package provides. Like the +# real pacman, -Q and -Qq answer for a provided name too, printing the real +# package that provides it. cat >"$test_bin/pacman" <"$log_file" rm -f "$state_dir"/* - PATH="$test_bin:$ROOT/bin:$PATH" TEST_LOG="$log_file" \ - bash "$ROOT/bin/omarchy-pkg-aur-add" "$@" + aur_add "$@" +} + +# Same, but starting from a machine where $1 is installed and provides $2. +run_aur_add_with_provider() { + local provider="$1" provided="$2" + shift 2 + : >"$log_file" + rm -f "$state_dir"/* + echo "$provided" >"$state_dir/$provider" + aur_add "$@" } # An "aur/name" target is passed through to yay as-is (to force AUR @@ -73,3 +96,17 @@ if run_aur_add "aur/voxtype"; then fail "missing bare package name after install is treated as failure" fi pass "missing bare package name after install is treated as failure" + +# The provider a prefixed target exists to bypass must not count as the target: +# "pacman -Q voxtype" answers "voxtype-bin" when that package provides it, so a +# machine already carrying the prebuilt binary would otherwise skip the build +# and then accept the binary it was trying to replace. +if run_aur_add_with_provider "voxtype-bin" "voxtype" "aur/voxtype"; then + fail "a package that only provides the target is not treated as the target" +fi +grep -qx 'yay:-S --noconfirm --needed aur/voxtype' "$log_file" || fail "an installed provider does not skip the AUR build" + +write_yay_installs +run_aur_add_with_provider "voxtype-bin" "voxtype" "aur/voxtype" || + fail "the real package installing over a provider succeeds" +pass "an installed provider neither skips nor satisfies a prefixed target" From 41fbafeb62a3142ebae0a28096bf5e5d538866ce Mon Sep 17 00:00:00 2001 From: omarchybot Date: Thu, 3 Sep 2026 05:25:50 -0700 Subject: [PATCH 09/15] Drop the conflicting prebuilt binary before building Voxtype from source voxtype-bin declares conflicts=('voxtype'), and pacman answers no to its conflict prompt under --noconfirm, aborting with "unresolvable package conflicts detected". A machine still carrying the prebuilt binary -- which is every machine this fallback exists for, since the way users arrive here is a voxtype-bin that SIGILLs -- would build for twenty minutes and then fail to install what it built. The drop runs only on the source-build branch, after the user has confirmed the build, and omarchy-pkg-drop is a no-op when the package is absent. On a non-x86_64 machine voxtype-bin cannot be installed in the first place, so nothing changes there. Co-Authored-By: Claude Opus 5 (1M context) --- bin/omarchy-voxtype-install | 4 ++++ test/shell.d/voxtype-install-test.sh | 10 +++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index b094ef36e05..be73f30d681 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -35,6 +35,10 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then if [[ $voxtype_pkg == voxtype-bin ]]; then omarchy-pkg-add voxtype-bin || exit 1 else + # voxtype-bin conflicts with voxtype, and pacman answers no to the conflict + # prompt under --noconfirm, so a machine still carrying the prebuilt binary + # would build for 20 minutes and then fail to install what it built. + omarchy-pkg-drop voxtype-bin omarchy-pkg-aur-add aur/voxtype || exit 1 fi diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index e7b0a21fad0..c7e846459d9 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -32,7 +32,7 @@ exit 0 EOF chmod +x "$test_bin/gum" -for cmd in omarchy-pkg-add omarchy-pkg-aur-add omarchy-restart-shell omarchy-notification-send omarchy-voxtype-remove; do +for cmd in omarchy-pkg-add omarchy-pkg-aur-add omarchy-pkg-drop omarchy-restart-shell omarchy-notification-send omarchy-voxtype-remove; do cat >"$test_bin/$cmd" <>"\$TEST_LOG" @@ -108,6 +108,7 @@ run_install "yes" grep -qx 'omarchy-pkg-add:voxtype-bin' "$log_file" || fail "v3-capable CPU installs voxtype-bin" grep -q '^omarchy-notification-send:' "$log_file" || fail "v3-capable CPU install sends the ready notification" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "v3-capable CPU install does not touch the AUR" +grep -q '^omarchy-pkg-drop:' "$log_file" && fail "v3-capable CPU install does not drop anything" # A CPU missing the baseline, with the user declining the source build, # installs nothing. @@ -123,6 +124,13 @@ write_voxtype_stub 0 run_install "yes yes" 0 grep -qx 'omarchy-pkg-aur-add:aur/voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "accepting the source build does not install voxtype-bin" +# voxtype-bin conflicts with voxtype, so it has to go before the build's output +# can be installed over it. +drop_line=$(grep -n '^omarchy-pkg-drop:voxtype-bin$' "$log_file" | cut -d: -f1) +aur_line=$(grep -n '^omarchy-pkg-aur-add:aur/voxtype$' "$log_file" | cut -d: -f1) +if [[ -z $drop_line ]] || (( drop_line > aur_line )); then + fail "the conflicting prebuilt binary is dropped before the source build installs" +fi # If the AUR is unreachable, the source-build offer fails cleanly. write_hw_x86_64_v3 1 From e691c74075902cdacd9d42743f51cf57a6b16103 Mon Sep 17 00:00:00 2001 From: ironbract Date: Thu, 3 Sep 2026 09:12:29 -0400 Subject: [PATCH 10/15] Install wtype only once Voxtype is going to be installed wtype was installed before the CPU capability decision, so declining the source build on a machine that cannot run the prebuilt binary left the package behind on a system that got no dictation -- while the test's own comment claimed the declining path "installs nothing". It now waits until after the decision, on both the prebuilt and source-build paths. The declining case asserts no package is installed at all rather than only that voxtype-bin isn't, which is what makes the regression visible. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0143VhE2XACsuXdHLRkWoy37 --- bin/omarchy-voxtype-install | 6 ++++-- test/shell.d/voxtype-install-test.sh | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index be73f30d681..a90fd68f226 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -6,8 +6,6 @@ # Install voxtype and configure it for use. if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then - omarchy-pkg-add wtype || exit 1 - voxtype_pkg=voxtype-bin if ! omarchy-hw-x86-64-v3; then if [[ $(uname -m) == "x86_64" ]]; then @@ -32,6 +30,10 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then fi fi + # wtype is only useful once Voxtype is actually going to be installed, so it + # waits until after the CPU decision: declining the build now installs nothing. + omarchy-pkg-add wtype || exit 1 + if [[ $voxtype_pkg == voxtype-bin ]]; then omarchy-pkg-add voxtype-bin || exit 1 else diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index c7e846459d9..4d8ec4a88ef 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -105,6 +105,7 @@ run_install() { write_hw_x86_64_v3 0 write_voxtype_stub 0 run_install "yes" +grep -qx 'omarchy-pkg-add:wtype' "$log_file" || fail "v3-capable CPU installs wtype" grep -qx 'omarchy-pkg-add:voxtype-bin' "$log_file" || fail "v3-capable CPU installs voxtype-bin" grep -q '^omarchy-notification-send:' "$log_file" || fail "v3-capable CPU install sends the ready notification" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "v3-capable CPU install does not touch the AUR" @@ -114,7 +115,7 @@ grep -q '^omarchy-pkg-drop:' "$log_file" && fail "v3-capable CPU install does no # installs nothing. write_hw_x86_64_v3 1 run_install "yes no" -grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "declining the source build does not install the prebuilt binary" +grep -q '^omarchy-pkg-add:' "$log_file" && fail "declining the source build installs no packages at all, wtype included" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build does not touch the AUR" # A CPU missing the baseline, with the user accepting the source build, @@ -122,6 +123,7 @@ grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build write_hw_x86_64_v3 1 write_voxtype_stub 0 run_install "yes yes" 0 +grep -qx 'omarchy-pkg-add:wtype' "$log_file" || fail "accepting the source build installs wtype" grep -qx 'omarchy-pkg-aur-add:aur/voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "accepting the source build does not install voxtype-bin" # voxtype-bin conflicts with voxtype, so it has to go before the build's output @@ -136,6 +138,7 @@ fi write_hw_x86_64_v3 1 run_install "yes yes" 1 grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "an unreachable AUR does not attempt the source install" +grep -q '^omarchy-pkg-add:' "$log_file" && fail "an unreachable AUR leaves no packages behind" # On a non-x86_64 machine nothing is missing and the source build is native, so # neither message may leak into the other architecture's branch. From e403558e7c2b965180152915c10296173dc58fbd Mon Sep 17 00:00:00 2001 From: ironbract Date: Thu, 3 Sep 2026 09:12:39 -0400 Subject: [PATCH 11/15] Require LZCNT in the x86-64-v3 predicate LZCNT is part of the x86-64-v3 baseline, and Voxtype's binaries are built with target-cpu=haswell, which may emit it. The predicate checked the other six flags, so a CPU -- or a VM presenting a masked CPUID -- carrying everything but LZCNT was accepted and could still take the SIGILL this branch exists to avoid. It is reported as "abm" in /proc/cpuinfo on both Intel and AMD. The Haswell fixture already carried the flag with nothing asserting it; the new case is the full baseline minus that one flag, and it fails without this change. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0143VhE2XACsuXdHLRkWoy37 --- bin/omarchy-hw-x86-64-v3 | 5 +++-- test/shell.d/hw-x86-64-v3-test.sh | 6 ++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/omarchy-hw-x86-64-v3 b/bin/omarchy-hw-x86-64-v3 index a4fc9582eab..3b9a744438a 100755 --- a/bin/omarchy-hw-x86-64-v3 +++ b/bin/omarchy-hw-x86-64-v3 @@ -1,6 +1,6 @@ #!/bin/bash -# omarchy:summary=Detect whether the CPU supports the x86-64-v3 baseline (AVX2, FMA, BMI1, BMI2, F16C, MOVBE). +# omarchy:summary=Detect whether the CPU supports the x86-64-v3 baseline (AVX2, FMA, BMI1, BMI2, F16C, MOVBE, LZCNT). machine=${OMARCHY_UNAME_M:-$(uname -m)} [[ $machine == "x86_64" ]] || exit 1 @@ -8,6 +8,7 @@ machine=${OMARCHY_UNAME_M:-$(uname -m)} cpuinfo=${OMARCHY_CPUINFO_PATH:-/proc/cpuinfo} flags=" $(grep -m1 "^flags" "$cpuinfo" 2>/dev/null | cut -d: -f2) " -for flag in avx2 fma bmi1 bmi2 f16c movbe; do +# LZCNT is reported as "abm" in /proc/cpuinfo on both Intel and AMD. +for flag in avx2 fma bmi1 bmi2 f16c movbe abm; do [[ $flags == *" $flag "* ]] || exit 1 done diff --git a/test/shell.d/hw-x86-64-v3-test.sh b/test/shell.d/hw-x86-64-v3-test.sh index 92b38e1072f..deef39bb6d0 100755 --- a/test/shell.d/hw-x86-64-v3-test.sh +++ b/test/shell.d/hw-x86-64-v3-test.sh @@ -42,6 +42,12 @@ assert_detects "Haswell with the full x86-64-v3 baseline satisfies it" write_cpuinfo_flags "fpu vme de pse tsc msr avx avx2" assert_rejects "AVX2 alone without FMA/BMI1/BMI2/F16C/MOVBE does not satisfy x86-64-v3" +# LZCNT is part of the x86-64-v3 baseline and Voxtype's binaries are built with +# target-cpu=haswell, so a CPU (or a CPUID mask) carrying every other flag but +# not this one can still take a SIGILL. +write_cpuinfo_flags "fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm avx2 bmi1 bmi2" +assert_rejects "the full baseline without LZCNT (abm) does not satisfy x86-64-v3" + : >"$tmp_dir/cpuinfo" assert_rejects "empty cpuinfo does not satisfy x86-64-v3" From af1d77be5324ef1c53358c200ced9bf89592b2ba Mon Sep 17 00:00:00 2001 From: ironbract Date: Thu, 3 Sep 2026 09:12:50 -0400 Subject: [PATCH 12/15] Say why a failed source build left no Voxtype behind Dropping the conflicting prebuilt binary before the build means a build that then fails leaves the machine with no voxtype at all, where it previously had a crash-looping one. That is no loss on the hardware this branch exists for, but the user saw only yay's own output and was left to work out what state they were in. The failure now says what happened, that the prebuilt binary is gone and why it was never usable here anyway, and how to retry. Also quotes the voxtype-bin literal in its comparison, per AGENTS.md. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0143VhE2XACsuXdHLRkWoy37 --- bin/omarchy-voxtype-install | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index a90fd68f226..fb28ecfd915 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -34,14 +34,18 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then # waits until after the CPU decision: declining the build now installs nothing. omarchy-pkg-add wtype || exit 1 - if [[ $voxtype_pkg == voxtype-bin ]]; then + if [[ $voxtype_pkg == "voxtype-bin" ]]; then omarchy-pkg-add voxtype-bin || exit 1 else # voxtype-bin conflicts with voxtype, and pacman answers no to the conflict # prompt under --noconfirm, so a machine still carrying the prebuilt binary # would build for 20 minutes and then fail to install what it built. omarchy-pkg-drop voxtype-bin - omarchy-pkg-aur-add aur/voxtype || exit 1 + if ! omarchy-pkg-aur-add aur/voxtype; then + gum style --foreground 1 \ + "Building Voxtype from source failed, so dictation isn't installed. Any prebuilt binary that was here has been removed, since it couldn't run on this CPU either. Re-run Install > Dictation to try again." + exit 1 + fi fi # Setup voxtype From b12afd8d9ba37689b56f4e4fed1b312cdd6bb760 Mon Sep 17 00:00:00 2001 From: ironbract Date: Thu, 3 Sep 2026 09:12:57 -0400 Subject: [PATCH 13/15] Assert the installer's exit status on every path The tests checked which commands each path logged but never what the installer returned, so a path that did the right work and then exited wrong -- or the rollback branch reporting success -- would have passed. The menu and any caller act on that status. Every case now asserts it: success on the prebuilt, declining, and source-build paths, failure on an unreachable AUR and on a rolled-back setup. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0143VhE2XACsuXdHLRkWoy37 --- test/shell.d/voxtype-install-test.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index 4d8ec4a88ef..01a2b1aad0c 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -99,12 +99,21 @@ run_install() { TEST_LOG="$log_file" CONFIRM_QUEUE="$confirm_queue" AUR_ACCESSIBLE="${2:-0}" \ TEST_UNAME_M="${3:-x86_64}" \ bash "$ROOT/bin/omarchy-voxtype-install" + install_status=$? + return $install_status +} + +# The installer's exit status is what the menu and any caller act on, so every +# path asserts it rather than only the commands it logged along the way. +assert_status() { + (( install_status == $1 )) || fail "$2 (exited $install_status, expected $1)" } # A CPU with the x86-64-v3 baseline installs the prebuilt binary as before. write_hw_x86_64_v3 0 write_voxtype_stub 0 run_install "yes" +assert_status 0 "a successful install on a v3-capable CPU succeeds" grep -qx 'omarchy-pkg-add:wtype' "$log_file" || fail "v3-capable CPU installs wtype" grep -qx 'omarchy-pkg-add:voxtype-bin' "$log_file" || fail "v3-capable CPU installs voxtype-bin" grep -q '^omarchy-notification-send:' "$log_file" || fail "v3-capable CPU install sends the ready notification" @@ -115,6 +124,7 @@ grep -q '^omarchy-pkg-drop:' "$log_file" && fail "v3-capable CPU install does no # installs nothing. write_hw_x86_64_v3 1 run_install "yes no" +assert_status 0 "declining the source build is not an error" grep -q '^omarchy-pkg-add:' "$log_file" && fail "declining the source build installs no packages at all, wtype included" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build does not touch the AUR" @@ -123,6 +133,7 @@ grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "declining the source build write_hw_x86_64_v3 1 write_voxtype_stub 0 run_install "yes yes" 0 +assert_status 0 "a successful source build succeeds" grep -qx 'omarchy-pkg-add:wtype' "$log_file" || fail "accepting the source build installs wtype" grep -qx 'omarchy-pkg-aur-add:aur/voxtype' "$log_file" || fail "accepting the source build installs voxtype via the AUR" grep -q '^omarchy-pkg-add:voxtype-bin' "$log_file" && fail "accepting the source build does not install voxtype-bin" @@ -137,6 +148,7 @@ fi # If the AUR is unreachable, the source-build offer fails cleanly. write_hw_x86_64_v3 1 run_install "yes yes" 1 +assert_status 1 "an unreachable AUR fails the install" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "an unreachable AUR does not attempt the source install" grep -q '^omarchy-pkg-add:' "$log_file" && fail "an unreachable AUR leaves no packages behind" @@ -156,6 +168,7 @@ grep -qxF 'confirm:Build Voxtype from source instead? This can take 20+ minutes. write_hw_x86_64_v3 0 write_voxtype_stub 1 run_install "yes" +assert_status 1 "a failed setup step fails the install" grep -q '^omarchy-voxtype-remove:' "$log_file" || fail "a failed setup step triggers a rollback" pass "Voxtype install gates on CPU capability and rolls back on failure" From 4a66f53fb5d147263fc747c890541fdee027dbcc Mon Sep 17 00:00:00 2001 From: Omabot Date: Fri, 4 Sep 2026 05:41:24 -0700 Subject: [PATCH 14/15] Stop the source build when the conflicting binary cannot be dropped The drop of voxtype-bin was run for its effect and not for its status, so a machine where pacman refuses the removal still spent the build and then hit the conflict it was meant to clear. The failure message that followed told the user the prebuilt binary had been removed, which on that path is false, and sent them to Install > Dictation to retry -- an entry that stays disabled while voxtype-bin is installed, because the guard is `omarchy-cmd-present voxtype`. Nothing the build produces can be installed while the conflict stands, so the install now stops there and says what happened instead of spending twenty minutes to arrive at the same place. Co-Authored-By: Claude Opus 5 (1M context) Co-Authored-By: Codex XHigh --- bin/omarchy-voxtype-install | 7 ++++++- test/shell.d/voxtype-install-test.sh | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/bin/omarchy-voxtype-install b/bin/omarchy-voxtype-install index fb28ecfd915..f52b5b54fbd 100755 --- a/bin/omarchy-voxtype-install +++ b/bin/omarchy-voxtype-install @@ -40,7 +40,12 @@ if gum confirm "Install Voxtype + AI model (~150MB) to enable dictation?"; then # voxtype-bin conflicts with voxtype, and pacman answers no to the conflict # prompt under --noconfirm, so a machine still carrying the prebuilt binary # would build for 20 minutes and then fail to install what it built. - omarchy-pkg-drop voxtype-bin + if ! omarchy-pkg-drop voxtype-bin; then + gum style --foreground 1 \ + "Couldn't remove the prebuilt Voxtype binary, and the source build can't install over it, so nothing was built. Dictation is unchanged." + exit 1 + fi + if ! omarchy-pkg-aur-add aur/voxtype; then gum style --foreground 1 \ "Building Voxtype from source failed, so dictation isn't installed. Any prebuilt binary that was here has been removed, since it couldn't run on this CPU either. Re-run Install > Dictation to try again." diff --git a/test/shell.d/voxtype-install-test.sh b/test/shell.d/voxtype-install-test.sh index 01a2b1aad0c..fcae9299c7b 100755 --- a/test/shell.d/voxtype-install-test.sh +++ b/test/shell.d/voxtype-install-test.sh @@ -40,6 +40,15 @@ EOF chmod +x "$test_bin/$cmd" done +# The drop of the conflicting prebuilt binary is the one stub a case needs to +# fail, so it answers an environment variable the way the AUR probe does. +cat >"$test_bin/omarchy-pkg-drop" <<'EOF' +#!/bin/bash +echo "omarchy-pkg-drop:$*" >>"$TEST_LOG" +exit "${PKG_DROP_EXIT:-0}" +EOF +chmod +x "$test_bin/omarchy-pkg-drop" + cat >"$test_bin/hyprctl" <<'EOF' #!/bin/bash exit 0 @@ -97,7 +106,7 @@ run_install() { printf '%s\n' $answers >"$confirm_queue" HOME="$test_home" OMARCHY_PATH="$test_omarchy_path" PATH="$test_bin:$ROOT/bin:$PATH" \ TEST_LOG="$log_file" CONFIRM_QUEUE="$confirm_queue" AUR_ACCESSIBLE="${2:-0}" \ - TEST_UNAME_M="${3:-x86_64}" \ + TEST_UNAME_M="${3:-x86_64}" PKG_DROP_EXIT="${4:-0}" \ bash "$ROOT/bin/omarchy-voxtype-install" install_status=$? return $install_status @@ -152,6 +161,13 @@ assert_status 1 "an unreachable AUR fails the install" grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "an unreachable AUR does not attempt the source install" grep -q '^omarchy-pkg-add:' "$log_file" && fail "an unreachable AUR leaves no packages behind" +# If the conflicting prebuilt binary cannot be dropped, the build's output could +# not be installed over it, so the build is not started at all. +write_hw_x86_64_v3 1 +run_install "yes yes" 0 x86_64 1 +assert_status 1 "a prebuilt binary that cannot be dropped fails the install" +grep -q '^omarchy-pkg-aur-add:' "$log_file" && fail "a prebuilt binary that cannot be dropped does not start the source build" + # On a non-x86_64 machine nothing is missing and the source build is native, so # neither message may leak into the other architecture's branch. write_hw_x86_64_v3 1 From 6d69839d48c73de0c57e8db50aaa9073dbd1b420 Mon Sep 17 00:00:00 2001 From: ironbract Date: Tue, 8 Sep 2026 09:21:57 -0400 Subject: [PATCH 15/15] List LZCNT in the manual's x86-64-v3 flag set The predicate gained the flag in e403558e but the manual kept the original six, so the published copy of the requirement disagreed with the check that enforces it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01F7n762HXXjCg8rW7cLfkpM --- manual/11-text-extraction-dictation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manual/11-text-extraction-dictation.md b/manual/11-text-extraction-dictation.md index da81b5b0b92..15e2cba7446 100644 --- a/manual/11-text-extraction-dictation.md +++ b/manual/11-text-extraction-dictation.md @@ -12,6 +12,6 @@ This is very helpful for grabbing addresses out of image footers or phone number Omarchy offers AI dictation via [Voxtype](https://voxtype.io/). You install it via _Install > AI > Dictation_ through the Omarchy menu. By default, it'll load a base English model that takes up 150MB. But you can tweak which model you'd like to use by running `voxtype setup model` in the terminal. And you can tweak all the settings via `~/.config/voxtype/config.toml`. -The prebuilt Voxtype binary is x86_64 only and requires the x86-64-v3 instruction baseline (AVX2, FMA, BMI1/2, F16C, MOVBE — Haswell-era or newer, roughly 2013+). On an older x86_64 CPU, or on any non-x86_64 machine (e.g. Apple Silicon), the installer offers to build Voxtype from source via the AUR instead; on an older x86_64 CPU this takes 20+ minutes and may run noticeably slower, while on other architectures it's a native build with no expected slowdown. +The prebuilt Voxtype binary is x86_64 only and requires the x86-64-v3 instruction baseline (AVX2, FMA, BMI1/2, F16C, MOVBE, LZCNT — Haswell-era or newer, roughly 2013+). On an older x86_64 CPU, or on any non-x86_64 machine (e.g. Apple Silicon), the installer offers to build Voxtype from source via the AUR instead; on an older x86_64 CPU this takes 20+ minutes and may run noticeably slower, while on other architectures it's a native build with no expected slowdown. Once installed, you dictate by holding down `F9` or by toggling with `Super + Ctrl + X`, and the dictated text will appear in the focused input area.