| name | voice-mode |
| description | Hands-free voice input for Claude Code. Runs a local whisper.cpp daemon that transcribes microphone speech into complete utterances; Monitor delivers each one to the chat. Use when the user asks to start, stop, or pause voice mode, or when working hands-free. |
Voice Mode — Hands-Free Dictation
Voice mode lets the user talk to Claude without typing. A daemon
(voice-mode) runs in the background, continuously transcribes the
microphone, and appends one line per complete utterance to a log file.
Claude tails that log via the Monitor tool, so each spoken utterance
arrives as a chat notification.
Prereq: the voice-mode binary on PATH and whisper-cpp installed
(brew install whisper-cpp). See the project README for first-time setup.
How the pieces fit
microphone → whisper-stream → voice-mode (gate) → /tmp/voice-mode.log
↓
Monitor: tail -F that log
↓
notifications to Claude
The daemon only writes a line when a complete utterance is detected (the
user paused after speaking). Annotations like [BLANK_AUDIO], [typing],
<cough> never reach the log. Rolling-window re-transcriptions collapse to
the final, fullest version.
Starting voice mode
When the user invokes /voice-mode, says "start voice mode", or asks to go
hands-free:
-
Start the daemon in the background, with the current shell's PID as the
owner so cleanup is automatic if the session ends:
voice-mode start --owner-pid $$ > /tmp/voice-mode.stderr 2>&1 &
--owner-pid $$ makes the daemon self-terminate if the Claude Code
session dies — no zombie daemons holding the mic.
- Defaults: log at
/tmp/voice-mode.log, PID lock at /tmp/voice-mode.pid,
whisper model at ~/.whisper-models/ggml-small.bin (override with
--model or $VOICE_MODE_WHISPER_MODEL).
-
Tell the user the daemon is starting and that the first model load takes
~10 seconds. Whisper.cpp loads the model and warms its GPU before the
first transcript appears. Don't claim "ready" too early.
-
Arm the Monitor tool to tail the log. This is the critical step —
Monitor turns each appended line into a chat notification. Use
persistent: true so it runs for the session and never times out:
Monitor:
command: tail -n 0 -F /tmp/voice-mode.log
description: voice-mode utterances
persistent: true
timeout_ms: 3600000 # ignored when persistent
-n 0 starts at end-of-file so you don't replay any old utterances
from a previous session.
-
Confirm voice mode is active (out loud / in chat), e.g. "Voice mode
is on — talk whenever you want."
Handling utterance notifications
When a Monitor notification arrives, it looks like:
2026-06-10T19:10:22Z Hello, I'm here. I believe you want me to say something?
The timestamp prefix is ISO 8601 UTC. Strip it for display/processing —
the actual user message is everything after the first space.
Mid-tool-loop interruption. Monitor notifications arrive even while
you're inside another tool call. When that happens:
- If the new utterance starts with interrupt-style words ("stop",
"wait", "cancel", "no", "actually", "hold on", "never mind", "different
question"), abandon the current task immediately and respond to the new
utterance. The user is course-correcting.
- Otherwise, finish the in-flight tool call cleanly and address the new
utterance next. Don't drop important work mid-flight unless interrupted.
Possibly-incomplete utterances. The daemon emits an utterance when
whisper's VAD detects silence. A brief mid-sentence breath could split one
thought into two. If an utterance looks mid-sentence (no terminal
punctuation, dangling conjunction "and"/"but"/"so", or feels syntactically
incomplete), do one short wait for a continuation before responding:
- Run
tail -n 0 -F /tmp/voice-mode.log via Bash with a short timeout
(e.g. timeout 8 ...). If a second utterance arrives within ~8s, treat
it as the continuation and concatenate before responding.
- If nothing arrives, the user really did stop — respond with what you
have. Don't wait indefinitely.
This is a judgment call, not a rule. Most utterances are complete; only
hedge when there's a clear cue.
Stopping voice mode
When the user says "stop voice mode", "exit voice mode", "I'm done
talking", or similar:
-
Stop the Monitor task (call TaskStop on the Monitor's task ID).
-
Stop the daemon:
voice-mode stop
This SIGTERMs the daemon, waits for graceful exit (3s), escalates to
SIGKILL if needed, and removes the PID lock.
-
Confirm voice mode is off.
If the Claude Code session ends without an explicit stop, the
--owner-pid watcher catches it within ~2 seconds and the daemon
self-terminates — but always prefer the explicit voice-mode stop when
possible. It's faster and tidier.
Status checks
voice-mode status
Useful when the user asks "is voice mode on?" or before trying to start
(check first to avoid ErrAlreadyRunning).
Troubleshooting
The Monitor fires but the text is [BLANK_AUDIO] or [typing].
That shouldn't happen — the gate suppresses these. If it does, the daemon
was bypassed (someone tailed whisper's raw -f file directly). Use
/tmp/voice-mode.log, not /tmp/voice-mode-raw.log.
No notifications even though the user is speaking.
- Check
voice-mode status — is the daemon running?
- Check
/tmp/voice-mode.stderr for backend errors (missing model,
whisper-stream not on PATH, etc.).
- Speak more clearly / closer to the mic. Whisper's VAD threshold is
permissive but background noise can starve it.
- For deeper debug, start with
--raw-log /tmp/voice-mode-raw.log and
inspect what whisper itself is producing.
"ErrAlreadyRunning" when starting.
Another daemon already holds the lock — likely from a previous session
that didn't clean up. Run voice-mode stop first.
Bluetooth headphones drop into low-quality mode.
Happens when the daemon grabs the BT mic for input. Fix: System Settings
→ Sound → Input → pick a non-Bluetooth mic before starting voice mode.
Keeping the skill up to date
To upgrade to the latest released version (binary + skill files):
"$(dirname SKILL.md)/update.sh"
"$(dirname SKILL.md)/update.sh" --yes
update.sh clones the latest tag into the system temp dir and reinstalls
the binary and skill to wherever this skill lives (user-global or project-
local). Needs git, curl, and the Go toolchain.
Reporting bugs
Open an issue at https://github.com/akostibas/voice-mode-skill/issues with:
- What you ran (command, environment, voice-mode version).
- What happened (gated log, raw log, daemon stderr).
- What you expected.
- A minimal repro.