Create a two-host podcast script and MP3 episode from source text with resumable script/audio generation, quality checks, and short/standard/long profiles.
Use this skill when the user wants to turn source text into a two-host podcast script JSON and MP3 episode, especially when they need resumable generation, a script-plus-audio pipeline, or script-quality-gated TTS.
Run commands from the skill root (.../podcast-maker).
3.10+OPENAI_API_KEY set directly or available via ~/.codex/auth.jsonffmpeg is optional for generation but required for full concat/loudnorm/EQ post-processingFor normal end-to-end runs, use the orchestrator so script and audio stages share the same run identity.
python3 ./scripts/run_podcast.py --profile standard /path/to/source.txt /output/dir episode_name
Expected outputs:
/output/dir/episode_name_norm_eq.mp3/output/dir/episode_name_raw_only.mp3 when ffmpeg is unavailable and --allow-raw-only or ALLOW_RAW_ONLY=1 is set./.script_checkpoints and outdir/.audio_checkpointsUse split commands when you need the script JSON first or want to regenerate audio from an existing script.
./scripts/make_script.py --profile standard /path/to/source.txt /path/to/script.json
./scripts/make_podcast.py --profile standard /path/to/script.json /output/dir episode_name
For shell portability, the wrapper also works:
./scripts/make_podcast.sh /path/to/script.json /output/dir episode_name --profile standard --resume
episode_name, basename, and explicit --episode-id values must be plain file-name tokens only.
episode_001foo/bar, ../episode, /tmp/nameIf you split script and audio generation across separate commands, pass the same explicit --episode-id to both stages so checkpoints, manifests, and reports stay grouped.
| Need | Command |
|---|---|
| Normal end-to-end generation with shared run identity | python3 ./scripts/run_podcast.py |
| Generate only the script JSON | ./scripts/make_script.py |
| Regenerate audio from an existing script JSON | ./scripts/make_podcast.py |
Use only flags documented in each script's --help.
short (~5 min), standard (~15 min, default), long (~30 min)short: prefer at least max(120, target_words * 0.35) wordsstandard: prefer at least max(120, target_words * 0.50) wordslong: prefer at least max(120, target_words * 0.60) wordsgpt-5.4 and still honors SCRIPT_MODEL / MODEL overridesmake_script.py is expected to persist quality_report.json; if that artifact is missing, the script run fails instead of triggering a hidden fallback repair/eval pathoff, warn, or enforce modeWhen generating or reviewing scripts, keep these constraints in force:
Host1 and Host2Bloque 1, Section 2, or Part 3Host2 genuinely interactive: ask for clarification, push on tradeoffs, or challenge vague claims instead of only agreeingExpected JSON shape:
{
"lines": [
{
"speaker": "Carlos",
"role": "Host1",
"instructions": "Speak in a warm, confident, conversational tone. Keep pacing measured and clear with brief pauses.",
"pace_hint": "steady",
"text": "Hola y bienvenidos..."
}
]
}
Resume a stopped run:
./scripts/make_script.py --resume input.txt script.json
./scripts/make_podcast.py --resume script.json outdir episode_name
Force resume when inputs changed intentionally:
./scripts/make_script.py --resume --resume-force input.txt script.json
Override duration directly:
TARGET_MINUTES=15 WORDS_PER_MIN=130 ./scripts/make_script.py input.txt script.json
references/env.md for canonical environment variables, defaults, and artifact pathsreferences/operations.md for incident handling, retention, SLOs, and rollout guidancereferences/quality-and-golden-tests.md for quality gate behavior, quality-loop comparisons, and golden regression commandsmake_podcast.py defaults the basename to episode if omittedCHECKPOINT_VERSION=3 is the current checkpoint schema majorutf-8, utf-8-sig, cp1252, and latin-1stderr and prints the final output path to stdout