Daily Briefing System
Two emails a day — morning context at 5 AM, evening recap at 6 PM — built on a shared Python core.
The problem
Every morning meant opening five apps to piece together the day; every evening, context was scattered across Notion, git, market apps, and weather. I wanted two artifacts — one that says “here’s your day” before coffee, one that says “here’s what happened” before winding down.
The approach
Both emails are thin orchestration scripts on top of vi3-signal, a shared Python core library with stateless modules for each data source: weather (Open-Meteo), anchors and kanban (Notion API), git activity (multi-repo log scanner), market data, MLB stats, and music history. Claude AI receives the assembled raw data and generates a narrative summary. Sections fail independently — a broken market API doesn’t kill the anchor section.
The morning dispatch fires at 5 AM via a macOS LaunchAgent. It synthesizes today’s anchors, weather, MLB schedule, and recent music into a concise read — then generates an MP3 via Edge-TTS (with say as a fallback) and attaches it to the email so you can listen on the commute.
The evening signal fires at 6 PM. It recaps anchor completions by domain, scans all active git repos for the day’s commits, pulls watchlist market performance, counts bookmark inbox changes, and tracks domain streaks (consecutive days of anchor completion) as a motivational close.
How it works
vi3-signal/cli.py exposes both signals as subcommands with --dry-run support. Each signal imports only the core modules it needs. Gmail SMTP with retry logic handles delivery; Jinja2 templates render the HTML. LaunchAgents schedule both signals without a web server or cron daemon.
Results
- 8 data sources unified — anchors, standup, git, market, bookmarks, kanban, weather, streaks
- Audio attachment on the morning email via Edge-TTS, so you can listen instead of read
- Fail-safe sections — one broken API never kills the whole email
- Shared core means adding a new data source once makes it available to both signals