{"slug": "text-to-speech-for-claude-code-hear-what-the-agent-is-doing", "title": "Text-to-Speech for Claude Code — Hear What the Agent Is Doing", "summary": "A developer has added text-to-speech functionality to Claude Code, allowing the AI coding agent to read its responses aloud. The hack uses Claude Code's lifecycle hooks to pipe the agent's messages through the operating system's speech command, enabling users to hear status updates like \"done, tests pass\" or \"I need a decision here\" from another room. The developer also integrated the feature into their personal tooling project called teatree, which can play spoken responses through local speakers or attach audio files to Slack DMs.", "body_md": "Claude Code can already listen to you. Run `/voice`\n\nand you get push-to-talk dictation — you speak, it transcribes into the prompt ([docs](https://code.claude.com/docs/en/voice-dictation)). What it does not do is talk back. When I leave a long task running, I either babysit the terminal or miss the moment it finishes or asks a question.\n\nSo I added the other half: text-to-speech. A hook reads the agent's replies aloud. I can be in another room and still hear \"done, tests pass\" or \"I need a decision here\". This post has two parts — a small recipe anyone can paste into their config, and how I wired the same idea into my own tooling for the times I'm not at my desk.\n\nThis is a personal hack, not a Claude Code feature. It reads short text aloud after the agent stops. That's it. No wake words, no conversation, no reading code blocks (you don't want that).\n\nClaude Code [hooks](https://code.claude.com/docs/en/hooks) run a shell command on lifecycle events. The two that matter here:\n\n`message`\n\nfield.Notification is the simplest win, so start there. Every OS ships a speech command: `say`\n\non macOS, `spd-say`\n\nor `espeak-ng`\n\non Linux, and a one-line PowerShell call on Windows.\n\nHere is a Notification hook that speaks the message. Put it in `~/.claude/settings.json`\n\n:\n\n```\n{\n  \"hooks\": {\n    \"Notification\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"jq -r '.message // empty' | say\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n`jq`\n\nreads the `message`\n\nfield from the JSON on stdin, and `say`\n\n(macOS) reads piped text aloud. On Linux swap `say`\n\nfor `spd-say -e`\n\nor `espeak-ng`\n\n, both of which also read stdin. On Windows, point the command at PowerShell:\n\n```\n\"command\": \"jq -r '.message // empty' | powershell -Command \\\"Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak([Console]::In.ReadToEnd())\\\"\"\n```\n\nThat covers the \"needs your attention\" case. If you also want the agent to read its actual reply, add a Stop hook. The wrinkle: Stop gives you the transcript path, not the text. The transcript is JSONL (one JSON object per line), so you pull the last assistant text block out of it:\n\n```\n{\n  \"hooks\": {\n    \"Stop\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"jq -rs 'map(select(.type==\\\"assistant\\\")) | last | .message.content[]? | select(.type==\\\"text\\\") | .text' \\\"$(jq -r .transcript_path)\\\" 2>/dev/null | head -c 600 | say\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nA few honest caveats, because this is where it gets rough:\n\n`head -c 600`\n\nstops `say`\n\ndroning through a 4 KB status report. Pick your own limit.`jq`\n\nfilter above matches the current JSONL layout. If Claude Code changes it, the filter breaks. Treat it as a hack, not an API.For most people the Notification hook alone is enough, and it's the part least likely to break.\n\nI keep my Claude Code automation in a project called [teatree](https://github.com/souliane/teatree). It has a `t3 speak`\n\ncommand driven by one `[teatree.speak]`\n\ntable:\n\n```\n[teatree.speak]\nlocal = \"dm\"   # what plays on this machine's speakers: \"dm\" | \"all\" | \"off\"\nslack = true   # attach a spoken audio file to each bot→user Slack DM\n```\n\n`local`\n\ncontrols the speakers in front of you: `dm`\n\nreads only the bot's DMs to you, `all`\n\nalso reads every agent turn aloud, `off`\n\nis silent. `slack`\n\nattaches a spoken audio file to each bot→user DM. The two are independent, and both default off, so it does nothing until you configure it.\n\nTwo destinations because there are two places I am. At the desk, `local`\n\nplays through the speakers the moment a DM lands — no clicking. Away from it, `slack`\n\nis what I reach for: the spoken text arrives as an audio file attached to the DM, and on the phone I press play. Not hands-free, but I can listen while moving instead of stopping to read.\n\nTwo operational notes. The voice comes from macOS `say`\n\n. And `slack`\n\nneeds the bot's file-upload permission, so an existing bot has to be reinstalled once to grant it.\n\nThe hook recipe is the part I'd actually recommend trying — it's a few lines and it degrades gracefully. The teatree side is tied to my own setup, so take it as one way to structure the same idea rather than something to copy verbatim.\n\nI'm still figuring out how much to read aloud. `local = \"all\"`\n\ngets chatty fast. `dm`\n\nis calmer but misses things. If you try this, I'd be curious what threshold works for you.", "url": "https://wpnews.pro/news/text-to-speech-for-claude-code-hear-what-the-agent-is-doing", "canonical_source": "https://dev.to/souliane/text-to-speech-for-claude-code-hear-what-the-agent-is-doing-3mom", "published_at": "2026-06-06 20:35:46+00:00", "updated_at": "2026-06-06 20:41:18.335826+00:00", "lang": "en", "topics": ["ai-tools", "ai-products", "ai-agents"], "entities": ["Claude Code", "Claude"], "alternates": {"html": "https://wpnews.pro/news/text-to-speech-for-claude-code-hear-what-the-agent-is-doing", "markdown": "https://wpnews.pro/news/text-to-speech-for-claude-code-hear-what-the-agent-is-doing.md", "text": "https://wpnews.pro/news/text-to-speech-for-claude-code-hear-what-the-agent-is-doing.txt", "jsonld": "https://wpnews.pro/news/text-to-speech-for-claude-code-hear-what-the-agent-is-doing.jsonld"}}