I gave Claude Code a voice, and why nothing else worked
Claude Code has /voice: you speak, it transcribes, Claude responds in text. But Claude never
talks back. I'd be staring at the terminal reading a three-paragraph explanation when I could be
hearing it while I kept working. The missing half was obvious. The fix wasn't.
Everything I tried first
I tried ElevenLabs first. $0.30 per million characters, API keys, a cloud round-trip, latency. OpenAI TTS was cheaper per character with the same fundamental problems. I tried the official VoiceMode MCP, which is a tool Claude has to choose to call, not something that fires automatically after every response. None of them did the simple thing I actually wanted: after every Claude response, just speak it aloud, locally, instantly, with no "would you like me to read this?" in the way.
A Stop hook is the whole trick
Claude Code has hooks. A Stop hook fires after every response. That's the entire mechanism. The hook grabs the response, strips markdown, code fences, and URLs, fixes the pronunciation of dev terms (CLI, API, JSON, nginx, kubectl all get mangled by naive TTS), generates audio with Kokoro, an 82M-parameter model that runs on CPU, and renders karaoke-style highlighting to the terminal while it plays. Current word lit up, a gradient around it, a progress bar. Press any key to stop.
Kokoro is the part that makes it work. It's small enough to run locally with no GPU, good enough to sound natural, and free. No API keys, no cloud, no audio leaving the machine. Twelve voices to pick from.
The "one file" constraint
The whole thing is 21KB of Python in a single file. It handles TTS generation, audio playback, terminal rendering, markdown stripping, pronunciation fixes, config, and the CLI. Is it a monolith? Yes. Would it be cleaner split into modules? Also yes. But "one file you drop in" is the feature. It's why people actually install it instead of bouncing off a setup guide. Sometimes the right architecture is the one that gets used.
Open source on github.