Engineering

I gave Claude Code a voice, and why nothing else worked


The tool is claude-voice, the most-starred thing I've shipped. This is why it exists and why it's one file.

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.

The pattern I keep coming back to: take a tool I already use every day, find the half that's missing, and build exactly that. Nothing more. claude-voice is the cleanest example of it.

Open source on github.