The Windows port is a beta with a Rune desktop app (a tray process; see
The app), WASAPI capture,
local transcribe.cpp transcription, a global shortcut, and generation-safe
automatic paste. Its daily-use surface includes live microphone, model, and
shortcut settings, Hold or Toggle shortcut modes, double-tap lock, Paste Last
Dictation, recording tones, a click-through HUD, retained History, text
replacements, a resident system tray, and per-user Launch at login. Global and
contextual Modes can rewrite completed dictation through the same
deadline-bounded OpenCode processing policy as macOS, then run ordered built-in
or user-defined TypeScript transformations.
The default shortcut is Ctrl+Space. In Hold mode, hold both keys while
speaking and release Space to transcribe and paste. In Toggle mode, press
Ctrl+Space to start and again to finish. Only Escape cancels; holding a
modifier on its own does nothing. Hex consumes the chord while it matches, so
applications and input methods no longer see Ctrl+Space; rebind it in Settings
if you rely on that chord elsewhere. To let another app use the same key, such as
a Discord push-to-talk key, turn on Share dictation shortcut with other apps
under Advanced: Hex still reacts to it but passes its key-down and key-up on,
which can also trigger that binding in other apps. In Hold mode, tap the shortcut twice within
300 ms to lock recording, then press it again to finish. Paste Last defaults to
Ctrl+Alt+V. Settings changes apply live or through an automatic listener
restart.
The Settings card reads Enabled when the shortcut works system-wide in every app and Disabled when it does nothing.
x86_64 PCs need a 2013 or newer processor with AVX2 (Intel Haswell / AMD Excavator or later); on an older processor Hex shows a message and quits instead of starting.
Download and run the installer for your PC:
- x64:
HexSetup.exe - ARM64:
HexSetup.exe
Until Hex's first stable release these are the newest dev build, which keeps updating itself from the Dev channel; afterwards, the stable release.
anoma.ly/hex picks the right one. The installer needs no administrator rights: it installs for the current user, adds Hex to the Start menu and to Settings › Apps for uninstalling, and opens Hex, whose first run downloads a speech model. Releases built once Anomaly's Azure Artifact Signing is configured are Authenticode-signed (windows-signing.md). Until then, and while a new publisher builds SmartScreen reputation, SmartScreen may say it protected your PC; choose More info, then Run anyway.
x64 decodes on the GPU through Vulkan and needs a current NVIDIA, AMD, or
Intel graphics driver (it supplies vulkan-1.dll); the installer stops with an
explanation when it is missing. ARM64 decodes on the CPU. Both are
self-contained: no Visual C++ Redistributable is required. Hex then keeps
itself current through the signed update feed. Uninstalling removes every
installed version, the shortcut, and Launch at login, and keeps settings, logs,
history, and models in %APPDATA%\hex.
The installer and the script below create the same managed layout, so either can replace the other. For a scripted install:
powershell -ExecutionPolicy Bypass -Command "iwr https://anoma.ly/hex/files/install-windows.ps1 -OutFile install-windows.ps1; ./install-windows.ps1"Uninstall a script install with install-windows.ps1 -Uninstall.
Discord shows "Playing HEX: Shards of Fate"
(#445). With game activity
detection on, Discord Desktop matches the running hex.exe to the verified game
HEX: Shards of Fate. It then shows that game on your profile for as long as
Hex runs. The reporter's local test suggests Discord matches on the executable
name. Hex keeps the name hex.exe because the installer, updater, Start Menu
shortcut, and Launch at login all use the managed
%APPDATA%\hex\versions\<version>\hex.exe path. The problem has been reported
to Discord. Until Discord fixes its game list, open Discord's
Settings › Registered Games (or Activity Privacy) and hide the detected
entry, or turn off activity sharing there. Hex works the same either way.
With Parakeet Unified English on a GPU, Hex streams audio into the model while
the shortcut is held, so release only decodes the last one to two seconds. The
same engine streams on macOS (Metal) and Linux (Vulkan). Each dictation logs
source=stream or source=fallback in logs\process.log; a stream that fails,
stalls past its deadline, or returns nothing falls back to transcribing the
whole clip. CPU devices (including ARM64) always use the whole-clip path. Set
HEX_STREAMING=0 to force the whole-clip path. See
dictation.
- 64-bit Windows 10 or 11, x64 or ARM64.
- PowerShell 7 or Windows PowerShell 5.1.
wingetfrom Microsoft App Installer.- Visual Studio C++ Build Tools, CMake, and the stable MSVC Rust toolchain.
- x64: the Vulkan SDK (
VULKAN_SDKset), for the GPU backend. - ARM64: Visual Studio's clang-cl and Ninja; ggml's ARM CPU backend refuses
MSVC. Build with
CC=clang-cl,CXX=clang-cl,CMAKE_GENERATOR=Ninja, andTRANSCRIBE_CMAKE_ARGS=-DGGML_NATIVE=OFF -DGGML_OPENMP=OFF, as.github/workflows/check-windows.ymldoes.
.cargo/config.toml links the C and C++ runtimes statically. Distributed builds
also set TRANSCRIBE_CMAKE_ARGS=-DGGML_NATIVE=OFF; without it ggml tunes its
CPU kernels to the build machine and the binary can crash on older CPUs.
Run the checked-in setup script from the repository root. It keeps an existing compatible Visual Studio installation and installs only missing prerequisites.
powershell -ExecutionPolicy Bypass -File .\scripts\setup-windows.ps1The script also installs rustfmt, Clippy, and rust-analyzer, fetches Cargo
dependencies, and runs cargo check --all-targets.
List WASAPI inputs and the compute backends visible to transcribe.cpp:
cargo run -- devices
cargo run -- model devicesInstall the selected model (with Hex stopped, model install downloads in
this process), load it, and transcribe a WAV file:
cargo run -- model install
cargo run -- model check
cargo run -- model transcribe .\sample.wavFor Polish, name the multilingual Parakeet model:
cargo run -- model install parakeet_v3 --language pl
cargo run -- model check parakeet_v3 --language pl
cargo run -- record --model parakeet_v3 --language pl --copyOpen the desktop application after the model is installed:
cargo run -- appThe Settings card reads Enabled when the shortcut works system-wide in every app and Disabled when it does nothing; its button and the tray's Enable / Disable Hex switch between them. Hex enables itself on launch by default (Enable on launch). The microphone records only while you dictate. Changing the transcription model, microphone, dictation shortcut, double-tap behavior, or Paste Last setting automatically restarts the listener; you do not need to stop it first. Text replacements and feedback volume apply without a model reload. Mode rules, OpenCode profiles, and ordered transformations are snapshotted by the output worker and apply to the next completed dictation without restarting capture. The command-line listener uses the settings saved by the app:
cargo run -- listen --model parakeet_v3 --language plrecord prewarms the selected model and opens the microphone before prompting.
Press Enter once to start, then again to stop. Captures shorter than 300 ms are
discarded. --device accepts a case-insensitive fragment from devices.
Runtime data is stored under %APPDATA%\hex. Observations are in
logs\live.ndjson, and native/runtime diagnostics are in logs\process.log,
including every panic with its thread and backtrace. A worker that stops
unexpectedly leaves its cause there. The app detaches from its console at
launch, so it has no stdout or stderr.
Successful pasted dictations are retained, subject to the selected retention
window and hard size limits, in history.json. Captured audio is never retained
by default.
The hex control commands (docs/cli.md) drive the running tray app
as they do on macOS: status, start, quit, restart, dictation start|stop|cancel|toggle (with stop --print), paste-last, settings,
model, window, vocabulary, history clear, check-for-updates,
launch-at-login (the Run key), onboarding reset, logs, and commands init|check, annotate, meetings record|stop|copy-last, history, and
mcp. They reach it through its local API (local-api.json in
%APPDATA%\hex and the bearer-authenticated POST /control). Dictation commands go
to the listener's own loop as a shortcut press would, and annotate
start, stop, cancel, and status wait for its capture host. history,
meetings, and mcp work as on macOS. hex restart
quits, waits for the drain, and starts hex app --hidden again.
The Transformations card in Modes always offers the built-in transformations.
Choose Set up there to create ~/.config/hex/hex.config.ts and load any
transformations registered by that config. Hex runs the config in its embedded
JavaScript engine (QuickJS), so nothing else needs installing.
Transformations run in the displayed order after mode corrections and the optional OpenCode rewrite. Reordering, adding, or removing them persists in the global or contextual mode and applies to the next output job. Each transformation call is limited to one second and the engine to 64 MiB; a failed step preserves the previous pipeline output. Saving the config reloads it; a config that fails to load keeps the previous one and shows its error in the card.
hex app (--hidden for a login launch) runs the tray app on Rune. Snapshot
fixtures without starting anything: hex app -- --snap out.png --scene modes.
hex app
├── named event already held -> signal it (the running app shows its window) -> exit
└── becomes the app // windows_rune::open
├── the local API's POST /control -> control::host::answer
├── runtime thread: WindowsDesktopHost (listener, model preparation, OpenCode, transformations, updater), publishes every 250 ms
├── main thread: rune::App's winit loop and the window; rune::Tray runs on its own thread
├── --hidden -> windowless start; close -> hide (keep_running)
├── tray Show or a relaunch -> AppHandle::open (shows and focuses)
└── tray Quit / Ctrl-C / restart into an update -> AppHandle::quit -> runtime stops the listener- Quit Hex in the window or the tray stops the listener and ends the app; closing the window only hides it.
- The window uses the shared Rune panes (General, Modes, History, the transcription picker, first-run setup) with Windows rows: Launch at login (the current-user Run key), no terminal-paste row. The sidebar footer holds Check for updates, and Download update for unmanaged installs. Shortcuts are recorded by polling the keyboard with the listener's hook suspended, because modifier-only chords never reach the window as key events.
- Models are prepared in-process through
transcription_preparation; the runtime saves the selection when it is ready and restarts the listener. - Enable on launch waits until first-run setup has recorded completion.
- The dictation HUD is a Rune overlay (
rune_hud.rs, shared with Linux): a HUD thread steps the shared indicator model and Dot scope, and the overlay's compositor draws each frame on the GPU withrune_hud.wgsl; Rune shows it in a topmost tool window withWS_EX_NOACTIVATE|WS_EX_TRANSPARENT|WS_EX_LAYERED, shown withSW_SHOWNOACTIVATE, 12 pt from the top or 24 pt above the taskbar. The same model, shaders, and overlay run on Linux; on Windows it is only type-checked. - The window gets the executable's icon from Rune's
App::on_windowhook (its HWND throughWindowHandle::with_raw_handle) for the taskbar, Alt-Tab, and the caption. The native title bar keeps its icon and title, blended into the window: DWM paints the caption the theme'sbg_deep(DWMWA_CAPTION_COLOR, Windows 11; Windows 10 keeps its own caption color). The view repaints it when the system theme switches. - Without a tray (creation failed) closing the window quits Hex. See the single-process plan.
This app has never run on Windows. Earlier releases shipped a GPUI app that a person did run; that app is gone, and the Rune app replaces it in the next release, so a person must run it on Windows (x64 and ARM64) before that release. It is type-checked by cross-compiling on Linux with cargo-xwin:
rustup target add x86_64-pc-windows-msvc && cargo install cargo-xwin
# clang-cl, lld-link, and llvm-lib must be on PATH (llvm-lib can be a
# symlink to rustup's llvm-tools llvm-ar).
mkdir -p /tmp/no-transcribe/lib
echo '{"libraries":[],"shared":false}' > /tmp/no-transcribe/lib/transcribe-link.json
# TRANSCRIBE_DIR skips the transcribe.cpp/Vulkan CMake build; nothing links in check.
TRANSCRIBE_DIR=/tmp/no-transcribe cargo xwin clippy --target x86_64-pc-windows-msvc \
--all-targets -- -D warningsFor ARM64, add the aarch64-pc-windows-msvc target and set
XWIN_CROSS_COMPILER=clang: ring's aarch64 build forces the GNU-style
clang driver, which rejects the clang-cl /imsvc flags cargo-xwin passes
by default. Also set CARGO_FEATURE_NO_NEON=1: blake3 (through Rune) builds
NEON C that the xwin sysroot's arm64_neon.h macros break under that driver.
That checks every Rust path, including Rune, wgpu's DX12 and Vulkan backends, and the Windows modules; it compiles C build scripts (ring) for the target but never links, builds transcribe.cpp, or runs anything.
Not available on Windows in this build. The windows-shell branch generalized
the authenticated local API (service and service --embedded) across
platforms, but dev has since reshaped it for macOS; porting it onto that
version is follow-up work.
The target is product and visual parity with macOS, using native Windows
adapters where the operating-system APIs differ. A direct copy of AppKit,
CoreAudio event taps, Metal, SMAppService, Accessibility, or
ScreenCaptureKit code would not run on Windows; the Windows implementation must
preserve the same user contract through Win32, WASAPI, Rune (wgpu), the
current-user startup registry, UI Automation, and Windows capture APIs.
| Area | Windows status |
|---|---|
| Local hold-to-dictate, Toggle mode, timestamped boundaries, Escape, paste | Implemented |
| Live model, shortcut, and microphone selection | Implemented |
| Double-tap lock and Paste Last Dictation | Implemented |
| Clipboard preservation and generation-safe restoration | Implemented |
| Recording tones and click-through recording/processing HUD | Implemented; a CPU port of the macOS Metal shader drawn in a Rune overlay, never run on Windows |
| History retention, list, detail, search, copy, delete, and clear | Implemented |
| Text replacements | Implemented in the Windows Modes pane using the shared phrase-boundary replacement engine |
| Application picker in Modes | Implemented; lists Start menu shortcuts, App Paths, and apps with an open window, with each executable's icon; "Choose a file…" opens the native dialog through rune::FileDialogs |
| Interface language | Implemented on every OS; English, Polish, Chinese, Japanese, German, Spanish, and Ukrainian |
| Resident tray and Launch at login | Implemented; the tray menu (shared with Linux) has Paste last dictation, the speech-model picker, and the recording state |
| Application modes with per-mode corrections, OpenCode rewriting, and transformations | Implemented on the shared ordered processing policy; global and contextual profiles persist their own corrections, model, reasoning variant, deadline, and ordered built-in/TypeScript transformations, while modes match by application name — physical end-to-end paste/UI validation remains |
| Recognition hints for Whisper-family models | Implemented |
| Release microphone while idle | Implemented; mutually exclusive with audio pre-roll, as documented in Settings |
| While-dictating audio control (mute other apps or pause media) | Implemented via WASAPI session volumes and GSMTC |
| Signed automatic self-update for managed installs | Implemented for x64 and ARM64; the same ed25519 key and https://anoma.ly/hex/files origin as Linux, one feed per architecture, activating into a user-local versions directory. Checks 10 s after launch and every 6 h (or Check for updates); a staged update shows Restart to update in the tray menu and the window's sidebar footer, and the tray tooltip says an update is available. Source builds keep the GitHub release link (Download update); CI test builds never check |
| Web-domain mode rules and browser context via UI Automation | Implemented; the page URL comes from the browser's UIA document element, bounded so a hung provider degrades to application-only context |
| Managed installer with Start Menu integration and clean uninstall | Implemented as .github/release/install-windows.ps1; it creates the self-updating versions layout, and updates retarget the managed shortcut and Launch-at-login entry |
| First-run onboarding | Implemented; a fresh install picks a dictation language, downloads its recommended model with live progress, and starts listening only once setup is recorded — the shared Rune tour |
| Activity pane with the live session and recent transcripts | Implemented in developer builds; the shared read-only pane |
| Developer Meetings, live drafts, and meeting paste | Missing |
| Local transcription API and public TypeScript SDK host lifecycle on Windows | Missing; see Local Transcription Service |
| Streaming finish with whole-clip fallback | Implemented on GPU devices with Parakeet Unified English |
Settings live in %APPDATA%\hex\settings.json, the same file macOS and
Linux use.
The Windows window uses the shared design system
(design-system.md): the same Rune panes as macOS and
Linux under the native title bar. Mode processing, OpenCode rewriting, and transformations run
through the same dictation_processor and personal_commands modules as
macOS, and Windows reaches the running OpenCode service the same way: its
registration file and loopback HTTP, never a CLI. Like macOS,
an unset OpenCode model tries the ranked recommended models before the
OpenCode default.
Remaining panes should be added only with their complete Windows behavior;
empty look-alike screens do not count as parity.
The Windows listener preserves physical press/release timestamps, keeps audio
capture off the transcription and paste worker, and restores the previous
clipboard only when no newer clipboard change supersedes it.
check-windows builds and tests the optimized MSVC release for x64 and ARM64
on every pull request. The remaining code
parity slice is the developer-only Meetings surface after the physical matrix
is green. Shared
first-run onboarding, complete OpenCode mode rewriting controls, and the bounded
TypeScript transformation host already ship. Windows releases are built for
x64 and ARM64 by
release.yml with
scripts/build-windows.sh, Authenticode-signed,
and published to the Anomaly release service with the other platforms
(docs/releasing.md); .github/release/install-windows.ps1
installs from its stable manifest. Users install
with the command under Install.