← Writing

dawncast: a morning briefing podcast for repos your agents worked on overnight

github.com/nero408/dawncast →

I run a lot of overnight agent loops. Research ideas, prototypes, refactors I'd never have the patience to do by hand — I queue them up before bed and let them grind. By morning the repo has new commits, a couple of PRs, and a sprawl of agent-authored markdown notes that read like a stream-of-consciousness diary of every dead end the agent walked down at 3am.

I also have a dog. He needs walking around 7. Reading diffs with a leash in one hand and a coffee in the other is not a workflow — it's a way to spill coffee on the dog. What I wanted was a podcast: a 3-minute briefing I could listen to on the way to the field, and arrive knowing what shipped.

So I built dawncast. It's a Python CLI that turns the overnight delta on a git repo into a multilingual audio briefing.

terminal
$ dawncast podcast --since overnight --languages "English,German"

▸ collecting commits in main since 2026-05-19 18:00 …  14 commits
▸ enriching with GitHub PRs (gh)  …                     3 PRs
▸ picking up agent journals       …                     2 markdown files
▸ rendering producer brief        …                     briefings/repo-2026-05-20.md
▸ podcastfy: writing dialogue (gemini)  …               ✓
▸ podcastfy: rendering audio (edge)     …               ✓ english (2m41s)
                                                         ✓ german  (2m48s)

→ out/dawncast-repo-english.mp3
→ out/dawncast-repo-german.mp3

Two stages, one pipeline

The pipeline splits cleanly in half, and that split is load-bearing — most of the design decisions fall out of it.

Stage 1 — the briefing. Collect everything the morning-self needs to know: commits in the window, file changes (with collapsed diffs), GitHub PRs pulled via gh if it's authenticated, and any agent-authored markdown notes inside the repo. Render it all into a single producer-ready markdown file. That file is useful on its own — it's a perfectly reasonable PR description, a standup note, a "what did the agent do" log. No audio, no API keys, no network. dawncast briefing stops here.

Stage 2 — the podcast. Hand the briefing to podcastfy, which has an LLM write a two-host conversation from it and a TTS engine speak it. By default the TTS is Microsoft Edge TTS — free, no API key, neural voices in 60+ languages.

The reason the split matters: the briefing is deterministic and cheap; the podcast is stochastic and (potentially) expensive. Keeping them as separate commands means I can iterate on the briefing format without burning LLM tokens, and I can re-render audio in a different language from a cached briefing without re-walking git history.

The signals beyond git log

If all you wanted was a summary of overnight commits, you don't need a tool — you need git log --since=yesterday | claude. The reason that's not enough is that agents don't only commit. They narrate.

Mine drop files like WINNER_REPORT.md (which of three competing approaches won the bake-off), FEATURE_BACKLOG.md (what's queued for the next loop), NORTH_STAR.md (the agent's current understanding of the goal), and journal.md (everything that didn't fit elsewhere). These files often contain the why behind the diff — and a diff without a why is just noise on a 7am walk.

dawncast auto-discovers them. Out of the box it picks up WINNER_REPORT*.md, FEATURE_BACKLOG.md, NORTH_STAR.md, AGENT_LOG*.md, docs/agents/*.md, and anything under .dawncast/journal*.md, provided they were touched in the window. If your agent already writes to one of those paths, you get journal pickup for free. If it doesn't, point it at .dawncast/journal.md and you're done.

GitHub PRs come through the same window filter, via gh. Title, state, author, body. If gh auth status is happy, they're in the brief. If not, --no-prs and move on.

Two modes: overnight and feature

Same engine, two framings — and the framing is what makes the audio listenable.

The feature mode is the one I didn't expect to keep using. It turns out a 5-minute audio walkthrough of a branch is a surprisingly good PR companion — I'll generate one before I write the actual PR description, listen to it, and find that the hosts already articulated the trade-off I was about to bury in a bullet point.

Decoupling dialogue from voice

podcastfy needs two model choices: an LLM to write the script, and a TTS engine to speak it. dawncast treats these as independent picks — you can mix any LLM with any TTS — because the cost curves are completely different.

The cheapest viable combo: Gemini for dialogue (free tier, generous), Edge for voices (free, no key, multilingual). That's the default. Upgrade either side independently when you want to: --tts elevenlabs for emotive multilingual voices, --llm-model gpt-5.2 for sharper dialogue, mix and match. The provider matrix in the README has the full menu.

Speaking of multilingual — dawncast ships voice mappings for sixteen languages on Edge: English, German, Spanish, French, Italian, Portuguese, Dutch, Polish, Swedish, Japanese, Chinese, Korean, Arabic, Hindi, Turkish, Russian. --languages "English,German" generates one MP3 per language from a shared briefing. I use both — English for technical density, German for ambient listening on the walk.

dawncast doctor

The CLI feature I wish more tools had. Run it and you get a PASS/WARN/FAIL table:

terminal
$ dawncast doctor --tts edge
 PASS  python      3.12.4
 PASS  git         2.45.1
 PASS  gh          authenticated as nero408
 PASS  ffmpeg      7.0.1
 PASS  podcastfy   importable (0.4.3)
 PASS  llm key     GEMINI_API_KEY set
 PASS  tts key     edge needs no key

 → briefing path: OK
 → podcast path:  OK

Every row that isn't green comes with a concrete fix suggestion — the env var to set, the package to install, the command to run. It exits 0 when the briefing path is functional (warnings are non-fatal) and 1 when something is actually broken. When the pipeline misfires at 6am, dawncast doctor is faster than reading the stack trace, and it's almost always the answer.

Building this was the most boring part of the project and easily the highest-leverage. Diagnostic tools earn their keep on day 30, not day 1.

The morning ritual

The end state, after a few weeks of using it:

cron
# Every weekday at 07:30, generate yesterday's recap.
30 7 * * 1-5  cd ~/work/my-repo && \
              /opt/homebrew/bin/dawncast podcast \
                --since overnight \
                --languages "English,German" \
                -o ~/morning-briefings/$(date +\%Y-\%m-\%d)

By the time I'm in the kitchen, today's folder has two MP3s in it. I AirDrop them to my phone, clip the leash on the dog, and walk. Most days the English one is enough; on days where the agent did something architecturally weird I'll listen to the German one too, because the slower cadence makes me re-process it.

What I didn't expect: hearing the work read out loud catches problems I'd have missed reading the diff. "The agent rewrote the retry logic" lands differently as audio than as a green-on-black +47 -23. Several times I've turned around mid-walk and gone back to revert something.

What I learned building it

A few things were surprisingly easy:

A few were surprisingly hard:

Install

sh
# Briefing only — no API keys, no network
uv tool install dawncast

# Briefing + audio (the --overrides flag is load-bearing, see below)
uv tool install \
  --overrides https://raw.githubusercontent.com/nero408/dawncast/main/constraints.txt \
  'dawncast[podcast]'

# Then point at a free LLM and you're done
export GEMINI_API_KEY=…   # https://aistudio.google.com/apikey
dawncast doctor

Python 3.11–3.13. pipx and pip work too. ffmpeg is required for some TTS providers (audio merging) — brew install ffmpeg on macOS. Everything else dawncast doctor will tell you about.

Where it's headed

If any of that sounds useful — or you have a use case I haven't thought of — open an issue. PRs welcome.

Try it

sh
uv tool install 'dawncast[podcast]'
export GEMINI_API_KEY=…
cd ~/your/repo
dawncast podcast --since overnight --languages English

Three minutes later you have an MP3. Put it on your phone, clip the leash on the dog, and find out what your agents did while you slept.


@nero408 ← All posts