IPC — Commands
How the renderer calls into Rust via Tauri commands and tauri-specta bindings
The renderer talks to the Rust backend through Tauri commands — typed request/response
functions. There is no WebSocket and no separate process; an invoke is a direct call into
Rust on the Tauri runtime. Push notifications go the other way as events.
How a call reaches Rust
Commands are plain Rust functions annotated #[tauri::command] #[specta::specta], collected
in lib.rs::make_specta_builder() via collect_commands![...] and mounted as the app's
invoke_handler. tauri-specta reads those signatures and generates a typed TypeScript
client.
renderer calls commands.winsttSetParameter(parameter, value) (generated src/bindings.ts)
→ TAURI_INVOKE("winstt_set_parameter", …)
→ invoke_handler → winstt::commands::dictation::winstt_set_parameter()
→ Result<T, String> → { status: "ok", data } | { status: "error", error }Two pieces make this work:
src/bindings.ts
Generated by tauri-specta. Every command is a typed wrapper returning
{ status: "ok", data } | { status: "error", error }. A #[test] export_bindings regenerates it so CI can git diff --exit-code and fail
if the file drifts from the live command registry.
collect_commands![]
In src-tauri/src/commands_registry.rs — the single list mounted as the
app's invoke_handler. A completeness guard test fails if a
#[tauri::command] function is missing from it, so the generated bindings
can never silently drift from the live registry.
One typed path, no string channels
Every renderer call site calls commands.* directly, so a signature change in Rust
breaks the TypeScript build. The old string-channel funnel — ipc-channels.ts →
ipc-transport.ts COMMAND_INVOKERS → native-bridge-adapter.ts ROUTE, all fronted
by a window.nativeBridge polyfill — was deleted in 720890c6.
src/shared/api/native-boundary.test.ts now scans every non-test file under src/
and fails the build if any of it comes back.
Command Catalog
~200 commands live in src-tauri/src/winstt/commands/ (plus a handful of legacy commands in
src-tauri/src/commands/), grouped by concern:
| Group | Module | Representative commands |
|---|---|---|
| Dictation | dictation.rs | winstt_set_model, winstt_set_parameter, winstt_call_method |
| Hotkey | hotkey.rs | hotkey_register, hotkey_start_recording, hotkey_stop_recording |
| STT models | stt.rs, runtime.rs | list_models, list_models_with_state, picker_quantizations_for, set_custom_model |
| Downloads | download.rs | predownload_quant, download_pause/resume/cancel_quant, delete_model_quantization |
| TTS | tts.rs | tts_speak, tts_cancel, tts_list_voices, tts_predownload_model |
| LLM | llm.rs | process_text, process_transform, scan_ollama_models, ollama_pull |
| Cloud STT | cloud_stt.rs, verify.rs | verify_cloud_stt_credential, verify_integration_credential |
| Settings | settings.rs, secret_storage.rs | winstt_get_settings, winstt_set_settings (secrets sealed enc:v1:) |
| Audio / system | audio_devices.rs, runtime.rs | get_audio_devices, gpu_get_info, get_runtime_info |
| History | history.rs | history_list, history_load_audio, align_words |
| Files / listen | file_transcribe.rs, listen.rs | file_transcribe_enqueue, start_listen, stop_listen |
| Windows / tray | windows.rs, tray_menu.rs | open_window, resize_window, show_tray_menu |
| Diagnostics | diag.rs, about.rs | diag_save_bundle, about_get_app_info, get_notices |
Failure handling is tiered
invoke() mutations on the critical path (download/delete/reload, settings save) re-throw on
error; high-blast-radius reads log and fall back. The adapter logs channel + argument digest
- error before any fallback, so a swallowed failure is still observable in the console.