The Problem
Keeping up with the news takes more of the morning than it should — and still leaves you feeling behind.
The Economist, NYT, BBC, TechCrunch, AI newsletters, podcasts — all in different apps, different inboxes, different formats. The signal is buried in the noise, and by the time you've pieced something together, half the morning is gone.
This pipeline produces the alternative: a single briefing, structured by topic, sourced only from outlets you choose, deep enough to leave you genuinely informed, and waiting before you're out the door.
What Lands In Your Inbox
At 5am local time, an email arrives. It contains:
Weather
Today's high, current conditions, and a clothing recommendation for two locations — home and work by default — so you know what to wear before you leave the house.
Categorised News
The example set ships as World & Politics · India · Tech & AI · Business & Finance · Science & Health · Sports — the six sections are fixed, but you set each one's weight and freshness window, and the sources it draws on, in config.json. Adding, removing or renaming a section means editing generate_brief.py. Several stories per section, with real summaries rather than headlines, and a "Why it matters" note on the top stories.
Explore
A discovery section that pulls from its own pool of sources — WIRED, MIT Technology Review, Quanta Magazine, Hacker News, Aeon and more in the shipped config — so you aren't reading the same perspectives every day.
Deep Dive
An optional persistent backlog — one longform read and one podcast episode, each with a day counter showing how long it has been queued, plus what you're currently reading and listening to. A nudge appears from day seven. The queue is personal data, so it is read from a private store you point at with an environment variable; leave it unset and the section is simply omitted.
Audio
The whole brief is narrated and delivered as an MP3, linked directly in the email — for the mornings when listening beats reading. Optional: skip the Deepgram key and you get a text-only brief.
How It Works
A Python pipeline runs on GitHub Actions. No server, no database, no ongoing maintenance.
It's travel-aware: point it at a calendar ICS feed and it detects multi-day trips, works out the destination timezone, and shifts delivery to 5am local time wherever you are (the hour is a constant in the generator, not a setting). Update your calendar and it adjusts — nothing to change in the repo.
1 · Search
Claude uses live web search to gather the day's top stories across your categories, restricted to the outlets on your allowlist and held to a per-section word budget.
2 · Synthesise
Claude cross-references stories across sources and writes substantive summaries, not headline rewrites. The Explore pick favours sources you mark as subscriptions. A post-synthesis validation layer then catches cross-section duplicates, meta-items, hallucinated sources, and explore stories without real URLs — code-level guardrails that hold regardless of whether the model followed the prompt.
3 · Narrate
The brief is converted to a natural spoken script and sent to Deepgram's text-to-speech API, which produces the MP3. The voice and accent are set in config.json. The audio covers the news sections and the Explore segment — Deep Dive links stay email-only.
4 · Deliver
An HTML email is generated and sent via Resend. The HTML and MP3 are committed back to your repository so the email can link the audio directly, then removed by a 7-day retention step so the archive can't grow without bound. The Deep Dive section is stripped from the committed copy — it reaches your inbox and never the archive.
Expect roughly $1.00–1.15 per run at the default 10-minute reading budget — about $30–35 a month running daily. That is almost entirely Anthropic API usage, dominated by the web searches and the tokens their results carry; Deepgram and Resend cost pennies. GitHub Actions is free on public repositories and metered on private ones.
Getting It Running
Five steps, no infrastructure to provision:
1 · Make your copy
Use the repository's Use this template button rather than forking, since a fork of a public repo can't be made private. Recipient, sender domain, weather locations and calendar all arrive through Actions secrets; the reading queue is read from a private store you mount, and the section stays empty without one. Each day's brief and audio are saved to the repo's briefs/ folder with your name and local weather in them: a private copy keeps them to you, but the email's Listen link only plays from a public one.
2 · Add secrets
Only ANTHROPIC_API_KEY is required. Audio, weather and calendar keys are optional, and each feature is skipped when its key is missing. Email takes three secrets together (RESEND_API_KEY, RECIPIENT_EMAILS, SENDER_FROM): set all three or none, or the run stops before spending anything. Set HOME_TIMEZONE too, or it assumes US Pacific time.
3 · Edit the config
One config.json holds your sources, section weights, word budget and personal preferences: Celsius or Fahrenheit, NBA scores, a sports focus, and the narration voice and accent. Keys and personal details stay in Actions secrets.
4 · Dry run
Trigger the workflow manually with dry run enabled: full generation, but no email, no audio and no commits. The output lands as a run artifact so you can read the brief before anyone else does. Then run it with force on to send a real brief straight away; a forced run counts as that day's brief.
5 · Go live
Uncomment the schedule: block in the workflow. It then runs hourly and delivers only at 5am local time — scheduled runs ship disabled so a fresh copy can't email anyone by accident.
Guard Rails
A news pipeline reads your calendar, writes to your repo and sends mail on your behalf. The template treats that as a privacy surface rather than an afterthought:
- PII scanning on every push — a CI workflow scans each commit for email, phone and SSN-shaped strings, with masked output. On a public copy, every committed byte is published.
- Fails closed on personal data — if the private store holding your reading queue is unset or unreachable, the Deep Dive section is omitted with a warning. It is never guessed at, and the queue is never tracked in the repo.
- Honest dry runs — dry-run artifacts contain your personal sections, and the README warns you not to share them.
- 45 tests in CI — the prose linter and regression suites run on every pull request and every push to main. Both are offline and key-free, so they run safely on fork PRs too.
- MIT licensed — fork it, change it, ship it. Third-party attributions are in
NOTICE.
Under the Hood
For the engineers — the full stack, openly published:
- Claude API — Sonnet 5 for story gathering and synthesis; Haiku 4.5 for the narration script, since converting finished prose to speech text is mechanical and costs a fraction as much
- Quality layer — an AI-prose linter, a reading-time word budget allocated by section weight, and a rolling coverage log that suppresses repeats and lets today's brief correct yesterday's
- Deepgram Aura — text-to-speech audio generation; MP3 linked in the email
- Resend — transactional email delivery
- GitHub Actions — scheduled automation, HTML and MP3 storage, and 7-day cleanup
- Python — the pipeline that ties it all together, with no server and no database anywhere in it
Want your own?
The full source is on GitHub under MIT. Copy the template, add one API key, and dry-run it — the README walks through the rest.