OpenLess open-source voice input for macOS & Windows — press a hotkey, speak, get AI-polished text inserted at your cursor in any app.
triggers
["set up OpenLess voice input","configure OpenLess hotkey dictation","build OpenLess from source","add OpenLess voice input to my app","OpenLess ASR credentials setup","OpenLess dictionary and vocab","OpenLess polish modes explained","troubleshoot OpenLess not inserting text"]
OpenLess is a cross-platform (macOS 12+, Windows 10+) voice-input app built with Tauri 2 + Rust + React/TypeScript. Press a global hotkey, speak, release — the app records audio, transcribes via Volcengine streaming ASR or Whisper, polishes the transcript with an LLM, and inserts the result at the active cursor in any app. It is a fully open-source alternative to Typeless, Wispr Flow, and Superwhisper.
Installation (End Users)
macOS
Download OpenLess_<version>_aarch64.dmg from Releases.
Open the DMG, drag OpenLess.app to /Applications.
Launch, grant Microphone and Accessibility permissions when prompted.
Quit and reopen — Accessibility only takes effect after a restart.
Open Settings → fill in ASR + LLM credentials.
Windows
Download OpenLess_<version>_x64-setup.exe from Releases.
Run the installer.
Grant Microphone access when prompted.
Open Settings → Permissions → verify the global hotkey listener is active.
Windows: MSVC build tools or MinGW (see openless-all/README.md)
Steps
git clone https://github.com/appergb/openless.git
cd openless/openless-all/app
npm ci
# Development (Vite at :1420 + Tauri shell with hot reload)
npm run tauri dev
# Production build — macOS (signs, installs, resets TCC)
./scripts/build-mac.sh
# Build only, skip install step
INSTALL=0 ./scripts/build-mac.sh
# Rust type-check without full compile
cargo check --manifest-path src-tauri/Cargo.toml
# Frontend TypeScript type-check
npm run build
Credentials are stored in the platform Keychain (service = com.openless.app). A plaintext fallback is written to ~/.openless/credentials.json (mode 0600) when Keychain is unavailable in dev mode.
Never commit API keys. Reference them via environment variables or enter them in the Settings UI.
Required credentials
Key
Where to get it
Volcengine ASR APP ID
Volcengine console → Speech Recognition
Volcengine ASR Access Token
Same console
Volcengine ASR Resource ID
Same console
Ark/LLM API Key
Volcengine Ark console or any OpenAI-compatible provider
hotkey DOWN
→ coordinator: Idle → Starting → Listening
→ recorder.start() + asr.open_session()
→ [audio frames streamed to ASR via WebSocket]
hotkey UP
→ recorder.stop() + asr.send_last_frame()
→ coordinator: Listening → Processing
→ polish(transcript, mode) → LLM API call
→ insertion.insert_at_cursor(polished_text)
├─ AX focused element write (macOS Accessibility API)
├─ clipboard + Cmd+V / Ctrl+V paste
└─ copy-only fallback (text in clipboard, user pastes manually)
→ history.save(session)
→ coordinator: Processing → Idle
Esc cancels at any phase including polish/insert.
Polish Modes
Mode
Tauri enum
Behaviour
Raw
PolishMode::Raw
Transcript verbatim, no LLM call
Light
PolishMode::Light
Remove filler words, fix punctuation
Structured
PolishMode::Structured
AI-prompt mode — reshapes speech into a structured, context-rich prompt
Formal
PolishMode::Formal
Formal prose, fixes grammar, organises paragraphs
Structured mode — what it does
Input (spoken): "uh so I want ChatGPT to write me a SQL query from the orders table get last month's orders group by customer sort by amount desc top ten"
Output inserted at cursor:
Please write a SQL query that:
- Pulls orders from last month from the `orders` table.
- Groups by customer.
- Sorts by total amount, descending.
- Returns the top 10 rows only.
Key invariant: the LLM only reshapes your text. It does not answer questions or execute commands. If you say "what features are missing?", the output is What features are missing? — not a feature list.
IPC Surface (Frontend → Backend)
All calls go through src/lib/ipc.ts using Tauri's invoke().
// src-tauri/src/types.rs#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]pubenumPolishMode {
Raw,
Light,
Structured,
Formal,
// Add your mode:
Technical,
}
// src-tauri/src/polish.rsfnbuild_system_prompt(mode: &PolishMode) -> &'staticstr {
match mode {
PolishMode::Raw => "",
PolishMode::Light => LIGHT_PROMPT,
PolishMode::Structured => STRUCTURED_PROMPT,
PolishMode::Formal => FORMAL_PROMPT,
PolishMode::Technical => {
"You are a technical writer. Convert the spoken transcript into \
precise technical documentation prose. Use correct terminology. \
Do not answer questions — output the cleaned text only, no preamble."
}
}
}
Dictionary / Vocabulary
Dictionary entries are sent as Volcengine ASR context.hotwords (improving transcription accuracy) and injected into the polish prompt (the LLM applies context-aware substitution).
Adding entries via UI
Settings → Dictionary tab → New button → fill Word, Category, Notes → Save.
macOS: Ensure Accessibility permission is active. CGEventTap silently fails without it.
Windows: Another app may have grabbed the same key combo. Change the hotkey in Settings.
Only one OpenLess instance can run (single-instance lock). Check Activity Monitor / Task Manager.
ASR returns empty / garbled transcript
Verify Volcengine ASR credentials: APP ID, Access Token, Resource ID all correct.
Check microphone sample rate — OpenLess records at 16 kHz mono Int16 PCM. Some USB mics need explicit configuration.
Check openless.log for WebSocket errors.
LLM polish not working / timeout
Verify Ark API Key and Model ID.
Confirm endpoint is reachable: curl -s $OPENLESS_ARK_ENDPOINT (should return 401, not timeout).
DeepSeek / OpenAI-compatible endpoints work — set the endpoint URL in Settings.
Build fails on macOS: codesign error
# Skip signing for local dev build
CODESIGN_IDENTITY="" INSTALL=0 ./scripts/build-mac.sh
Cargo check errors after pulling
cd openless-all/app
cargo check --manifest-path src-tauri/Cargo.toml
# Look for changed feature flags in Cargo.toml# Run `cargo update` if lock file is stale
Key Files Reference
File
Purpose
src-tauri/src/coordinator.rs
Master state machine — start here to understand the flow