Voice I/O companion for CLI AI agents
Features • Installation • Usage • Configuration • Keybindings
vox is a lightweight, cross-platform system tray application that gives any CLI AI agent — or any desktop application — speech input (ASR) and text-to-speech (TTS) capabilities. It works at the system level, injecting recognized text at the cursor position or reading selected text aloud, without requiring any plugin or integration from the target application.
- 🎤 Voice Input — Press a hotkey, speak, and have the transcribed text appear instantly at any cursor position (terminals, editors, browsers, anywhere)
- 🔊 Text-to-Speech — Select text and press a hotkey to hear it read aloud; supports selection copy and clipboard modes
- 🧠 Multiple ASR Engines — Local inference (whisper.cpp HTTP server, whisper-rs FFI) and cloud engines (OpenAI-compatible, Mimo, Aliyun) with automatic fallback
- 🗣️ Multiple TTS Engines — Free Microsoft Edge TTS (no API key) and cloud Mimo TTS, with voice/rate/volume/pitch configuration
- 🌐 Local Translation Routes — inbound detect/source → English and outbound English → a selected language, available for speech, selected text, injection, and TTS
- 🎭 Named LongCat Voices — save any number of
.wav/.mp3/.m4a+ verbatim.txtpairs and switch them from the tray or a hotkey - 🎚️ Native Mic Router — mix multiple Windows input devices with generated speech and send the result to a selectable virtual-microphone endpoint
- 💬 Independent Live Captions — caption the physical microphone mix and native system playback simultaneously, with optional local translation and dubbing
- 🧩 Programmable Route Matrix — save independent input → STT → translate → TTS/text/caption workflows with live-reloadable hotkeys and tray actions
- 📝 Ephemeral Popout — open a disposable text editor, dictate into it, preview/copy local translations, or render its text through a chosen LongCat voice directly to the microphone router; only workflow choices persist
- 🪶 Minimal Footprint — Pure system tray icon with on-demand windows and zero CPU when idle
- 🌍 Global Hotkeys — Fully customizable keybindings for all actions
- 💻 Cross-Platform — Windows, macOS and Linux
- Rust toolchain 1.75+
- A microphone and speakers/headphones
- Linux only: global hotkeys need
/dev/uinputwrite access. Add your user to theinputgroup (then log out and back in):Or grant the device directly:sudo usermod -aG input $USERsudo chmod 0660 /dev/uinput
git clone https://github.com/CommanderTurtle/vox.git
cd vox
# The mic forwarder is currently an opt-in binary. Build all but mic:
cargo build --release
# Release is then at... ./target/release/vox or vox.exeThe native Windows microphone router is a separate opt-in binary and is not part of an ordinary Vox build:
# Build everything (vox -and- the mic forwarder):
cargo build --release --features mic-forwarder --bins
# Build only the mic forwarder on its own:
cargo build --release --features mic-forwarder --bin vox-mic-forwarderOn Windows, install the current VB-CABLE package from the official VB-Audio page, reboot, and run:
.\windows-vb-cable\setup.ps1 -OpenSoundSettingsThe setup helper builds the optional router if needed, verifies CABLE Input and CABLE Output through the router's actual CPAL/WASAPI enumerator, and launches the numbered device wizard. Choose real physical microphones as inputs; Vox writes the completed mix to CABLE Input, while applications use CABLE Output as their microphone. System playback remains on the existing speakers/headphones and stays isolated in the subtitle-only capture lane.
VB-CABLE is separately downloaded and installed under its own license; Vox does
not bundle or silently install it. See the
windows-vb-cable integration guide.
The private backend-only gateway is an equally optional workspace member. It shares CrisperWhisper and LongCat behavior with desktop Vox without pulling in the tray, hotkeys, clipboard, GUI, capture, or device dependencies:
cd http-router-only
./setup
./starthttp.shIts first launch creates http-router-only/target/release/config.toml beside
the binary. See HTTP router documentation.
# (Optional) Start a local ASR server so voice input works offline / free:
# whisper.cpp: ./whisper-server -m ggml-tiny.bin --port 8080
# or any OpenAI-compatible server (faster-whisper, LocalAI, ...) pointed at
# [asr.openai].base_url in the config.
# If no local server runs, vox falls back through the configured engines.
# Run the app
cargo run --release
# The tray icon appears in your system tray.
# Press Alt+` to start recording, say something, press Alt+` again.
# The transcribed text appears at your cursor position.
# Press Alt+T with text selected to hear it read aloud (Edge TTS, no key).This fork can use CrisperWhisper 2.0 in intended/non-literal or literal mode, LongCat
voice cloning with configurable sentence-aware concatenated requests, and a dedicated local
EraX translation service. A known Crisper language is the one-pass fast path; detect is an optional per-utterance
parallel Crisper + XLM-R + EraX-VL arbitration lane. Windows can run the native Vox tray client while
the model services remain inside WSL or on another private-LAN host.
Start with Quick Start. See Local Backends: Windows + WSL for the exact startup sequence, settings, CLI checks, and service ownership boundaries.
- Place your cursor in any text field (terminal, editor, browser)
- Press `Alt+`` to start recording (tray icon turns red)
- Speak into your microphone
- Press `Alt+`` again to stop recording
- The recognized text is automatically injected at your cursor
- Select text in any application
- Press
Alt+Tto hear it read aloud - Or right-click the tray icon →
TTS Input→ switch toClipboardmode to read clipboard content
| Action | Default | Description |
|---|---|---|
| Record | Alt+` | Hold to record (push-to-talk) or press to toggle |
| Switch ASR engine | Alt+Shift+E | Cycle through available engines |
| Switch inject mode | Alt+Shift+V | Toggle keyboard / clipboard injection |
| Open popout editor | Alt+Shift+P | Open the ephemeral compose/translate/STT/hoist window |
| TTS trigger | Alt+T | Read selected text (or clipboard) aloud |
| Switch voice pair | Alt+Shift+T | Cycle saved LongCat audio + transcript pairs |
| LongCat seed +1 | Alt+Shift+S | Increment the persisted LongCat seed by one |
| LongCat seed −1 | Alt+Shift+A | Decrement the persisted LongCat seed by one |
| Translate text | Alt+R | Translate selection/clipboard, then inject |
| Translate + TTS | Alt+Shift+R | Translate selection/clipboard, then speak |
| Speech translate → text | Alt+Ctrl+R | Transcribe, translate with active route, then inject |
| Raw speech → TTS | Alt+Ctrl+` | Transcribe speech and speak it without translation |
| Speech translate → TTS | Alt+Shift+` | Transcribe, translate with active route, then speak |
| Switch route | Alt+Shift+L | Toggle inbound/outbound translation |
The record hotkey behavior depends on the Record Mode (settable in the tray menu or Settings):
- Push-to-Talk (default): hold `Alt+`` to record, release to stop & transcribe
- Toggle: press `Alt+`` to start, press again to stop & transcribe
All keybindings are configurable in config.toml. The Popout and programmable
route chords apply live when Settings is saved; edited legacy chords take
effect the next time Vox starts.
The Popout is also available directly from the tray and from the button in
Settings. Its editor text and translated preview are discarded on close.
Translation target, automatic clipboard-copy choice, and selected LongCat
voice are the only Popout values saved to config.toml.
The Routes page adds live-reloadable workflow hotkeys on top of those
legacy actions. Each preset independently selects microphone/system/selected
text/clipboard input, a Crisper language, optional translation target, and
caption/clipboard/microphone output. The seven first-run presets use
Ctrl+Alt+1 through Ctrl+Alt+7; clear a chord to keep that action tray-only.
Caption presets launch independent processes and non-destructive router
cursors, so multiple translated and untranslated windows may remain active
at the same time—even from the same source device.
Settings exposes two independent global clipboard switches:
- Restore clipboard afterwards restores whatever was present before Vox temporarily copies or pastes.
- Copy only (no paste) leaves every completed STT transcript on the clipboard and skips cursor injection.
Both switches are also checkmarked under the tray's Clipboard Behavior submenu and apply live without changing any recording hotkey.
ASR Engine ▸ whisper-cpp / openai / mimo / aliyun / whisper-local (✓ active)
Inject Mode ▸ Keyboard / Clipboard (✓ active)
Clipboard Behavior ▸ Restore clipboard afterwards / Copy only (no paste) (✓ each)
Record Mode ▸ Push-to-Talk (hold) / Toggle (press) (✓ active)
─────────────
TTS Engine ▸ edge-tts / mimo-tts (✓ active)
TTS Input ▸ Selection (Ctrl+C) / Clipboard (✓ active)
TTS Output ▸ Speakers / Clipboard WAV file / Microphone router (✓ active)
LongCat Voice Pair ▸ each saved .wav/.mp3/.m4a + verbatim .txt pair (✓ active)
LongCat Seed (1024) ▸ − 1 / + 1
Local Translation ▸ Enable / Inbound / Outbound / target language (✓ active)
Live Captions ▸ Microphone or system playback ▸ Native / translated / dub
─────────────
Toggle Recording
Popout…
Settings…
Quit
The active option in each submenu is checkmarked. The menu and tooltip are rebuilt live from a plain-data model whenever state changes — no restart needed when you switch engines or modes.
Configuration is portable: config.toml lives beside the running Vox
executable on every platform. If it is not present there, Vox creates a fresh
one there. No platform config directory or migration path is used.
[hotkey]
record_toggle = "Alt+`"
engine_switch = "Alt+Shift+E"
inject_mode_switch = "Alt+Shift+V"
editor_popout = "Alt+Shift+P"
tts_trigger = "Alt+T"
tts_voice_switch = "Alt+Shift+T"
tts_seed_increment = "Alt+Shift+S"
tts_seed_decrement = "Alt+Shift+A"
translate_text = "Alt+R"
translate_tts = "Alt+Shift+R"
record_translate_text = "Alt+Ctrl+R"
record_tts = "Alt+Ctrl+`"
record_translate_tts = "Alt+Shift+`"
translate_route_switch = "Alt+Shift+L"
[inject]
mode = "keyboard"
restore_clipboard = true
copy_only = false
[editor]
target_language = "English"
copy_translation = false
longcat_voice_profile = "" # empty follows the globally active voice
[asr]
primary_engine = "whisper-cpp" # local, no key
fallback_engines = ["openai"]
[asr.whisper_cpp]
base_url = "http://127.0.0.1:8080" # whisper.cpp HTTP server
[asr.openai]
base_url = "https://api.openai.com/v1" # or a local OpenAI-compatible server
api_key = ""
model = "whisper-1"
[asr.mimo]
base_url = "https://token-plan-cn.xiaomimimo.com/v1"
api_key = ""
model = "mimo-v2.5-asr"
[asr.doubao]
# Volcano Engine Doubao ASR 2.0 (volc.seedasr.sauc.duration).
# Uses the Agent Plan endpoint (/api/v3/plan/sauc/...). When set, doubao-asr
# registers and becomes the default ASR engine.
api_key = ""
[inject]
mode = "keyboard"
[tts]
primary_engine = "edge-tts" # free, no API key
input_mode = "selection"
[tts.edge]
voice = "zh-CN-XiaoxiaoNeural"
rate = "+0%"
volume = "+0%"
pitch = "+0Hz"
[tts.mimo]
model = "mimo-v2.5-tts"
voice = "default"
speed = 1.0
[tts.doubao]
# Doubao TTS 2.0 (seed-tts-2.0). Shares api_key with [asr.doubao].
speaker = "zh_female_vv_uranus_bigtts"
speech_rate = 0 # [-50, 100]
loudness_rate = 0 # [-50, 100]
sample_rate = 24000| Engine | Type | Status |
|---|---|---|
whisper.cpp (whisper-cpp) |
Local (HTTP server) | ✅ Default - no key, no FFI |
OpenAI-compatible (openai) |
Cloud / Local (REST, multipart) | ✅base_url configurable for localhost |
Mimo ASR (mimo) |
Cloud (multimodal chat) | ✅ Needs API key |
Aliyun ASR (aliyun) |
Cloud (一句话识别) | ✅ Needs appkey + token |
Doubao ASR (doubao-asr) |
Cloud (WebSocket, volc.seedasr.sauc.duration) |
✅ Auto-default when key set; needs Doubao Speech key |
Whisper Local (whisper-local) |
Local (whisper-rs FFI) | --features whisper-local + libclang |
| Engine | Type | Status |
|---|---|---|
Edge TTS (edge-tts) |
Cloud (free, no key) | ✅ Default - Microsoft Edge Read Aloud |
Mimo TTS (mimo-tts) |
Cloud (neural TTS) | ✅ Needs API key |
Doubao TTS (doubao-tts) |
Cloud (seed-tts-2.0, HTTP streaming) |
✅ Auto-default when key set; needs Doubao Speech key |
vox/
├── Cargo.toml
├── SPEC.md # Specification
├── PLAN.md # Implementation plan
└── src/
├── main.rs # Event loop, CLI subcommands, engine wiring
├── app/ # State machine & global hotkeys
├── asr/ # AsrEngine trait + manager (fallback) + engines
│ whisper_cpp / openai / mimo / aliyun / whisper_local
├── audio/ # Microphone capture, WAV encode, resampling
├── config/ # TOML configuration (serde-default backwards compat)
├── editor.rs # Ephemeral STT/translation/LongCat popout
├── inject/ # Text injection (keyboard/clipboard) + clipboard snapshot
├── settings/ # egui settings window (pure view over Config snapshot)
├── tray/ # System tray + menu built from a MenuModel
└── tts/ # TtsEngine trait + manager + engines
edge_tts / mimo_tts + rodio playback
# Build
cargo build
# Run with debug logging
RUST_LOG=debug cargo run
# Run tests
cargo test
# Build release
cargo build --release
# Debug CLI subcommands (no GUI):
cargo run -- transcribe <audio.wav> # test ASR with a file
cargo run -- inject "<text>" --mode keyboard # test text injection
cargo run -- tts "<text>" [out.mp3] # test TTS (writes file + plays)
cargo run -- translate "<text>" # test the local translation stageAGPLv3
vox 是一个轻量级、跨平台的系统托盘应用,为任何 CLI AI Agent——以及任何桌面应用——提供**语音输入(ASR)和文字转语音(TTS)**能力。它在系统层面工作,将识别出的文字直接注入光标位置,或朗读选中的文字,无需目标应用安装任何插件。
- 🎤 语音输入 — 按快捷键说话,识别文字即刻出现在任意光标位置(终端、编辑器、浏览器……)
- 🔊 文字转语音 — 选中文字按快捷键自动朗读;支持选中文字和剪贴板两种模式
- 📝 临时弹出编辑器 — 可口述输入、预览/复制本地翻译,或用指定 LongCat 音色将文本直接提交到麦克风路由;仅保存工作流选项
- 🧠 多 ASR 引擎 — 本地推理(whisper.cpp HTTP 服务、whisper-rs FFI)与云端引擎(OpenAI 兼容、Mimo、阿里云)自动 fallback
- 🗣️ 多 TTS 引擎 — 免费微软 Edge TTS(无需 API Key)与云端 Mimo TTS,支持音色/语速/音量/音调配置
- 🪶 极致轻量 — 纯系统托盘图标,无主窗口,空闲时零 CPU 占用
- 🌍 全局快捷键 — 所有操作快捷键完全自定义
- 💻 跨平台 — 支持 Windows、macOS 和 Linux
- Rust 工具链 1.75+
- 麦克风和音箱/耳机
- 仅 Linux: 全局热键需要
/dev/uinput写权限。将用户加入input组(然后重新登录):或直接授权设备:sudo usermod -aG input $USERsudo chmod 0660 /dev/uinput
git clone https://github.com/your-username/vox.git
cd vox
cargo build --release
./target/release/vox# (可选)启动本地 ASR 服务,实现离线/免费语音输入:
# whisper.cpp: ./whisper-server -m ggml-tiny.bin --port 8080
# 或任意 OpenAI 兼容服务(faster-whisper、LocalAI……),把
# [asr.openai].base_url 指向它即可。
# 若无本地服务,vox 会按配置的引擎链自动 fallback。
# 运行
cargo run --release
# 托盘图标出现后,按 Alt+` 开始录音,说完再按 Alt+` 停止
# 识别的文字自动出现在光标位置
# 选中文字按 Alt+T 朗读(Edge TTS,免密钥)- 将光标放在任意文本输入位置(终端、编辑器、浏览器等)
- 按 `Alt+`` 开始录音(托盘图标变红)
- 对着麦克风说话
- 再按 `Alt+`` 停止录音
- 识别结果文字自动注入光标位置
- 在任意应用中选中文字
- 按
Alt+T自动朗读 - 或右键托盘图标 →
TTS Input→ 切换到Clipboard模式读取剪贴板内容
| 操作 | 默认按键 | 说明 |
|---|---|---|
| 录音 | Alt+` | 按住录音(push-to-talk)或按一下切换 |
| 切换 ASR 引擎 | Alt+Shift+E | 循环切换可用引擎 |
| 切换注入模式 | Alt+Shift+V | 键盘模拟 / 剪贴板粘贴 |
| 打开弹出编辑器 | Alt+Shift+P | 打开临时编写/翻译/STT/麦克风提交窗口 |
| TTS 触发 | Alt+T | 朗读选中文字(或剪贴板内容) |
录音热键的行为取决于 Record Mode(可在托盘菜单或设置里切换):
- Push-to-Talk(默认):按住 `Alt+`` 录音,松手停止并识别
- Toggle:按一下 `Alt+`` 开始,再按一下停止并识别
所有快捷键可在 config.toml 中自定义。弹出编辑器也可从托盘或设置窗口打开;
关闭时会丢弃编辑文本和翻译预览,只保存目标语言、自动复制选项和 LongCat 音色。
ASR Engine ▸ whisper-cpp / openai / mimo / aliyun / whisper-local (✓ 当前)
Inject Mode ▸ Keyboard / Clipboard (✓ 当前)
Record Mode ▸ Push-to-Talk (hold) / Toggle (press) (✓ 当前)
─────────────
TTS Engine ▸ edge-tts / mimo-tts (✓ 当前)
TTS Input ▸ Selection (Ctrl+C) / Clipboard (✓ 当前)
─────────────
Toggle Recording
Popout…
Settings…
Quit
各子菜单的当前选项会打勾。菜单与 tooltip 由纯数据模型在状态变化时实时重建,切换引擎/模式无需重启。
配置是可移植的:所有平台上的 config.toml 都位于正在运行的 Vox
可执行文件旁边;如果不存在,Vox 会在该位置创建默认文件。
[hotkey]
record_toggle = "Alt+`"
engine_switch = "Alt+Shift+E"
inject_mode_switch = "Alt+Shift+V"
editor_popout = "Alt+Shift+P"
tts_trigger = "Alt+T"
[editor]
target_language = "English"
copy_translation = false
longcat_voice_profile = "" # 留空则跟随当前全局音色
[asr]
primary_engine = "whisper-cpp" # 本地,免密钥
fallback_engines = ["openai"]
[asr.whisper_cpp]
base_url = "http://127.0.0.1:8080" # whisper.cpp HTTP 服务
[asr.openai]
base_url = "https://api.openai.com/v1" # 也可指向本地 OpenAI 兼容服务
api_key = ""
model = "whisper-1"
[asr.mimo]
base_url = "https://token-plan-cn.xiaomimimo.com/v1"
api_key = ""
model = "mimo-v2.5-asr"
[asr.doubao]
# 火山引擎豆包 ASR 2.0(volc.seedasr.sauc.duration)。
# 使用 Agent Plan 端点(/api/v3/plan/sauc/...)。配置后 doubao-asr
# 自动注册并设为默认 ASR 引擎。
api_key = ""
[inject]
mode = "keyboard"
[tts]
primary_engine = "edge-tts" # 免费,无需 API Key
input_mode = "selection"
[tts.edge]
voice = "zh-CN-XiaoxiaoNeural"
rate = "+0%"
volume = "+0%"
pitch = "+0Hz"
[tts.mimo]
model = "mimo-v2.5-tts"
voice = "default"
speed = 1.0
[tts.doubao]
# 豆包 TTS 2.0(seed-tts-2.0)。与 [asr.doubao] 共用 api_key。
speaker = "zh_female_vv_uranus_bigtts"
speech_rate = 0 # [-50, 100]
loudness_rate = 0 # [-50, 100]
sample_rate = 24000| 引擎 | 类型 | 状态 |
|---|---|---|
whisper.cpp (whisper-cpp) |
本地(HTTP 服务) | ✅ 默认 - 免密钥、无 FFI |
OpenAI 兼容 (openai) |
云端/本地(REST multipart) | ✅base_url 可指向 localhost |
Mimo ASR (mimo) |
云端(多模态对话) | ✅ 需 API Key |
阿里云 ASR (aliyun) |
云端(一句话识别) | ✅ 需 appkey + token |
豆包 ASR (doubao-asr) |
云端(WebSocket,volc.seedasr.sauc.duration) |
✅ 配 Key 后自动设为默认;需 Agent Plan key |
Whisper 本地 (whisper-local) |
本地(whisper-rs FFI) | --features whisper-local + libclang |
| 引擎 | 类型 | 状态 |
|---|---|---|
Edge TTS (edge-tts) |
云端(免费、免密钥) | ✅ 默认 - 微软 Edge 朗读 |
Mimo TTS (mimo-tts) |
云端(神经 TTS) | ✅ 需 API Key |
豆包 TTS (doubao-tts) |
云端(seed-tts-2.0,HTTP 流式) |
✅ 配 Key 后自动设为默认;需 Agent Plan key |
vox/
├── Cargo.toml
├── SPEC.md # 技术规范
├── PLAN.md # 实施计划
└── src/
├── main.rs # 事件循环、CLI 子命令、引擎装配
├── app/ # 状态机 & 全局热键
├── asr/ # AsrEngine trait + manager(fallback) + 各引擎
│ whisper_cpp / openai / mimo / aliyun / whisper_local
├── audio/ # 麦克风采集、WAV 编码、重采样
├── config/ # TOML 配置(serde-default 向后兼容)
├── editor.rs # 临时编写/翻译/STT/麦克风提交窗口
├── inject/ # 文字注入(键盘/剪贴板)+ 剪贴板快照保护
├── settings/ # egui 设置窗口(Config 快照的纯视图)
├── tray/ # 系统托盘 + 由 MenuModel 构建的菜单
└── tts/ # TtsEngine trait + manager + 各引擎
edge_tts / mimo_tts + rodio 播放
# 编译
cargo build
# 调试模式运行(显示详细日志)
RUST_LOG=debug cargo run
# 运行测试
cargo test
# 发布编译
cargo build --release
# 调试 CLI 子命令(无需 GUI):
cargo run -- transcribe <audio.wav> # 用文件测试 ASR
cargo run -- inject "<文字>" --mode keyboard # 测试文字注入
cargo run -- tts "<文字>" [out.mp3] # 测试 TTS(写文件并播放)MIT