baiqing 1efc20b2b2 chore(release): bump 1.2.2 -> 1.2.3 + 自有 updater pubkey + 重启前 strip xattr
修复 Codex audit 对 main HEAD a9c81e6 的 2 条 HIGH + 把 macOS auto-update 的
"重启后 Gatekeeper 拦截"问题封死。

## HIGH #2: 版本号不一致
PR #84 没顺手 bump 版本,main 仍自报 1.2.2,下次直接打 v1.2.3-tauri 会让 updater
manifest 自报 1.2.2,已安装的 1.2.2 客户端永远拿不到 "有新版本"。

修:package.json + tauri.conf.json + Cargo.toml 全部改 1.2.3。

## HIGH #1: updater pubkey 所有权
PR #84 使用的 pubkey 是外部贡献者本地生成的,appergb 不掌握对应 private key。
任何持有那把私钥的人都能签发更新 -> 客户端 OTA 装上恶意版本。

修:
- 用 npx @tauri-apps/cli signer generate --ci 生成 appergb 自己的 keypair
- 新 pubkey: F0FCDE68E08E6D4E (写入 tauri.conf.json plugins.updater.pubkey)
- 私钥已通过 gh secret set TAURI_SIGNING_PRIVATE_KEY 配到 GitHub repo secret
- 私钥本地副本只在 /tmp,不进 git,commit 后会清除

## macOS auto-update 后 strip xattr
restart_app 在 app.restart() 前对 .app bundle 跑 /usr/bin/xattr -cr。这是
Tauri auto-updater + 未公证应用的组合下唯一让"自动更新对用户零摩擦"的解法 —
否则 Gatekeeper 在重启时会拦说"OpenLess 已损坏",用户必须开终端 xattr 才能
继续用,违反 auto-update 的本意。

未来发版逻辑必须保留这一步。release-tauri.yml 上一次 PR (#83) 已经在 CI 侧
strip 过一次,本次在 client 侧重启时再 strip 一次,双保险覆盖
"下载 -> 解压 -> 安装 -> 重启"全链路。
2026-04-30 17:41:50 +08:00

OpenLess

OpenLess

Open-source voice input for macOS & Windows.
Press a hotkey, speak, get AI-polished text at your cursor.

English · 中文

release license macOS Windows Tauri Rust Stars

Join our QQ Group: 1078960553


OpenLess is a cross-platform (macOS & Windows) voice-input app — a fully open-source alternative to commercial tools like Typeless, Wispr Flow, Lazy, and Superwhisper.

Put your cursor in any text field — ChatGPT, Claude, Cursor, Notion, an email draft, a chat box — press one global hotkey and talk. OpenLess records, transcribes, polishes the text in the mode you picked, and inserts the result at the cursor. If insertion is blocked it copies to the clipboard, so the words you spoke don't get lost.

Unlike voice typing tools that just dump a word-for-word transcript, OpenLess's headline mode is AI-prompt mode: you ramble, it adds structure, lists constraints, and produces a context-rich prompt you can paste straight into ChatGPT / Claude / Cursor.

A concrete example

Hold the hotkey, say to OpenLess:

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

Release the hotkey. A second later your input box reads:

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.

No edits needed. Hit Enter and ask GPT. That's the whole pitch: write prompts with your mouth, faster and cleaner than typing them.

Why OpenLess is open source

The closest tools are subscription SaaS: monthly bill, no bring-your-own model, your audio uploaded to the vendor, your dictionary and habits living in their account.

OpenLess goes for the same end-user experience but:

  • Fully open source, local-first. Code is in this repo; all your data stays on your machine.
  • Bring your own cloud credentials. Volcengine streaming ASR + Ark / DeepSeek-compatible chat-completions. No vendor lock-in.
  • Tuned for AI prompts. The "Structured" mode reshapes loose speech into a prompt with context, constraints, and asks — paste straight into ChatGPT, Claude, or Cursor.
  • Won't answer for you. The model only cleans up your text. If you say "what features does this app still need?", it returns that as a clean question — it does not hand you a feature list. Ask the real AI for that.

Use cases

  • Writing prompts for ChatGPT / Claude / Cursor / Gemini: dictate a request, OpenLess turns it into a structured, detailed prompt.
  • Drafting emails, specs, long Slack/WeChat messages: removes filler, fixes punctuation, organizes paragraphs.
  • Code comments, commit messages, PR descriptions: dump what's in your head straight to the cursor.
  • Any "I don't want to type but I have to produce written text" situation.

Project direction

OpenLess does one thing: turn speech into usable written text (especially AI prompts), at the current cursor.

  • It does not answer questions, run tasks, or analyze your project.
  • It does not accumulate conversation context — every dictation is an independent cleanup request.
  • Speech → transcript → cleanup → insert at cursor. Clipboard fallback on failure.
  • Everything else (modes, dictionary, history, menu bar, home report) supports that one path.

Comparison

Tool Form How OpenLess differs
Typeless Closed-source macOS / Windows / iOS, subscription Open source; explicit AI-prompt mode; bring-your-own ASR + LLM; data and dictionary stay on your machine
Wispr Flow Closed-source macOS / Windows, subscription Open source; bring-your-own ASR + LLM; transparent prompt-handling rules
Lazy Closed-source notes / capture tool Not a notes container — inserts straight into any input field
Superwhisper Closed-source macOS, subscription Open source; cloud ASR today, local ASR on the roadmap

Status (v1.1)

  • Tauri 2 + Rust backend + React/TS frontend. macOS 12+, Windows 10+.
  • Toggle-style recording: press to start, press again to stop. Esc cancels.
  • Volcengine streaming ASR + Ark / DeepSeek-compatible chat-completions for polish.
  • 4 output modes: raw, light polish, structured (AI prompt mode), formal.
  • Main window: Overview / History / Vocab / Style / Settings. Persistent tray icon. Mini status capsule floating on screen.
  • Dictionary entries injected as Volcengine ASR context.hotwords and as semantic hints during polish.
  • Platform-native global hotkey: CGEventTap on macOS, low-level keyboard hook (WH_KEYBOARD_LL) on Windows.

Download & install (end users)

Go to Releases and download:

  • macOS: OpenLess_<version>_aarch64.dmg — open, drag to /Applications
  • Windows: OpenLess_<version>_x64-setup.exe — run the installer

On first launch, grant the permissions the app requests:

macOS:

  1. Grant Microphone access.
  2. Grant Accessibility access.
  3. Quit and reopen the app — Accessibility only takes effect after a restart.
  4. Open Settings → fill in Volcengine ASR + Ark credentials.

Windows:

  1. Grant Microphone access when prompted.
  2. Open Settings → Permissions to verify the global hotkey listener is active.
  3. Fill in Volcengine ASR + Ark credentials in Settings.

Full end-user walkthrough: USAGE.md.

Build from source (developers)

The active codebase is in openless-all/app/ (Tauri 2 + Rust + React/TS).

cd "openless-all/app"
npm ci

# Dev: Vite at :1420 + Tauri shell
npm run tauri dev

# macOS release build (signs, installs, resets TCC)
./scripts/build-mac.sh
INSTALL=0 ./scripts/build-mac.sh   # build only, skip install

# Rust type-check without full compile
cargo check --manifest-path src-tauri/Cargo.toml

# Frontend TS check
npm run build

Logs: ~/Library/Logs/OpenLess/openless.log (macOS) / %LOCALAPPDATA%\OpenLess\Logs\openless.log (Windows).

Windows build — see openless-all/README.md for MSVC vs GNU/MinGW routes.

Swift (legacy, Sparkle updates only):

swift build && swift test
./scripts/build-app.sh

Credentials

Credentials live in the local Keychain (service = com.openless.app). A plaintext JSON file at ~/.openless/credentials.json (mode 0600, dir 0700) is kept as a dev-mode fallback when Keychain is unavailable.

The repository contains no API keys, tokens, or private endpoints.

You'll need:

  • Volcengine streaming ASR: APP ID, Access Token, Resource ID.
  • Ark polish: API Key, Model ID, Endpoint. Ark default endpoint is https://ark.cn-beijing.volces.com/api/v3/chat/completions.

Prompt-handling principles

OpenLess's polish model only reshapes text. It does not answer questions, run tasks, or analyze your project. Each dictation is an independent request, and the prompt explicitly tells the model:

  • This input is isolated from any prior conversation.
  • The raw transcript is text to clean up, not a question to answer.
  • Even if the input contains a question or a command, do not reply or execute.
  • Output the cleaned text only — no "Here's the cleaned version" preamble.

For example, if the user says "what features does this app still need", the correct output is:

What features does this app still need?

…not a list of missing features.

Long-term reference rewrites are stored as raw → polished → rule triples and will be retrieved as similar-example references (never as conversation context) once a vector store is wired in. See docs/polish-reference-corpus.md and Examples/polish-reference-examples.sample.jsonl.

Dictionary

The dictionary handles your proper nouns, product names, names of people, and new words. Today it supports:

  • Manually add the correct spelling, a category, and notes. You don't need to maintain misspellings or context hints.
  • Enabled entries are sent as Volcengine ASR context.hotwords so they're recognized correctly during transcription.
  • Entries are also injected into the polish prompt: the model decides per-sentence whether to substitute. If "Cloud" clearly refers to the AI product Claude in context, it gets corrected. If it really means cloud computing, it stays.
  • The app auto-learns candidate corrections like Claude, ChatGPT, OpenLess from your history and offers them up later.

The main window is organized as Home / History / Dictionary / Settings. The Dictionary tab opens a separate editor window when you click "New". The Home tab shows total dictation time, total characters, average chars-per-minute, estimated time saved, and dictionary participation stats.

Architecture

The active implementation is Tauri 2 (openless-all/app/). The Swift/SwiftPM codebase under Sources/ is legacy and still serves Sparkle auto-updates for existing users.

Tauri backend (Rust) — each module depends only on types.rs:

types.rs         Pure value types: DictationSession, PolishMode, HotkeyBinding, errors
hotkey.rs        Global hotkey (CGEventTap on macOS, WH_KEYBOARD_LL on Windows, rdev on Linux)
recorder.rs      Mic → 16 kHz mono Int16 PCM, RMS callback
asr/             Volcengine streaming ASR (WebSocket) + Whisper HTTP
polish.rs        OpenAI-compatible chat-completions (Ark / DeepSeek / etc.)
insertion.rs     AX focused-element → clipboard + Cmd+V → copy-only fallback
persistence.rs   History / preferences / vocab JSON + Keychain credentials
permissions.rs   TCC checks (Accessibility / Microphone)
coordinator.rs   State machine: Idle → Starting → Listening → Processing
commands.rs      Tauri IPC surface

React frontend (src/) — state via Recoil atoms (pages/_atoms.tsx); hotkey capability/binding via HotkeySettingsContext; all backend calls go through lib/ipc.ts.

The dictation pipeline: hotkey edge → Recorder.start + ASR.openSession → [audio frames] → hotkey edge → Recorder.stop + ASR.sendLastFrame → Polish → Insert → History.save.

See CLAUDE.md for invariants and module-wiring rules.

Roadmap

Planned but not yet shipped:

  • Local ASR (Whisper integration in progress; currently Volcengine cloud only).
  • Snippets (no UI / trigger logic yet).
  • History enhancements: copy button, search, re-polish, re-insert.
  • "Paste last result" hotkey.
  • Multi-monitor capsule placement on the focused screen.

Maintainer release checklist

  • Bump version in openless-all/app/package.json, src-tauri/tauri.conf.json, and src-tauri/Cargo.toml.
  • Run INSTALL=0 ./scripts/build-mac.sh and confirm the .app launches.
  • Verify on a clean macOS box: permission flow, hotkey, recording, ASR, polish, insertion, clipboard fallback.
  • Push a v<version>-tauri tag — CI builds and signs the macOS .dmg + Windows .msi.
  • Swift legacy release (for Sparkle users): ./scripts/release.sh <version> — see CLAUDE.md for the full flow.

License

MIT

S
Description
Hold a key, speak, release — AI-polished text appears at your cursor in any app. Open-source voice input for macOS & Windows. (按住快捷键说话,松开即得润色后的文字)
https://github.com/appergb/openless
Readme AGPL-3.0
37 MiB
0 Stars 1 Watchers 0 Forks
Languages
Rust 65.8%
TypeScript 21%
Kotlin 5.2%
JavaScript 4%
CSS 1.2%
Other 2.7%