mcpbeat

Generating Podcast Script

microsoft/generating-podcast-script

Use this skill whenever the user asks to write, generate, or create a podcast script or podcast episode — from a topic, or from source material such as a news digest, newsletter, email review, or set of articles — and optionally convert it to audio with Azure Text-to-Speech. Handles the initial request and every follow-up refinement (source, topic, length, cast, narration) in the same task.

4k tokens
context cost
the whole folder, loaded on every use
3
files
instructions only
0
copies elsewhere
how many repositories repackaged it
5 d ago
last touched
this folder, not the whole repository

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/cat-agent-skills --skill generating-podcast-script

What comes with it

4 356 bytes besides the instruction
README.md
metadata.json

The instruction itself

13 sections, as written by the author

Podcast Script Generation

Produces a two-host, NotebookLM-style conversational episode: a readable script

plus a multi-voice SSML document ready for Azure Text-to-Speech.

Step 1 — Gather inputs

Ask only for what is missing. Do not ask for optional fields that have safe

defaults.

| Input | Required | Default |

|---|---|---|

| source or topic | Yes | — (source material such as a digest/newsletter/articles, or a plain topic) |

| duration | No | mediumshort ≈ 3 min / ~450 words, medium ≈ 6 min / ~900 words, long ≈ 12 min / ~1,800 words |

| language | No | English |

| cast | No | Two hosts, NOVA and MILES (see Step 4) |

| generate_audio | No | Ask after the script is ready |

All word targets assume ~150 spoken words per minute. Stay within 10 percent of

target.

Derive a lowercase-hyphenated <slug> from the source or topic (max 6 words,

ASCII only).

Step 2 — Parse the source material

Skip this step when the user gave a bare topic with no source material.

Extract every distinct article or item. For each, capture:

  • headline
  • publication / source
  • date, if present
  • the core factual claim
  • any figures or quotes
  • the "so what"

Merge duplicates covering the same event. Discard boilerplate, footers,

disclaimers, legal notices, unsubscribe text, and image captions.

Step 3 — Editorial selection

Rank items by newsworthiness and reader impact. Keep the top 4 to 6 for full

treatment (fewer for short, more for long). Group the remainder into one

fast rapid fire segment. If the material has a dominant theme, lead with it

and thread it through the episode.

Step 4 — Cast

Two hosts, always the same personalities, always distinct voices:

  • NOVA — voice en-US-AvaMultilingualNeural. Lead host. Warm, curious,

quick. Drives the agenda, asks the question the listener is thinking, reacts

out loud, reframes jargon into plain language. Slightly faster cadence.

  • MILES — voice en-US-AndrewMultilingualNeural. Analyst. Calm, dry,

precise. Supplies context, numbers, caveats, second-order implications.

Slightly slower, lower pitch. Occasionally pushes back on Nova.

Neither host is a narrator. They talk to each other, not to the microphone.

Step 5 — Episode structure

  • Cold open (15–20s) — Nova opens on the single most striking fact or

tension. No "welcome to the podcast", no channel branding, no music cues.

  • Agenda tease (10s) — Miles lays out what they'll cover, casually.
  • Story segments (60–90s each) — one item per segment. Pattern:

hook → the facts → why it matters → a short exchange of interpretation →

handoff line into the next story. Vary who leads each segment.

  • Rapid fire (45s) — alternating one-liners on the leftover items, quick

tempo.

  • Close (20–30s) — three concrete takeaways split between the two hosts,

then a short human sign-off. Alternate whether Nova or Miles ends.

Step 6 — Dialogue style

This is what makes it sound conversational rather than read-aloud.

  • Write spoken English, not written English. Contractions everywhere.
  • Keep most lines under 30 words. Break long explanations across two or three

turns with the other host interjecting.

  • Use real conversational connective tissue — "okay so", "right", "wait, back

up", "here's the part I didn't expect", "yeah, and that's the thing", "hmm".

Roughly one marker every 4 to 5 turns. Never let it become a tic.

  • One host regularly asks the naive clarifying question so the other can

explain.

  • Use one concrete analogy or comparison per complex item.
  • Genuine reactions are allowed ("that number is wild"). Invented opinions on

people, companies, or politics are not.

  • Never read a headline verbatim. Paraphrase it into speech.
  • Attribute clearly: "according to the Financial Times", "Reuters is

reporting".

  • If the source is ambiguous or a claim is unconfirmed, say so on air: "the

report is careful to call that unconfirmed".

  • No stage directions, no "[laughs]", no speaker labels, no markdown, no

emojis, no bullet points, and no URLs in the spoken text.

Step 7 — TTS hygiene

Applies to every word that will be spoken.

  • Spell out anything a synthesizer would mangle: "twenty twenty-six" not

2026, "three point two billion dollars" not $3.2B, "about fifteen

percent" not ~15%.

  • First mention of an acronym: expand it, then use the short form.
  • Letter-by-letter acronyms: <say-as interpret-as="characters">API</say-as>.
  • Odd proper nouns: <sub alias="phonetic spelling">Name</sub>.
  • A non-English name or phrase inside an English line:

<lang xml:lang="fr-FR">...</lang>.

  • Escape XML entities in all spoken text: &&amp;, <&lt;,

>&gt;.

  • Never emit smart quotes, em dashes, asterisks, or underscores.

Step 8 — Write the readable script

Write the human-readable transcript to:

/app/created/<slug>_Podcast_Script.txt

This file — and only this file — may carry NOVA: / MILES: speaker labels so

a person can follow along. It contains no stage directions and no markdown. The

spoken text itself must already satisfy Steps 6 and 7 so it can be lifted into

SSML unchanged.

Step 9 — SSML output contract

Produce the SSML document and nothing else — no preamble, no explanation, no

code fences, no trailing notes inside the artifact. Write it verbatim to:

/app/created/<slug>_Podcast.ssml

Rules:

  • Exactly one root <speak> element with version="1.0",

xmlns="http://www.w3.org/2001/10/synthesis",

xmlns:mstts="http://www.w3.org/2001/mstts", xml:lang="en-US".

  • One <voice> element per conversational turn. Alternate speakers. Never put

both hosts inside one <voice> element.

  • Vary delivery with <prosody> so it never sounds flat. Baselines: Nova

rate="+6%" pitch="+2%", Miles rate="-2%" pitch="-4%". Nudge per line to

match the emotion of the sentence.

  • Use <mstts:express-as style="..."> where the voice supports it. Preferred

styles: chat for banter, friendly for explanation,

narration-professional for the factual core of a story, excited sparingly

for the cold open. An unsupported style is ignored by the service, so keep

styles optional — never structural.

  • Pauses: <break time="250ms"/> between turns within a segment,

<break time="700ms"/> between segments, <break time="400ms"/> before a

punchline or a pivot. Never exceed 900ms.

  • Every <break> must sit inside a <voice> element. A <break> placed

between <voice> elements — as a direct child of <speak> — is invalid in a

multi-voice document and will fail synthesis. Two <voice> elements may sit

directly next to each other with nothing between them. To pause *between*

turns, put the break at the end of the preceding turn's text, inside that

turn's <prosody>.

  • <emphasis level="moderate"> on at most one or two key terms per segment.
  • Keep the total document under 40,000 characters.

Shape

<speak version="1.0"
       xmlns="http://www.w3.org/2001/10/synthesis"
       xmlns:mstts="http://www.w3.org/2001/mstts"
       xml:lang="en-US">
  <voice name="en-US-AvaMultilingualNeural">
    <mstts:express-as style="excited">
      <prosody rate="+8%" pitch="+3%">Okay, so the number that stopped me cold
      this morning was forty percent. <break time="300ms"/> Forty percent, in one
      quarter. <break time="250ms"/></prosody>
    </mstts:express-as>
  </voice>
  <voice name="en-US-AndrewMultilingualNeural">
    <mstts:express-as style="chat">
      <prosody rate="-2%" pitch="-4%">Right, and the part everyone's skipping is
      that it's off a very small base. <break time="250ms"/> Context matters
      here. <break time="700ms"/></prosody>
    </mstts:express-as>
  </voice>
</speak>

Note the trailing <break> closing each turn: the 250ms is the gap before the

next turn, the 700ms is the longer gap before the next segment. Nothing sits

between the two <voice> elements.

Step 10 — Review, then generate audio

Show the user a table summarising each segment (title, one-line description,

approximate spoken duration), print both file paths, and ask:

> Would you like me to convert this to an audio file?

Only if they say yes:

  • Confirm the ConverttexttospeechwithSSML tool is available on the agent. If

it is not, tell the user how to add it and stop.

  • Call ConverttexttospeechwithSSML with the SSML document from Step 9 and

outputFormat: riff-24khz-16bit-mono-pcm.

  • Decode the base64 response and save to /app/created/<slug>_Podcast.wav.

If the document is too large for a single call, split it at a segment boundary and synthesize each part separately.

When stitching, do NOT concatenate decoded RIFF/WAV bytes; instead, append the audio at the PCM-frame level (e.g., via Python’s wave module) and write a single valid /app/created/<slug>_Podcast.wav with one header.

import base64

with open('<tool_output_file>', 'r') as f:
    content = f.read().strip()

audio_bytes = base64.b64decode(content)

with open('/app/created/<slug>_Podcast.wav', 'wb') as f:
    f.write(audio_bytes)

Step 11 — Final report

Always end with:

| Item | Details |

|---|---|

| Script file | /app/created/<slug>_Podcast_Script.txt |

| SSML file | /app/created/<slug>_Podcast.ssml |

| Word count / estimated duration | actual vs. target at ~150 wpm |

| Items covered | full segments + rapid-fire count |

| Voices | en-US-AvaMultilingualNeural (Nova), en-US-AndrewMultilingualNeural (Miles) |

| Audio file | /app/created/<slug>_Podcast.wav *(only if audio generated)* |

How to use it

Copy the folder

Take microsoft/generating-podcast-script from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.