Growing up watching Iron Man, I always wanted a Jarvis. An AI you could just talk to like a friend, and it would talk back. We’re not quite there yet, but with AI coding agents like Claude Code, we’re closer than ever.
I already speak to Claude Code. I built Whisp as a fun, free, open-source alternative to Wispr Flow and started loving the speech-to-text experience on Mac, especially for Claude Code. I hold a key, say what I want, and the prompt lands in the terminal. It’s faster than typing and surprisingly natural.
But the conversation was one-sided. I could talk to Claude Code, but it couldn’t talk back. I’d speak a prompt, then sit there staring at the terminal, watching text scroll by. Sometimes for minutes.
At some point I thought: why am I watching this? I don’t need to read every line in real time. I just need to know what it’s doing so I can glance over when it actually matters. The rest of the time, I’d rather be on my phone, checking Twitter, catching up on Reddit, or just doing literally anything other than watching code and commands scroll by.
So I built a plugin that makes Claude Code talk back.

What It Does
Narrator is a Claude Code plugin that speaks responses aloud using Kokoro, a local neural text-to-speech engine. No cloud APIs, no subscriptions, everything runs on your machine.
When Claude reads a file, you hear “Reading file settings dot json”. When it runs a command, you hear “Running git push”. When it finishes a response, the first chunk is spoken aloud.
It turns Claude Code into something you can listen to while you do something else. Review a PR in another tab, sip your coffee, doomscroll on your phone. You stay in the loop without being glued to the terminal.
It’s free and open-source: github.com/shreyas-s-rao/claude-code-narrator.
Why Local TTS?
Sure, your code already lives on Anthropic’s servers when you use Claude Code, so privacy isn’t the strongest argument here. But there are two very practical reasons to keep TTS local: latency and cost.
Latency
Cloud TTS APIs add a network round-trip to every utterance. For a tool that narrates each step of an ongoing coding session, that delay adds up fast. By the time the audio plays, Claude has already moved on to the next step, and the narration feels disconnected from what’s actually happening.
Kokoro is a small (82M parameter) neural TTS model that runs entirely on your machine. After a ~10 second cold start to load the model, each utterance synthesizes in under 50 milliseconds. The speech stays in sync with what Claude is doing.
Cost
Cloud TTS is priced per character, and a heavy Claude Code session generates a lot of text. Let’s do some rough math.
A typical Claude Code session might produce 50,000–100,000 characters of spoken text per day (tool descriptions, intermediate commentary, final responses). For a developer who uses Claude Code regularly, that’s easily 1.5–3 million characters per month.
Here’s what that would cost with cloud providers:
- Google Cloud TTS (WaveNet voices): $16 per 1M characters. That’s $24–48/month.
- Amazon Polly (neural voices): $16 per 1M characters. Same range, $24–48/month.
- Azure Speech (neural voices): $15 per 1M characters. About $22–45/month.
- ElevenLabs: $5/month gets you only 30K characters. You’d need the $22/month plan for 100K, and even that wouldn’t cover heavy usage.
That’s $20–50/month on top of what you’re already paying for Claude. For something that’s supposed to be a convenience feature, not a core service.
Kokoro runs locally and costs nothing. Zero API keys, zero billing dashboards, zero surprise invoices.
How It Works
The architecture is simple:
Hook fires → speak.sh → FIFO pipe → speak-daemon.py → audio
Claude Code has a plugin hook system that fires events when the assistant responds, uses a tool, or sends a notification. Narrator registers for these events and pipes the relevant text through a speech pipeline.
The key design decision was keeping a persistent daemon. Kokoro takes about 10 seconds to load its model into memory, which is too slow for per-utterance startup. So speak-daemon.py starts once, keeps the pipeline loaded, and reads from a named pipe (FIFO). Each message is a JSON line with the text, voice, and speed, so multiple Claude Code sessions can share a single daemon while each using different voices.
The text goes through a cleanup pipeline before reaching the TTS engine. settings.json becomes “settings dot json” (so Kokoro doesn’t treat the dot as a sentence boundary). README becomes “read me” (Kokoro mangles all-caps words). Arrows, operators, and markdown noise are all converted to natural speech. It’s a surprising amount of text processing for something that “just reads text aloud,” but the difference between raw and processed output is night and day.
The Details That Make It Feel Right
A few small things that took disproportionate effort but make the experience actually pleasant:
- Per-directory voices: If you’re running two Claude Code sessions, one on a frontend project, one on a backend API, you can give them different voices.
/narrator:cast am_adam --localin one directory,/narrator:cast af_bella --localin the other. Each session’s utterances carry their own voice and speed in the FIFO message, so they interleave correctly through the shared daemon. - Trailing periods on command descriptions: This was a fun debugging session. Kokoro clips the last syllable of short utterances that don’t end with a sentence boundary. “Running echo” came out as “Running ech”. Adding a period to every command description fixed it completely.
- Pronunciation fixes: Kokoro mispronounces many developer terms when they’re in ALL CAPS. README, JSON, YAML, API, CLI, SQL, all mangled. The fix is a sed pipeline that converts them to phonetic equivalents before they reach the TTS engine.
JSONbecomes “jason”,APIbecomes “A P I”,FIFObecomes “fye foe”. There are about 30 of these now, and I keep adding more as I hear new ones.
Install in 3 Commands
You need Python 3.9+, macOS or Linux, and Claude Code.
In Claude Code:
/plugin marketplace add shreyas-s-rao/claude-code-narrator
/plugin install narrator
/reload-plugins
Then /narrator:on or /narrator:on --local. Kokoro and all dependencies are auto-installed into a dedicated venv on first run. Takes a few minutes, then you’re set.
Pick a Voice
Narrator ships with 8 voices, 5 female and 3 male. Each has a distinct character:
- af_heart (default): warm, expressive
- af_bella:** **clear, professional
- af_sarah: bright, energetic
- am_adam: deep, authoritative
- am_michael: warm, friendly
- am_fenrir: bold, commanding
- And more…
Switch anytime with /narrator:cast am_adam or just /narrator:cast to hear the options. You can also adjust speed from 0.5x to 2.0x with /narrator:speed .
What Gets Spoken
- Tool use: “Reading file package dot json”, “Running git status”, “Searching codebase”
- Text between tool calls: the assistant’s intermediate commentary that would otherwise scroll past
- Final response: the first ~1000 characters, ending at a sentence boundary
- Notifications: title and message from Claude Code notifications
The Workflow Change
The real value isn’t the technology, it’s the workflow shift. Before Narrator, I was a passive observer of my own terminal, watching commands stream by. Now I can:
- Doomscroll guilt-free: Claude is refactoring a module? Cool. I’ll be on my phone. When I hear “Running tests,” I’ll glance over.
- Actually multitask: Code review in one tab while Claude works in another. I hear “Running tests” and look over when I hear “All tests passed.”
- Catch things I’d miss: When Claude reads a file or runs a command I didn’t expect, I hear it and can interrupt before it goes down the wrong path.
It’s a small thing, but it changes how you relate to the tool. Claude Code stops being something you watch and starts being something you work alongside.
Limitations
Narrator is a personal hobby project, built and tested on one machine. Some honest caveats:
- ~10 second cold start on first utterance while Kokoro loads. After that, it’s near-instant.
- Linux audio is untested: PortAudio/sounddevice should work, but I haven’t verified beyond install.
- Python 3.13 requires workarounds: Kokoro’s PyPI wheels don’t officially support it yet. The auto-installer handles this, but it’s fragile.
- One daemon for all sessions: Utterances from different sessions interleave sequentially. No parallel playback.
Get It
- GitHub: github.com/shreyas-s-rao/claude-code-narrator
- Install: 3 slash commands in Claude Code (see above)
If you try it, I’d love to hear how it works for you. Star the repo if you find it useful, it helps others find it. Bug reports and PRs are very welcome.
A message from our Founder
Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community. Did you know that our team run these publications as a volunteer effort to over 3.5m monthly readers? We don’t receive any funding, we do this to support the community.
If you want to show some love, please take a moment to follow me on LinkedIn, TikTok, Instagram. You can also subscribe to our weekly newsletter. And before you go, don’t forget to clap and follow the writer️!
Comments
Loading comments…