Metadata-Version: 2.5
Name: miragea-podcast
Version: 0.1.0
Summary: Open-source AI podcast generator: turn any URL, PDF, text or topic into a two-host (or panel) podcast with distinct voices, chapters, SRT/VTT transcript and RSS. CLI + MCP server + Agent Skill, voiced by Miragea.
Project-URL: Homepage, https://codeberg.org/miragea-voice/miragea-podcast
Project-URL: Documentation, https://codeberg.org/miragea-voice/miragea-podcast#readme
Project-URL: Issues, https://codeberg.org/miragea-voice/miragea-podcast/issues
Project-URL: Changelog, https://codeberg.org/miragea-voice/miragea-podcast/src/branch/main/CHANGELOG.md
Project-URL: Miragea API, https://miragea.ai
Author: miragea-podcast contributors
License-Expression: MIT
License-File: LICENSE
Keywords: agent-skill,ai-podcast,audio-overview,claude,cursor,mcp,mcp-server,miragea,multi-speaker,notebooklm,notebooklm-alternative,pdf-to-podcast,podcast,podcast-generator,rss,text-to-podcast,text-to-speech,transcript,tts,voice-cloning
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio :: Mixers
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: anyio>=4
Requires-Dist: httpx>=0.27
Requires-Dist: mcp>=1.9
Requires-Dist: mutagen>=1.47
Requires-Dist: pydantic>=2
Requires-Dist: pypdf>=4
Requires-Dist: tomli>=2; python_version < '3.11'
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# miragea-podcast: open-source AI podcast generator (NotebookLM-style two-host audio from any URL, PDF or topic)

![miragea-podcast banner: two AI hosts, Alex and Sam, with waveforms, and the files the tool writes: MP3 with chapters, SRT/VTT transcript, chapters JSON, show notes and a Podcasting 2.0 RSS feed](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/docs/images/cover.png)

**miragea-podcast** is an open-source (MIT) AI podcast generator that turns a web page, PDF, text file or plain topic into a finished two-host (or up to six-voice panel) podcast episode. Your AI agent or any LLM writes a natural conversation script, and miragea-podcast voices each host with a distinct cloned or saved voice through the [Miragea](https://miragea.ai) voice API. It then mixes real turn-taking (interruptions, overlaps, laughs, pauses) and writes an MP3 with ID3 chapters, SRT/VTT/JSON transcripts, show notes and a Podcasting 2.0 RSS feed. It ships as a **CLI**, an **MCP server** (Claude Desktop, Claude Code, Cursor, VS Code, Windsurf) and an **Agent Skill**. It needs no GPU, no local TTS model and no second LLM key when an agent writes the script.

[Listen to the demo episode (MP3, 85 s)](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/examples/output/why-songs-get-stuck-in-your-head.mp3) · [Watch it with captions (MP4)](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/examples/demo.mp4) · [Read the script](https://codeberg.org/miragea-voice/miragea-podcast/src/branch/main/examples/earworms.md) · [PyPI](https://pypi.org/project/miragea-podcast/)

![Animated preview of the demo episode: a waveform moves while burned-in captions show Alex and Sam talking about earworms](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/docs/images/demo.gif)

## Contents

- [Quick start](#quick-start)
- [How it works](#how-it-works)
- [Real demo output](#real-demo-output)
- [Use it from Claude, Cursor or any MCP client](#use-it-from-claude-cursor-or-any-mcp-client)
- [Use it as an Agent Skill](#use-it-as-an-agent-skill)
- [Script format](#script-format)
- [Voices](#voices)
- [CLI reference](#cli-reference)
- [Publish as a real podcast (RSS)](#publish-as-a-real-podcast-rss)
- [How it compares](#how-it-compares)
- [FAQ](#faq)
- [Development](#development)

## Quick start

```bash
# 1. Install (Python 3.10+ and ffmpeg)
pipx install miragea-podcast          # or run without installing: uvx miragea-podcast ...

# 2. Add your Miragea API key (create one at https://miragea.ai/workspace/api)
export MIRAGEA_API_KEY=...
miragea-podcast doctor                # free check: key, network, ffmpeg

# 3. Free dry run with placeholder tones (no credits, no network)
miragea-podcast make examples/earworms.md --preview

# 4. The real episode: one voice per host, cloned from public samples
miragea-podcast make examples/earworms.md --intro-music chime --outro-music chime \
  --host "Alex=https://example.com/alex.wav|Exact words spoken in alex.wav." \
  --host "Sam=https://example.com/sam.wav|Exact words spoken in sam.wav."
```

Or straight from a source, if you have an OpenAI-compatible LLM key (`PODCAST_LLM_API_KEY`, `PODCAST_LLM_BASE_URL`, `PODCAST_LLM_MODEL`):

```bash
miragea-podcast create https://en.wikipedia.org/wiki/Earworm --minutes 5 --style deep-dive \
  --host "Alex=..." --host "Sam=..."
```

Using Claude Code, Codex or Cursor instead? You don't need an LLM key at all: the agent writes the script. Agents can also add the general Miragea integration with: `Install https://miragea.ai/skills/miragea-audio/install.md`.

## How it works

![Pipeline diagram: 1 Source (URL, PDF, text or topic), 2 Script written by your agent or any LLM, 3 Plan that validates speakers, tags and voices and estimates credits for free, 4 Voices generated by the Miragea API with one cloned voice per host in parallel, 5 Mix with turn-taking, overlaps, interruptions, music and a -16 LUFS master, producing publish-ready MP3, transcripts, chapters, show notes and RSS](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/docs/images/flow.png)

1. **Source.** `extract` / `read_source` pulls readable text from HTML pages, PDFs, TXT and Markdown, and skips navigation and scripts.
2. **Script.** One brief (`prompt`, `script_guide`) tells any writer the exact format, the word target (150 words per minute) and the delivery tags. Six styles are built in: deep-dive, debate, interview, explainer, news-brief and panel.
3. **Plan (free).** It parses the script, gives each speaker a distinct voice, maps English tags such as `[laughs]` to the labels Miragea accepts, drops unsupported tags with a warning, splits long turns at sentence boundaries and estimates credits.
4. **Voices.** Segments are generated in parallel, and each request carries a deterministic idempotency key and a local cache. If a run stops halfway, run the same command again: finished segments are reused and nothing is billed twice.
5. **Mix and publish.** It trims silence, keeps natural gaps, starts `[interrupts]` and `[overlap]` turns early so voices really overlap, adds optional intro/outro music, masters to -16 LUFS (the usual podcast target), embeds ID3 chapters and the transcript, then writes every companion file.

## Real demo output

Everything below came from one real run of `examples/earworms.md` (207 words, 2 hosts, 3 chapters, 15 voice requests). No numbers were edited.

![Terminal capture of the real miragea-podcast make run: plan line with 2 speakers and 207 words, 15 segments voiced, mixing and mastering, then the MP3 path, an 84.898 second duration, three chapters at 0, 22 and 50 seconds, and an empty warnings list](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/docs/images/terminal-make.png)

![Waveform of the real 85-second demo MP3 with yellow chapter markers for Cold open, Why it happens, and How to make it stop](https://codeberg.org/miragea-voice/miragea-podcast/raw/branch/main/docs/images/waveform.png)

Files in [`examples/output/`](https://codeberg.org/miragea-voice/miragea-podcast/src/branch/main/examples/output):

| File | What it is |
|---|---|
| `why-songs-get-stuck-in-your-head.mp3` | The episode: 128 kbps MP3 with ID3 title, chapters (CHAP/CTOC), transcript (USLT) |
| `.srt` / `.vtt` / `.txt` | Speaker-labelled transcript for YouTube, players and show notes |
| `.transcript.json` | Podcasting 2.0 JSON transcript |
| `.chapters.json` | Podcasting 2.0 chapters (Apple Podcasts, Pocket Casts, Podverse, Fountain) |
| `.shownotes.md` | Title, summary, hosts and timestamped chapters |
| `.episode.json` / `.rss-item.xml` | Metadata and a ready-made `<item>` for your feed |

As a check, we sent the finished MP3 back through Miragea speech recognition, and it returned the script word for word apart from one homophone ("cereal" heard as "serial").

The two demo voices are cloned from short [CMU ARCTIC](http://www.festvox.org/cmu_arctic/) recordings (speakers `slt` and `bdl`; free for any use, Copyright 2003 Carnegie Mellon University).

## Use it from Claude, Cursor or any MCP client

The MCP server exposes 7 tools: `read_source`, `script_guide`, `list_voices`, `list_tags`, `plan_podcast`, `create_podcast`, `build_feed`. It also has one prompt, `make_podcast`. The agent writes the script itself, so it needs no LLM key.

**Claude Code**

```bash
claude mcp add miragea-podcast -e MIRAGEA_API_KEY=<your-key> -- uvx --from miragea-podcast miragea-podcast-mcp
```

**Claude Desktop, Cursor, Windsurf** (`claude_desktop_config.json`, `~/.cursor/mcp.json`, ...)

```json
{
  "mcpServers": {
    "miragea-podcast": {
      "command": "uvx",
      "args": ["--from", "miragea-podcast", "miragea-podcast-mcp"],
      "env": { "MIRAGEA_API_KEY": "<your-key>" }
    }
  }
}
```

`miragea-podcast config vscode` (or `cursor`, `windsurf`, `claude-desktop`, `claude-code`) prints the exact snippet. Then ask: *"Turn https://example.com/article into a 5-minute two-host podcast, with Alex and Sam."*

## Use it as an Agent Skill

[`skills/ai-podcast/SKILL.md`](https://codeberg.org/miragea-voice/miragea-podcast/src/branch/main/skills/ai-podcast/SKILL.md) teaches Claude Code, Codex, Cursor and other SKILL.md-aware agents the whole workflow: read, brief, write, plan, make, publish. It is also part of the [miragea-skills](https://codeberg.org/miragea-voice/miragea-skills) collection:

```bash
npx skills add https://codeberg.org/miragea-voice/miragea-skills.git
```

## Script format

```markdown
---
title: Why Is the Ocean Salty?
description: Two hosts untangle a question every kid asks.
language: en
---

## Cold open
Alex: [excited] Okay, I learned something wild this week.
Sam: [chuckles] You say that every week.
Alex: Rain slowly dissolves minerals out of rocks—
Sam: [interrupts] Wait, so the salt starts on land?
Alex: [overlap] On land!
[pause 0.6s]

## Where the salt goes
Sam: Rivers carry those minerals to the sea...
```

- `Name: text` is one turn. `## Heading` starts a chapter. 2 to 6 speakers.
- Delivery tags go right before the words they colour: `[laughs]`, `[chuckles]`, `[sighs]`, `[gasps]`, `[whispers]`, `[excited]`, `[surprised]`, `[shouts]`, `[clears throat]` and more (`miragea-podcast tags`). `*laughs*` and `(laughs)` work too.
- `[interrupts]` and `[overlap]` change timing as well as delivery: the turn starts before the other voice has finished.
- `[pause 1.5s]` inserts silence. JSON scripts (`{"chapters": [{"title", "turns": [{"speaker", "text"}]}]}`) are accepted too.

## Voices

Each speaker gets their own voice in one of three ways:

| Spec | Meaning |
|---|---|
| `--host "Alex=actor:ID"` | A voice saved in your Miragea account (`miragea-podcast voices`) |
| `--host "Alex=Emma"` | A saved voice by name |
| `--host "Sam=https://host/sam.wav\|exact words in the sample"` | Zero-shot clone from a public sample (10 to 30 s of clean speech). Adding the transcript after `\|` gives the best match. |

Options can follow after `;`, for example `Sam=actor:123;speed=1.05`. A TOML file works too (`--hosts-file hosts.toml`). Only clone voices you have the right to use.

## CLI reference

| Command | What it does | Credits |
|---|---|---|
| `doctor` | Checks key, API, ffmpeg, saved voices | free |
| `voices`, `tags` | Lists saved voices and delivery tags | free |
| `extract SOURCE` | Prints the text pulled from a URL/PDF/file | free |
| `prompt SOURCE` | Prints the script-writing brief plus source, for any LLM | free |
| `write SOURCE -o script.md` | Writes a script with an OpenAI-compatible LLM | LLM only |
| `plan script.md --host ...` | Validates and estimates | free |
| `make script.md --host ...` | Produces the episode (`--preview` is free) | yes |
| `create SOURCE --host ...` | `write` + `make` | yes |
| `feed DIR --base-url ...` | Builds `feed.xml` from a folder of episodes | free |
| `mcp`, `config CLIENT` | Runs the MCP server / prints client config | free |

Useful flags: `--style`, `--minutes`, `--cast "Name=role"`, `--model expressive|standard`, `--intro-music FILE|chime`, `--outro-music`, `--cover art.jpg`, `--max-credits N`, `--gap 0.32`, `-o DIR`, `--json`.

Environment: `MIRAGEA_API_KEY` (required), `MIRAGEA_BASE_URL` (default `https://miragea.ai/v1`), `MIRAGEA_OUTPUT_DIR`, `MIRAGEA_DEFAULT_MODEL`, `MIRAGEA_CONCURRENCY` (1-8).

## Publish as a real podcast (RSS)

```bash
# upload ./episodes to any static host (S3, R2, GitHub/Codeberg Pages, Netlify), then:
miragea-podcast feed ./episodes --base-url https://cdn.example.com/show \
  --title "Curious Minutes" --author "You" --image https://cdn.example.com/show/art.jpg --email you@example.com
```

The feed is RSS 2.0 with iTunes tags and Podcasting 2.0 `podcast:transcript`, `podcast:chapters` and `podcast:person`. Submit its URL to Apple Podcasts, Spotify for Creators or the Podcast Index. Preview episodes are never published.

## How it compares

| | miragea-podcast | NotebookLM Audio Overviews | podcastfy | open-notebook |
|---|---|---|---|---|
| Open source | Yes (MIT) | No | Yes (Apache-2.0) | Yes (MIT) |
| Edit the script before voicing | Yes, plain Markdown | No (prompt steering only) | Yes (transcript file) | Partly |
| Choose or clone host voices | Any saved or cloned voice per host | Fixed voices | Depends on TTS provider | Depends on TTS provider |
| Interruptions and overlapping speech | Yes (`[interrupts]`, `[overlap]`) | Yes | No (turns play one after another) | No |
| Chapters, SRT/VTT, RSS feed | Yes, all built in | No | Transcript only | No |
| MCP server + Agent Skill | Yes | No | No | No (has its own API) |
| Keys needed | Miragea only (agent writes the script) | Google account | LLM key + TTS key | LLM key + TTS key + database |
| Runs without a GPU | Yes | n/a (hosted) | Yes with cloud TTS | Yes with cloud TTS |

Comparison as of November 2026, based on each project's public docs. Corrections are welcome via issues.

## FAQ

### How do I make a podcast from a PDF with AI?
Run `miragea-podcast prompt paper.pdf --minutes 8`. Paste the brief into any LLM (or let your agent read it), save the script, then `miragea-podcast make script.md --host ... --host ...`. With an LLM key set, `miragea-podcast create paper.pdf --host ... --host ...` does it in one step.

### Is there an open-source NotebookLM Audio Overview alternative?
Yes. miragea-podcast produces the same two-host "deep dive" format, but you can read and edit the script, pick or clone each host's voice, set the length and style, and you get chapters, transcripts and an RSS feed.

### Can I use my own voice as one of the hosts?
Yes. Record 10 to 30 seconds of clean speech, upload it somewhere public (a direct file URL), and pass `--host "Me=https://.../me.wav|the exact words you said"`.

### How do I add an AI podcast tool to Claude Desktop or Cursor?
Add the MCP config shown above, restart the client and ask for an episode. The agent calls `read_source`, writes the script with `script_guide`, checks it with `plan_podcast` and renders it with `create_podcast`.

### How long can an episode be?
`script_guide` accepts up to 90 minutes. Long turns are split at sentence boundaries automatically, and runs are resumable, so long episodes are practical.

### How much does an episode cost?
`plan` prints a credit estimate before anything is spent, and `--max-credits` refuses to run above your limit. Tags, plans, previews and cached re-runs are free. See [miragea.ai](https://miragea.ai) for current plans.

### Does it support languages other than English?
The script format and mixing are language-agnostic. Set `language:` in the front matter and write the script in that language. Subtitles handle CJK width correctly.

### Why is the voice generation not local?
Local multi-speaker TTS needs a GPU, large models and fragile dependencies, and those are the most common issues in similar projects. Cloud voices from one API mean `pipx install` and an API key are all you need.

## Troubleshooting

| Symptom | Fix |
|---|---|
| `MIRAGEA_API_KEY is not set` | Create a key at https://miragea.ai/workspace/api and export it (or put it in the MCP `env` block) |
| `synthesis_failed` | Check that each reference URL is public and returns the audio file directly (`curl -I URL`), then rerun the same command: finished segments are reused |
| `ffmpeg not found` | `brew install ffmpeg`, `sudo apt install ffmpeg` or `winget install ffmpeg` |
| Tag ignored warning | That tag isn't offered on the chosen model; `miragea-podcast tags` lists the valid ones |
| `over_budget` | The estimate exceeded `--max-credits`; nothing was spent |

## Development

```bash
git clone https://codeberg.org/miragea-voice/miragea-podcast.git && cd miragea-podcast
uv venv && uv pip install -e '.[dev]'
pytest            # 36 tests, offline: the Miragea API is mocked with httpx.MockTransport; needs ffmpeg
ruff check .
python docs/make_images.py   # re-render README images and the demo video from examples/output
```

Project layout: `src/miragea_podcast/` (`script.py` parser and segmenter, `voices.py`, `tags.py`, `synth.py` parallel cached synthesis, `mix.py` timeline, mastering and ID3 chapters, `subtitles.py`, `rss.py`, `sources.py`, `server.py` MCP, `cli.py`), `skills/ai-podcast/`, `examples/`, `tests/`.

## License

MIT. Demo voices are derived from CMU ARCTIC (free for any use). "NotebookLM" is a trademark of Google LLC; this project is not affiliated with Google.
