agentleFS
eins78eins78/agent-skills/skills/text-to-speech/SKILL.md

text-to-speech

Skill2 starsChanged 14 days agoMITView on GitHub

Use when you need to convert a text document to an audio file via a local TTS pipeline. Outputs MP3. Handles narrative rewrite, text normalization, prosody prep, and audio render. Backend is configurable. Triggers: text to speech, narrate document, make audio from text, synthesize speech, TTS, MP3 from document, convert to podcast, audio version of document.

  • Installs packages

21 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use voice-changer, speech-engine and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • wlzhSkill

    voice-changer

    音频变声处理工具 - 使用 RVC AI 模型进行真实的声音转换,支持视频直接输入

    Also in 4 projects that use this

  • RobStrayerSkill

    speech-engine

    Add real-time voice conversations to a custom agent runtime with ElevenLabs Speech Engine. Use when building Speech Engine servers, WebSocket handlers, WebRTC browser clients, conversation token endpoints, interruption-aware streaming responses, or voice-enabled chat agents that connect developer-owned server logic to ElevenLabs speech-to-text and text-to-speech.

    Also in 3 projects that use this

  • RobStrayerSkill

    voice-isolator

    Remove background noise and isolate vocals/speech from audio using ElevenLabs Voice Isolator (audio isolation) API. Use when cleaning up noisy recordings, removing music or background ambience from dialogue, isolating speech from field recordings, preparing audio for transcription, extracting vocals, or any "denoise / clean up / isolate voice" task.

    Also in 3 projects that use this

  • perso-aiSkill

    dubbing

    Auto-dub (voice-translate) videos into other languages, with lip-sync (Perso AI Dubbing).

    Also in 4 projects that use this

  • LinHao-citySkill

    setup-api-key

    Guides users through setting up an ElevenLabs API key for ElevenLabs MCP tools. Use when the user needs to configure an ElevenLabs API key, when ElevenLabs tools fail due to missing API key, or when the user mentions needing access to ElevenLabs. First checks whether ELEVENLABS_API_KEY is already configured and valid, and only runs full setup when needed.

    Also in 5 projects that use this

  • LinHao-citySkill

    bfl-api

    BFL FLUX API integration guide covering endpoints, async polling patterns, rate limiting, error handling, webhooks, and regional endpoints with Python and TypeScript code examples.

    Also in 3 projects that use this

  • +5 more from LinHao-city

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 1 is distinctive, and 6 are very specific to this project.

  • 0

    Common

    Most of the 18 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Place synth-backend.yaml in your project root to override CLI defaults:

    line 52
  2. Very specific:

    When --backend kokoro (default), the pipeline runs four layers:

    line 68
  3. Very specific:

    Do NOT let synth-audio.sh/pipeline.py shell out to claude --print for you — a nested claude --print launched from inside your own session …

    line 74
  4. Distinctive:

    Read the input document.

    line 86
  5. Very specific:

    Place phoneme-dict.yaml in your project root for project-specific proper nouns:

    line 124
  6. Very specific:

    Place stress.yaml in your project root:

    line 141
  7. Very specific:

    After render, transcribes the MP3 with Whisper and reports IPA regressions, missing ordinal patterns, and unexpected artefacts.

    line 175

“Common” is measured: kept by at least 6 in 10 of the 18 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

text-to-speech

Converts a text document to an MP3 audio file via a local TTS pipeline. The skill ships a wrapper script (synth-audio.sh) with a clean text → audio-file interface. The current backend is Kokoro-82M; swapping backends is a config change.

Does NOT install any TTS backend. See Backend Dependencies.

v2.0.0 breaking change: the narrative rewrite (L1) no longer runs automatically inside synth-audio.sh. If you're a driving Claude Code agent, dispatch a rewrite subagent first — see L1 Narrative Rewrite below — this is the normal way to use the skill now, not an edge case. A bare synth-audio.sh input.md output.mp3 with no existing narrative.txt now fails loudly instead of silently shelling out to claude --print (that nested call could inherit your session's output style/CLAUDE.md and leak meta-commentary into the audio — see L1 Narrative Rewrite for why). For headless/standalone use, pass --allow-inline-llm-rewrite.

Quick Start

${CLAUDE_SKILL_DIR}/scripts/synth-audio.sh input.md output.mp3 --skip-layer 1
# ^ requires <output.mp3>.workdir/narrative.txt to already exist — see
#   "L1 Narrative Rewrite" below for how to produce it (subagent dispatch)

Copy and configure backend settings (optional):

cp ${CLAUDE_SKILL_DIR}/templates/synth-backend.yaml.example ./synth-backend.yaml
# Edit synth-backend.yaml to match your setup

Backend Config (synth-backend.yaml)

Place synth-backend.yaml in your project root to override CLI defaults:

backend: kokoro        # current: kokoro | future: orpheus | ...

kokoro:
  voice: am_puck       # validated voice (R5, 5-round iteration)
  speed: 0.92          # validated speed — see Kokoro backend section
  phoneme_dict: ./phoneme-dict.yaml   # optional IPA overrides
  stress_hints: ./stress.yaml         # optional emphasis overrides

See ${CLAUDE_SKILL_DIR}/templates/synth-backend.yaml.example for annotated defaults.

Kokoro Backend

When --backend kokoro (default), the pipeline runs four layers: L1 narrative rewrite (LLM) → L2 normalization → L3 prosody prep → render

L1 Narrative Rewrite — dispatch a subagent (do this first)

If you are the driving Claude Code agent, do this before calling synth-audio.sh. Do NOT let synth-audio.sh/pipeline.py shell out to claude --print for you — a nested claude --print launched from inside your own session inherits your active output style, project CLAUDE.md, and any other session framing, and can return meta-commentary instead of a rewrite (observed failure: a literal ★ Insight block rendered into the audio). Dispatching a subagent via the Agent/Task tool gives a genuinely isolated context instead.

  1. Determine <workdir> = <output.mp3 path with .mp3 stripped>.workdir and mkdir -p it (this matches the directory the backend itself creates).
  2. Dispatch one subagent (general-purpose) with a self-contained prompt:
    • Read ${CLAUDE_SKILL_DIR}/scripts/backends/prompts/narrative-chapter-focused.md and follow it exactly as the rewrite rules.
    • Read the input document.
    • Output ONLY the rewritten prose with [[CHAPTER: ...]] markers — no preamble, no explanation, no markdown fences, no commentary about the task itself.
    • Instruct it to write the result directly to <workdir>/narrative.txt (via Write) and return only a short status line — don't have it return multi-thousand-word prose through the tool result.
    • For documents >5000 words, either let the subagent chunk internally by H2, or dispatch one subagent per H2 section in parallel and concatenate — this replaces chunk_and_rewrite.py's own claude --print calls when you're running inside a session.
  3. Run:
    ${CLAUDE_SKILL_DIR}/scripts/synth-audio.sh input.md output.mp3 --skip-layer 1 [other flags]
    pipeline.py validates narrative.txt (chapter markers present, word count plausible vs. the source, no known contamination patterns) before continuing to L2/L3/render — if validation fails it exits loudly rather than rendering audio from a bad narrative. Re-dispatch the subagent and retry.

Standalone / headless (no driving agent present): pass --allow-inline-llm-rewrite to synth-audio.sh. This falls back to an isolated inline claude --print --safe-mode call inside the pipeline (--safe-mode disables CLAUDE.md auto-discovery, output styles, hooks, plugins, and custom agents/commands). It's a weaker guarantee than subagent dispatch — there's no independent process boundary confirming isolation beyond the flag itself — so validate_narrative() still runs as the backstop either way. Prefer subagent dispatch whenever a driving agent is available.

Voice and Speed

  • Voice: am_puck (validated across 5 rounds of iteration)
  • Speed: 0.92× — empirical: at 0.95+ the /s/→/k/ transition in compound nouns like "Six key concepts" slurs to "Zik's"; 0.92 is the last clean value

Phoneme Dictionary (L3a)

Place phoneme-dict.yaml in your project root for project-specific proper nouns:

terms:
  MyProduct:
    ipa: "mˈaɪ pɹˈɒdʌkt"
    notes: "Default G2P stresses wrong syllable"

MUST use [word](/IPA/) Markdown-link form. Bare /IPA/ is not reliably parsed — in Round 4 misaki voiced IPA characters as literal names ("slash D stress I slash"). The backend applies the link form automatically from your dict entries.

⚠️ Do NOT add entries where default G2P is already correct. misaki will voice the word twice ("Letta Letta"). Test with --verify before committing new entries.

See ${CLAUDE_SKILL_DIR}/templates/phoneme-dict.yaml.example for format and warnings.

Stress Hints (L3b)

Place stress.yaml in your project root:

emphasize:
  - not
  - only
  - critical

deemphasize: []

⚠️ deemphasize MUST stay empty. Round 4 regression: ~650 (-1) wraps on articles, pronouns, and linking verbs produced a "timid, reserved" cadence that listeners flagged in review. Known-unsafe: articles (the, a, an), pronouns (I, you, it, they, we), be-forms (is, are, was, were), filler adverbs (just, really, very, quite). Do NOT re-add.

See ${CLAUDE_SKILL_DIR}/templates/stress.yaml.example for safe examples with commentary.

Em-Dash Chunking (L3c)

Kokoro only creates chunk boundaries at ., !, ?. An em-dash does not force a breath pause. The pipeline converts X — Y to X. — Y — adding a pause while preserving the em-dash's intonation curve (removing the dash entirely produced flat, mechanical prosody).

List Prosody (L1 prompt rules)

The narrative rewrite enforces a spoken-list structure:

  • Announce list length up front ("Here are six requirements.")
  • Period-terminate every item
  • Ordinal words (First, Second… Tenth) — not numerals
  • Sub-opener topic sentence for items >40 words
  • Anchor + capstone for nested sub-lists ("So that is the first tier. Next, the second tier…")

Whisper Self-Check (--verify)

${CLAUDE_SKILL_DIR}/scripts/synth-audio.sh input.md output.mp3 --verify

After render, transcribes the MP3 with Whisper and reports IPA regressions, missing ordinal patterns, and unexpected artefacts. Requires mlx-whisper (Apple Silicon; uv pip install mlx-whisper).

ID3 Lyrics (USLT) — narrative debug artefact

The backend embeds the final narrative.txt (chapter markers stripped to plain title lines) into the rendered MP3's ID3 USLT (lyrics) frame by default — the spoken text travels inside the file, so you can compare it against the source without a separate artefact. Pass --no-lyrics to synth-audio.sh to skip it. Read it back with:

uv run --with mutagen --no-project python -c "
from mutagen.id3 import ID3
id3 = ID3('output.mp3')
for k, f in id3.items():
    if k.startswith('USLT'):
        print(str(f.text))
"

Backend Dependencies

The skill does NOT install or configure backend software. Caller must provide:

  • Kokoro-82M: uv pip install kokoro (hexgrad/kokoro)
  • Python 3.11+ with uv
  • ffmpeg: brew install ffmpeg
  • espeak-ng: conditional dependency — brew install espeak-ng as a fallback. Kokoro's misaki G2P depends on espeakng_loader, whose bundled libespeak-ng.dylib data-path resolution is not reliably correct on every install (observed: byte-identical dylib+data works fine from a normally-located venv, hard-aborts before Python can flush stdout from a venv nested under a long path — it's install-dependent, not universal). kokoro.sh runs a probe-first preflight (macOS): it actually exercises misaki's G2P once, and only if that fails does it symlink the loader's dylibs to a Homebrew espeak-ng build — silent and a no-op when the bundled path already works. If TTS aborts with an espeak-ng-data path error and you don't have espeak-ng installed via Homebrew, that's the fallback you need.
  • VIRTUAL_ENV must be set in the calling environment. misaki auto-installs the en-core-web-sm spaCy model via uv pip install on first use; under uv run --no-project with no active VIRTUAL_ENV this fails with an unhelpful "No virtual environment found" (exit 2, no traceback). kokoro.sh checks this upfront and fails loudly with the fix (export VIRTUAL_ENV=/path/to/your/venv) rather than letting the render fail deep inside misaki.
  • mutagen: uv pip install mutagen (for ID3 chapter + lyrics injection)
  • mlx-whisper (optional, for --verify): uv pip install mlx-whisper

Known Kokoro Limitations

  • Phoneme doubling: Adding a phoneme-dict entry where G2P is already correct renders the word twice. Drop the entry; test with --verify.
  • Whisper vocabulary gaps: Novel compounds (atproto → "AppProto"). Gloss in prose on first mention.
  • Chunker edge cases: etc., e.g. may survive L2 normalization. Spot-check the Kokoro text output.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.