Say "Hey Claude" and dispatch a Claude Code background agent — a fully local, on-device voice wake word for your Mac.
Project description
hey-claude
Say "Hey Claude, fix the failing tests" out loud. A Claude Code agent spins up in the background and gets to work. Fully on-device — no cloud wake word, no API key to listen, no per-user signup.
hey-claude is an always-listening wake word for Claude Code
on macOS. When it hears "hey claude," it captures what you say next,
transcribes it locally, and dispatches it as a background agent with
claude --bg. You keep talking; the agents keep stacking up in claude agents.
┌─────────┐ ┌───────────────┐ ┌──────────────┐ ┌──────────────────┐ ┌───────────────────┐
│ mic │──▶│ openWakeWord │──▶│ endpoint by │──▶│ MLX Whisper │──▶│ claude --bg │
│ 16kHz │ │ "hey claude"? │ │ silence │ │ (transcribe cmd) │ │ "<your command>" │
└─────────┘ └───────────────┘ └──────────────┘ └──────────────────┘ └───────────────────┘
always-on tiny on-device VAD on the Apple-Silicon GPU detached agent,
capture classifier command tail local transcription survives terminal
Everything before the final step stays on your machine. The only thing that leaves is the command you ask your agent to run — and that goes exactly where that agent already sends it.
The story behind it: I taught my Mac to launch coding agents when I say "Hey Claude" — the on-device pipeline, and how the wake words were trained on free cloud GPUs.
Work with us
hey-claude is built and maintained by Levelbrook Consulting,
a senior software engineering practice. The same care that went into the
on-device audio pipeline, the safe single-argv dispatch, and the
trained-from-scratch wake words is the care we bring to client work: Ruby/Rails,
Python, AWS, and AI tooling that has to survive production.
We take on contract work — corp-to-corp, remote, Pacific Time. If you're building agent-driven tooling, voice/ML features, or just need senior hands on a Rails or Python system, get in touch → or read how we work.
Requirements
hey-claude is macOS + Apple-Silicon only. It transcribes your speech locally with MLX Whisper, which runs on the Metal GPU of an Apple-Silicon chip — there's no Linux, Windows, or Intel-Mac build.
| Need | Why |
|---|---|
| macOS | MLX + CoreAudio; no cross-platform build |
| Apple Silicon (M1 or newer) | MLX Whisper runs on the Metal GPU |
| Python 3.10–3.13 | ML wheels (MLX, onnxruntime) |
Claude Code ≥ 2.1.139 |
the claude --bg agent it dispatches to (or point it at another agent) |
You won't waste time finding out the hard way: hey-claude fails fast with a
friendly message the moment you start it on an unsupported OS/CPU, or without
MLX Whisper installed — before any model loads. Run hey-claude doctor any time
for the full environment check.
Install
# PortAudio is the only system dependency
brew install portaudio
# recommended — installs the latest release in an isolated environment
pipx install git+https://github.com/tachyurgy/hey-claude@v0.3.0
Also on Homebrew and PyPI, but those can trail the newest tag — use the pinned
git+…@v0.3.0 above for the latest:
brew install tachyurgy/tap/hey-claude # Homebrew tap
pipx install hey-claude # or: pip install hey-claude (PyPI)
Then run the first-run check, which tells you exactly what (if anything) is missing:
hey-claude doctor
Quickstart
It works the moment it's installed — a "hey claude" wake word ships in the box, so there's no training step to start:
hey-claude # starts listening with the bundled "hey claude" model
Now say: "Hey Claude, add type hints to utils.py and run the tests."
You'll hear a chime, then a confirmation, and a new row appears in claude agents.
Want a different trigger phrase? Several wake words ship bundled — switch with one command (see Bundled wake words):
hey-claude models # list the bundled + installed models
hey-claude models use hey_computer
Microphone permission (the one macOS gotcha)
macOS grants microphone access to an app with a stable identity. There are two paths:
-
Running from Terminal: the first time you start
hey-claude, macOS prompts for mic access for your terminal — click Allow. Done. -
Running at login / headless: a bare CLI launched by
launchdoften can't raise that prompt. Build the bundled.app, which has its own identity macOS can grant:hey-claude app # builds ~/Applications/Hey Claude.app open "$HOME/Applications/Hey Claude.app" # click Allow on the mic prompt
Then add it to System Settings → General → Login Items to start at login.
Bundled wake words (mileage may vary)
Several openWakeWord models ship in the box, so you can pick a trigger phrase without training anything:
| Model | Say | Notes |
|---|---|---|
hey_claude (default) |
"hey claude" | the phrase the tool is named for |
okay_claude |
"okay claude" | alternate Claude trigger |
hey_computer |
"hey computer" | Star-Trek style, distinct from any product name |
hey_assistant |
"hey assistant" | generic, agent-neutral |
hey_agent |
"hey agent" | generic, agent-neutral |
hey-claude models # list bundled + installed, shows the active one
hey-claude models use hey_computer
Mileage may vary. These are small models trained on a modest synthetic-speech
budget — they're speaker-independent, but real-world accuracy and the
false-positive rate depend on your mic, room, and accent. If one fires too often,
raise threshold; if it misses you, lower it. If none are reliable enough, train
your own dialed-in model (next section).
Training your own wake word
openWakeWord models are trained on 100% synthetic speech — you never record your voice, and the result is speaker-independent. The fastest free path is the official Colab notebook:
hey-claude train # opens the notebook + prints the steps
Set the phrase, pick a free T4 GPU, Run all (~10 min), download the .onnx,
then hey-claude import-model <path>. See
openWakeWord for details. There's a
headless, scriptable version of the same recipe in
training/train_wakewords.py.
No model at all? The fallback engine matches the phrase from a Whisper transcript with zero setup (slightly more CPU):
hey-claude config set engine whisper
Configuration
Everything is configurable two ways — the CLI, or by editing the config file
directly. Config lives at ~/.config/hey-claude/config.toml
(hey-claude config path):
hey-claude config show # print every setting
hey-claude config set threshold 0.6 # change one from the CLI
hey-claude config edit # open the TOML in $EDITOR
The file is plain TOML — hey-claude config edit just opens it; any key in the
table below can be set there by hand and takes effect on next start.
Launch any agent — not just Claude
A wake doesn't have to run claude. It runs whatever agent you point it at.
Switch with one command:
hey-claude agent list # see the presets + which is active
hey-claude agent use codex # now "hey claude, <task>" drives Codex
| Preset | What a heard command runs |
|---|---|
claude-bg (default) |
claude --bg "<command>" — detached background agent, watch it in claude agents |
claude-terminal |
a new Terminal running claude "<command>" so you can supervise/approve |
claude-print |
claude -p "<command>" headless one-shot, output appended to the log |
codex |
codex exec "<command>" — OpenAI Codex CLI |
aider |
aider --yes --message "<command>" |
opencode |
opencode run "<command>" |
gemini |
gemini --prompt "<command>" |
The external presets are honest starting points — third-party CLIs change their flags, so confirm yours and tune the template.
Fully custom — any command at all
Under the hood every preset just sets launch_template, which you can write
yourself. It's a shell-style token list; placeholders are substituted per
token, and the {command} token is always passed as a single argument, so a
spoken command can never inject extra flags or shell metacharacters:
hey-claude config set launch_template 'my-agent --name {name} --prompt {command}'
Or in the file directly:
# ~/.config/hey-claude/config.toml
launch_template = 'claude --bg --name {name} --permission-mode acceptEdits --model opus {command}'
Placeholders: {command} {name} {permission_mode} {model} {claude_bin}.
Leave launch_template empty to use the native claude launch modes (which keep
full support for permission_mode, claude_model, and max_concurrent).
Configurable sounds
Each event plays a sound; override any of them with a file path or a macOS
system-sound name (from /System/Library/Sounds), or none to silence one:
hey-claude config set sound_wake Hero # system sound by name
hey-claude config set sound_dispatch ~/snd/go.wav
hey-claude config set sound_cancel none
hey-claude config set chime false # disable all sounds
There are two listening cues, Siri-style: sound_wake when it starts listening
and sound_endpoint the moment you stop talking and it begins transcribing.
| Event | Default | When it plays |
|---|---|---|
sound_wake |
Tink | the wake word was detected — start talking |
sound_endpoint |
Pop | you stopped talking; capture ended, now transcribing |
sound_dispatch |
Glass | an agent was successfully dispatched |
sound_cancel |
Funk | wake fired but no command followed / you cancelled |
sound_error |
Basso | dispatch failed |
Key settings
| Key | Default | Notes |
|---|---|---|
engine |
openwakeword |
or whisper (no model file needed) |
wakeword_model |
"" |
bundled name (hey_claude…), a path, or empty for the default |
wake_phrase |
hey claude |
also used by the whisper engine |
threshold |
0.5 |
openWakeWord score; higher = fewer false positives |
whisper_model |
mlx-community/whisper-large-v3-turbo |
command transcription |
launch_template |
"" |
run any agent; empty = native claude modes (see above) |
permission_mode |
"" |
e.g. acceptEdits, plan for dispatched agents |
claude_model |
"" |
model for dispatched agents |
max_concurrent |
0 |
0 = unlimited; else refuse to dispatch past N live bg sessions |
confirm |
false |
require Enter before each dispatch |
Run at login (launchd)
hey-claude install # installs a launchd user agent (starts at login, restarts on crash)
hey-claude status
hey-claude stop / start / uninstall
Grant mic permission first (see above) or the service will receive silent audio.
Uninstalling
hey-claude keeps state in three places a package manager won't clean up: the
launchd agent (~/Library/LaunchAgents), your config and trained wake-word
models (~/.config/hey-claude), and the .app bundle (~/Applications). The
teardown command removes all three:
hey-claude uninstall # just the launchd agent
hey-claude uninstall --all # + config, trained models, and the .app (asks first)
Run --all before removing the package, since brew/pipx/pip can't
reach those paths. Two things it can't do for you: clear the macOS microphone
grant (revoke it in System Settings → Privacy & Security → Microphone), and
remove the package itself:
brew uninstall hey-claude # or: pipx uninstall hey-claude / pip uninstall hey-claude
Safety
A voice trigger carries false-positive risk, so the defaults are conservative:
the bg launch mode runs each agent in Claude Code's supervisor (with its normal
permission prompts and per-session git worktree isolation). If you set a
non-interactive permission mode like acceptEdits or bypassPermissions, an
agent can act without you watching — scope it deliberately, and consider
max_concurrent and confirm.
How it works
- Wake — openWakeWord runs a ~250 KB classifier over a frozen Google speech
embedding on each 80 ms frame. A score above
threshold(outside a short refractory window) is a wake. Lowest possible CPU for always-on listening. - Endpoint — once woken (and after the
wakecue plays), a small energy VAD records the command and stops after ~800 ms of trailing silence, keeping a short pre-roll so the first syllable isn't clipped. The moment it stops, theendpointcue plays so you know it heard you and is now thinking. - Transcribe — the command audio goes to MLX Whisper (Metal GPU), which returns text in well under a second on Apple Silicon.
- Dispatch — the text is passed verbatim as a single argument to
claude --bg, which hands it to Claude Code's background-session supervisor.
Documentation
- The build log — how it works and how the wake words were trained (Levelbrook engineering blog)
- Architecture — the four-stage pipeline and why it's built this way
- Contributing — setup, project layout, good first issues
- Changelog
- Release runbook — tagging, Homebrew, PyPI
Development
git clone https://github.com/tachyurgy/hey-claude
cd hey-claude
brew install portaudio
python3.12 -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest
License
MIT. See LICENSE.
Built and maintained by Levelbrook Consulting — a senior software engineering practice (Rails · Python · AWS · AI tooling). Available for contract work, corp-to-corp. Get in touch →
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hey_claude-0.3.0.tar.gz.
File metadata
- Download URL: hey_claude-0.3.0.tar.gz
- Upload date:
- Size: 7.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3cbcf35e3be6220765209e14bd9224f5da7126d1fc2c3471e7e9e7707468b453
|
|
| MD5 |
15d189460099b3195d935b9778661360
|
|
| BLAKE2b-256 |
ca003d13169622ce8307bfc705d63e085082b427a3b7209fc1d9d5210d382042
|
File details
Details for the file hey_claude-0.3.0-py3-none-any.whl.
File metadata
- Download URL: hey_claude-0.3.0-py3-none-any.whl
- Upload date:
- Size: 7.6 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0aea58a8cbba09a496fa945b2f16e7a26e1d27f618841791364315b58d83fcf0
|
|
| MD5 |
00514484fafff5d655650d83e83bd63f
|
|
| BLAKE2b-256 |
6ec2b7fe95050878603fa9f8568214f539f5f8eca9bddc0102f727c511717085
|