OpenVibe is an open-source, local-first macOS voice input app inspired by Typeless. It lives in the menu bar, records speech, sends audio to a local dictation service, and inserts polished text into the active app.
OpenVibe currently uses a hybrid pipeline:
microphone audio
-> Qwen3-ASR-0.6B raw transcript
-> optional Gemma 4 E2B audio verification
-> Gemma 4 E2B cleanup, formatting, dictionary and style control
-> auto-insert into the active macOS text field
Option + Space.http://127.0.0.1:8765./Applications/Xcode.app.uv.Install command line prerequisites:
xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
brew install uv python@3.11
If model downloads need a proxy:
export HTTPS_PROXY=http://127.0.0.1:7897
export HTTP_PROXY=http://127.0.0.1:7897
OpenVibe uses LiteRT-LM for Gemma 4 E2B by default. Import the LiteRT model once:
uv tool install litert-lm
litert-lm import \
--from-huggingface-repo litert-community/gemma-4-E2B-it-litert-lm \
gemma-4-E2B-it.litertlm \
gemma-4-e2b-it
The expected Gemma model path after import is:
~/.litert-lm/models/gemma-4-e2b-it/model.litertlm
Qwen3-ASR is installed by the server extras on first run:
Qwen/Qwen3-ASR-0.6B
If Hugging Face asks for authentication:
huggingface-cli login
Do not commit Hugging Face tokens or .env files to the repository.
Clone and enter the repo:
git clone https://github.com/Miraculum1729/OpenVibe.git
cd OpenVibe
Start the local server:
./scripts/run-server
The first run creates .venv and installs:
services/gemma-server[hybrid]
In another terminal, start the macOS app:
./scripts/run-mac
For UI testing without loading Qwen/Gemma:
./scripts/run-mock-server
./scripts/run-mac
Recommended:
./scripts/package-mac
open dist/OpenVibe.app
If SwiftPM or xcrun is confused by SDK/compiler state, use the direct Xcode compiler fallback:
./scripts/package-mac-direct
open dist/OpenVibe.app
The app automatically starts the local server on launch and listens on the configured port, default 127.0.0.1:8765.
OpenVibe needs:
Enable them in:
System Settings -> Privacy & Security -> Microphone
System Settings -> Privacy & Security -> Accessibility
If auto-insert fails after rebuilding the app:
System Settings -> Privacy & Security -> Accessibility.dist/OpenVibe.app.Without Accessibility permission, OpenVibe still copies the result to the clipboard, but macOS may block automatic insertion.
OpenVibe.app.设置.Option + Space to start recording.Option + Space again to stop.The menu bar only contains:
设置退出 OpenVibe50.#term chips.The automatic dictionary is correction-based, not frequency-based. After OpenVibe inserts text, it observes short-term edits in the target text field and extracts useful corrected terms such as product names, acronyms, mixed Chinese/English names, and domain-specific terms. It avoids adding ordinary filler words and simple numeric formatting changes.
Gemma verification uses roughly 20 second audio chunks to stay within Gemma 4 E2B's audio limits and keep latency manageable.
The server reads OPENVIBE_ environment variables:
OPENVIBE_HOST=127.0.0.1
OPENVIBE_PORT=8765
OPENVIBE_BACKEND=litert
OPENVIBE_ASR_BACKEND=qwen3
OPENVIBE_ASR_MODEL_ID=Qwen/Qwen3-ASR-0.6B
OPENVIBE_ASR_LANGUAGE=
OPENVIBE_GEMMA_VERIFICATION_CHUNK_SECONDS=20
OPENVIBE_LITERT_MODEL_PATH=~/.litert-lm/models/gemma-4-e2b-it/model.litertlm
OPENVIBE_MODEL_ID=google/gemma-4-E2B-it
OPENVIBE_MAX_NEW_TOKENS=512
OPENVIBE_ENABLE_MOCK=false
Run with a different server setting:
OPENVIBE_PORT=8766 ./scripts/run-server
Use the Transformers backend instead of LiteRT-LM:
OPENVIBE_BACKEND=transformers ./scripts/run-server
Check server health:
curl http://127.0.0.1:8765/health
Expected real-model health response includes:
{
"ok": true,
"pipeline": "hybrid",
"backend": "litert",
"asr": "Qwen/Qwen3-ASR-0.6B",
"mock": false
}
Default local data locations:
~/Library/Application Support/OpenVibe/Recordings
Ignored development artifacts:
.venv/
.build/
dist/
*.wav
*.log
hf_cache/
Model files are expected outside the repo, for example:
~/.litert-lm/models/
Check whether something is listening on the port:
lsof -nP -iTCP:8765 -sTCP:LISTEN
curl http://127.0.0.1:8765/health
Quit OpenVibe and reopen it. On launch, OpenVibe tries to free the configured port before starting its managed server.
This means the text was copied to the clipboard, but macOS blocked automatic insertion. Re-add the current OpenVibe.app under Accessibility permissions.
This usually means macOS sees a rebuilt app bundle as a new app identity. Re-add the latest dist/OpenVibe.app in Privacy & Security.
Use a proxy if needed:
export HTTPS_PROXY=http://127.0.0.1:7897
export HTTP_PROXY=http://127.0.0.1:7897
If you only want to test the menu bar app, settings UI, permissions, and insertion flow:
./scripts/run-mock-server
./scripts/run-mac
Build:
swift build
Run the app:
./scripts/run-mac
Run the server:
./scripts/run-server
Package:
./scripts/package-mac-direct
Git identity used during local development:
git config user.email "pfp23@mails.tsinghua.edu.cn"
See LICENSE.
2 commits
Swift
82.7%
Python
16.0%
Shell
1.3%
OpenVibe is an open-source, local-first macOS voice input app inspired by Typeless. It lives in the menu bar, records speech, sends audio to a local dictation service, and inserts polished text into the active app.
OpenVibe currently uses a hybrid pipeline:
microphone audio
-> Qwen3-ASR-0.6B raw transcript
-> optional Gemma 4 E2B audio verification
-> Gemma 4 E2B cleanup, formatting, dictionary and style control
-> auto-insert into the active macOS text field
Option + Space.http://127.0.0.1:8765./Applications/Xcode.app.uv.Install command line prerequisites:
xcode-select -s /Applications/Xcode.app/Contents/Developer
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
brew install uv python@3.11
If model downloads need a proxy:
export HTTPS_PROXY=http://127.0.0.1:7897
export HTTP_PROXY=http://127.0.0.1:7897
OpenVibe uses LiteRT-LM for Gemma 4 E2B by default. Import the LiteRT model once:
uv tool install litert-lm
litert-lm import \
--from-huggingface-repo litert-community/gemma-4-E2B-it-litert-lm \
gemma-4-E2B-it.litertlm \
gemma-4-e2b-it
The expected Gemma model path after import is:
~/.litert-lm/models/gemma-4-e2b-it/model.litertlm
Qwen3-ASR is installed by the server extras on first run:
Qwen/Qwen3-ASR-0.6B
If Hugging Face asks for authentication:
huggingface-cli login
Do not commit Hugging Face tokens or .env files to the repository.
Clone and enter the repo:
git clone https://github.com/Miraculum1729/OpenVibe.git
cd OpenVibe
Start the local server:
./scripts/run-server
The first run creates .venv and installs:
services/gemma-server[hybrid]
In another terminal, start the macOS app:
./scripts/run-mac
For UI testing without loading Qwen/Gemma:
./scripts/run-mock-server
./scripts/run-mac
Recommended:
./scripts/package-mac
open dist/OpenVibe.app
If SwiftPM or xcrun is confused by SDK/compiler state, use the direct Xcode compiler fallback:
./scripts/package-mac-direct
open dist/OpenVibe.app
The app automatically starts the local server on launch and listens on the configured port, default 127.0.0.1:8765.
OpenVibe needs:
Enable them in:
System Settings -> Privacy & Security -> Microphone
System Settings -> Privacy & Security -> Accessibility
If auto-insert fails after rebuilding the app:
System Settings -> Privacy & Security -> Accessibility.dist/OpenVibe.app.Without Accessibility permission, OpenVibe still copies the result to the clipboard, but macOS may block automatic insertion.
OpenVibe.app.设置.Option + Space to start recording.Option + Space again to stop.The menu bar only contains:
设置退出 OpenVibe50.#term chips.The automatic dictionary is correction-based, not frequency-based. After OpenVibe inserts text, it observes short-term edits in the target text field and extracts useful corrected terms such as product names, acronyms, mixed Chinese/English names, and domain-specific terms. It avoids adding ordinary filler words and simple numeric formatting changes.
Gemma verification uses roughly 20 second audio chunks to stay within Gemma 4 E2B's audio limits and keep latency manageable.
The server reads OPENVIBE_ environment variables:
OPENVIBE_HOST=127.0.0.1
OPENVIBE_PORT=8765
OPENVIBE_BACKEND=litert
OPENVIBE_ASR_BACKEND=qwen3
OPENVIBE_ASR_MODEL_ID=Qwen/Qwen3-ASR-0.6B
OPENVIBE_ASR_LANGUAGE=
OPENVIBE_GEMMA_VERIFICATION_CHUNK_SECONDS=20
OPENVIBE_LITERT_MODEL_PATH=~/.litert-lm/models/gemma-4-e2b-it/model.litertlm
OPENVIBE_MODEL_ID=google/gemma-4-E2B-it
OPENVIBE_MAX_NEW_TOKENS=512
OPENVIBE_ENABLE_MOCK=false
Run with a different server setting:
OPENVIBE_PORT=8766 ./scripts/run-server
Use the Transformers backend instead of LiteRT-LM:
OPENVIBE_BACKEND=transformers ./scripts/run-server
Check server health:
curl http://127.0.0.1:8765/health
Expected real-model health response includes:
{
"ok": true,
"pipeline": "hybrid",
"backend": "litert",
"asr": "Qwen/Qwen3-ASR-0.6B",
"mock": false
}
Default local data locations:
~/Library/Application Support/OpenVibe/Recordings
Ignored development artifacts:
.venv/
.build/
dist/
*.wav
*.log
hf_cache/
Model files are expected outside the repo, for example:
~/.litert-lm/models/
Check whether something is listening on the port:
lsof -nP -iTCP:8765 -sTCP:LISTEN
curl http://127.0.0.1:8765/health
Quit OpenVibe and reopen it. On launch, OpenVibe tries to free the configured port before starting its managed server.
This means the text was copied to the clipboard, but macOS blocked automatic insertion. Re-add the current OpenVibe.app under Accessibility permissions.
This usually means macOS sees a rebuilt app bundle as a new app identity. Re-add the latest dist/OpenVibe.app in Privacy & Security.
Use a proxy if needed:
export HTTPS_PROXY=http://127.0.0.1:7897
export HTTP_PROXY=http://127.0.0.1:7897
If you only want to test the menu bar app, settings UI, permissions, and insertion flow:
./scripts/run-mock-server
./scripts/run-mac
Build:
swift build
Run the app:
./scripts/run-mac
Run the server:
./scripts/run-server
Package:
./scripts/package-mac-direct
Git identity used during local development:
git config user.email "pfp23@mails.tsinghua.edu.cn"
See LICENSE.
2 commits
Swift
82.7%
Python
16.0%
Shell
1.3%