WHENUSE: {UserAsksToReadAloud,ListenWhileWorking,AudioReviewOfPastLesson,VoiceMemo}. ESPECIALLY:{LongDocument,UserMultitasking}.
TTS Read-Aloud Delivery
Turn written material (lessons, guides, notes, past-session reviews) into spoken audio the user can listen to while working. The durable skill here is two-part: (1) a reliable local synthesis+playback pipeline, and (2) converting written text into a spoken script — markdown does not survive being read verbatim.
Choose the route
- Check what's configured:
hermes config get voice and hermes config get tts. The voice subsystem supports many providers (openai, edge, elevenlabs, gemini, piper, etc.).
- If the current session's toolset includes a text-to-speech tool, prefer it — it honours the configured provider.
- If not (e.g., a TUI session without the tts toolset loaded), use the local pipeline below. edge-tts is free, needs no API key, and has high-quality neural voices.
Setup (one-time)
pip3 install edge-tts --quiet --break-system-packages # macOS system Python: plain `pip` may not exist; --break-system-packages needed on PEP 668 systems
edge-tts --list-voices | grep en-US | head # pick a voice
Voices proven good for long-form narration:
| Voice |
Character |
| en-US-AriaNeural |
Female — positive, confident; news/novel tone (default pick) |
| en-US-GuyNeural |
Male — passionate, news/novel |
| en-US-JennyNeural |
Female — friendly, considerate, comfortable |
Procedure
- Gather the material — and check its freshness. For past-topic reviews:
session_search() (browse) to list sessions, let the user pick via clarify, then read the artifact (session transcript or saved guide file). If the artifact is a technical guide written a while ago, ask whether to refresh it against the current version BEFORE narrating — reading a stale guide aloud locks in outdated info. If refreshing: audit every falsifiable claim in the doc against the actual source at the current version (grep/ripgrep the checked-out install; record CONFIRMED/STALE/CHANGED per claim), update the file, then narrate from the updated version.
- Offer a short test first. Synthesize one sentence, play it, let the user confirm they can hear it before generating the full piece:
edge-tts --voice en-US-AriaNeural --text "Test line." --write-media /tmp/tts-test.mp3
afplay /tmp/tts-test.mp3 # macOS
- Convert to a spoken script (see rules below). Never feed raw markdown to the synthesizer.
- Generate and play in chunks using
scripts/tts_read.py (bundled with this skill): splits into ~3500-char paragraph chunks, synthesizes each to MP3, plays sequentially with progress lines. Run it in the background (terminal background=true) so the user isn't blocked; poll for progress if they ask where it is.
- Offer scope choice for long material — full vs. core sections vs. highlights — before generating. ~160 words/min is a good length estimate.
Spoken-script conversion rules
| Written form |
Spoken replacement |
| Markdown tables |
Prose: "There are three options: first..., second..., third..." |
| Code blocks / config YAML |
Describe intent ("you'd set the backend to docker in your config") or skip; never read syntax aloud |
| Headings with symbols (##, ✅, 🥇) |
Signposting phrases: "Section two, delegation. The key point is..." |
| URLs, file paths, flag soup |
Name them once in plain words or omit; listeners can read the written doc later |
| Commit hashes, version strings, hex IDs |
Replace with plain language ("at our current commit") or spell out letter-by-letter — never read raw hex aloud |
| Bullet lists |
Full sentences joined with connectives |
Good example: table {local: development | docker: security | ssh: sandboxing} → "There are several terminal backends. Local is the default for development. Docker gives you security and reproducibility. And SSH keeps the agent away from your own code."
Bad example: reading "pipe local, docker, ssh, modal, daytona" as a bare list with no context.
Pitfalls
- Don't promise audio before the test playback succeeds. Speakers, volume, and output device vary — the one-sentence test catches all of it.
- Don't narrate a stale document as-is. When asked to review an old guide, check whether the system it documents has moved on (versions, renamed flags, relocated paths). Refresh first, read second.
- Don't read markdown verbatim. Pipe characters, backticks, and emoji names are noise in audio.
- afplay is macOS-only. Linux:
mpv or aplay. Windows: start or PowerShell MediaElement. The chunk script's player command is the only OS-specific line.
- Long single synthesis calls can time out or get monotone. Chunking at ~3500 chars keeps each call bounded and lets playback start early.
- The voice subsystem's
use_gateway setting routes TTS through the gateway — in sessions without that path, the local pipeline is the dependable route.
Verification
- Test clip played and user confirmed audibility.
- Reader script prints
▶ part N/M playing lines as it progresses and DONE at the end.
- Ask the user at the end whether pacing/voice worked; adjust voice or speed (
edge-tts --rate=+10%) for next time.
Support files
scripts/tts_read.py — chunked narrator: paragraph-split → edge-tts per chunk → sequential afplay with progress. Usage: python3 scripts/tts_read.py /tmp/narration.txt [--voice en-US-AriaNeural]. Components (edge-tts synthesis, afplay playback) verified live; adjust CHUNK_SIZE/VOICE as needed.
1---2name: tts-read-aloud3description: Use when the user wants text read aloud via TTS.4license: MIT5---6
7WHENUSE: {UserAsksToReadAloud,ListenWhileWorking,AudioReviewOfPastLesson,VoiceMemo}. ESPECIALLY:{LongDocument,UserMultitasking}.
8
9# TTS Read-Aloud Delivery
10
11Turn written material (lessons, guides, notes, past-session reviews) into spoken audio the user can listen to while working. The durable skill here is two-part: (1) a reliable local synthesis+playback pipeline, and (2) converting written text into a *spoken* script — markdown does not survive being read verbatim.
12
13## Choose the route
14
151. Check what's configured: `hermes config get voice` and `hermes config get tts`. The voice subsystem supports many providers (openai, edge, elevenlabs, gemini, piper, etc.).
162. If the current session's toolset includes a text-to-speech tool, prefer it — it honours the configured provider.
173. If not (e.g., a TUI session without the tts toolset loaded), use the local pipeline below. edge-tts is free, needs no API key, and has high-quality neural voices.
18
19## Setup (one-time)
20
21```bash
22pip3 install edge-tts --quiet --break-system-packages # macOS system Python: plain `pip` may not exist; --break-system-packages needed on PEP 668 systems
23edge-tts --list-voices | grep en-US | head # pick a voice
24```
25
26Voices proven good for long-form narration:
27
28| Voice | Character |
29|-------|-----------|
30| en-US-AriaNeural | Female — positive, confident; news/novel tone (default pick) |
31| en-US-GuyNeural | Male — passionate, news/novel |
32| en-US-JennyNeural | Female — friendly, considerate, comfortable |
33
34## Procedure
35
361. **Gather the material — and check its freshness.** For past-topic reviews: `session_search()` (browse) to list sessions, let the user pick via `clarify`, then read the artifact (session transcript or saved guide file). If the artifact is a technical guide written a while ago, ask whether to refresh it against the current version BEFORE narrating — reading a stale guide aloud locks in outdated info. If refreshing: audit every falsifiable claim in the doc against the actual source at the current version (grep/ripgrep the checked-out install; record CONFIRMED/STALE/CHANGED per claim), update the file, then narrate from the updated version.
372. **Offer a short test first.** Synthesize one sentence, play it, let the user confirm they can hear it *before* generating the full piece:
38 ```bash
39 edge-tts --voice en-US-AriaNeural --text "Test line." --write-media /tmp/tts-test.mp3
40 afplay /tmp/tts-test.mp3 # macOS
41 ```
423. **Convert to a spoken script** (see rules below). Never feed raw markdown to the synthesizer.
434. **Generate and play in chunks** using `scripts/tts_read.py` (bundled with this skill): splits into ~3500-char paragraph chunks, synthesizes each to MP3, plays sequentially with progress lines. Run it in the background (`terminal background=true`) so the user isn't blocked; poll for progress if they ask where it is.
445. **Offer scope choice for long material** — full vs. core sections vs. highlights — before generating. ~160 words/min is a good length estimate.
45
46## Spoken-script conversion rules
47
48| Written form | Spoken replacement |
49|--------------|--------------------|
50| Markdown tables | Prose: "There are three options: first..., second..., third..." |
51| Code blocks / config YAML | Describe intent ("you'd set the backend to docker in your config") or skip; never read syntax aloud |
52| Headings with symbols (##, ✅, 🥇) | Signposting phrases: "Section two, delegation. The key point is..." |
53| URLs, file paths, flag soup | Name them once in plain words or omit; listeners can read the written doc later |
54| Commit hashes, version strings, hex IDs | Replace with plain language ("at our current commit") or spell out letter-by-letter — never read raw hex aloud |
55| Bullet lists | Full sentences joined with connectives |
56
57Good example: table `{local: development | docker: security | ssh: sandboxing}` → "There are several terminal backends. Local is the default for development. Docker gives you security and reproducibility. And SSH keeps the agent away from your own code."
58
59Bad example: reading "pipe local, docker, ssh, modal, daytona" as a bare list with no context.
60
61## Pitfalls
62
63- **Don't promise audio before the test playback succeeds.** Speakers, volume, and output device vary — the one-sentence test catches all of it.
64- **Don't narrate a stale document as-is.** When asked to review an old guide, check whether the system it documents has moved on (versions, renamed flags, relocated paths). Refresh first, read second.
65- **Don't read markdown verbatim.** Pipe characters, backticks, and emoji names are noise in audio.
66- **afplay is macOS-only.** Linux: `mpv` or `aplay`. Windows: `start` or PowerShell MediaElement. The chunk script's player command is the only OS-specific line.
67- **Long single synthesis calls can time out or get monotone.** Chunking at ~3500 chars keeps each call bounded and lets playback start early.
68- **The voice subsystem's `use_gateway` setting routes TTS through the gateway** — in sessions without that path, the local pipeline is the dependable route.
69
70## Verification
71
72- Test clip played and user confirmed audibility.
73- Reader script prints `▶ part N/M playing` lines as it progresses and `DONE` at the end.
74- Ask the user at the end whether pacing/voice worked; adjust voice or speed (`edge-tts --rate=+10%`) for next time.
75
76## Support files
77
78- `scripts/tts_read.py` — chunked narrator: paragraph-split → edge-tts per chunk → sequential afplay with progress. Usage: `python3 scripts/tts_read.py /tmp/narration.txt [--voice en-US-AriaNeural]`. Components (edge-tts synthesis, afplay playback) verified live; adjust CHUNK_SIZE/VOICE as needed.