The steps run in this order every time. They're defined in src/orchestrator.py.
Each source type has its own collector in src/scrapers/. RSS and Atom feeds are parsed with feedparser. For lab blogs and long-form feeds, the full article is also downloaded and cleaned with trafilatura, so Claude reads the whole post, not just a teaser. Hacker News comes from its official API and includes the top comments.
No AI
If the same link turns up from two sources, for example an OpenAI post that is also on Hacker News, the copies are merged into one item that keeps the discussion from both.
No AI
Each item goes to Claude with its profile's rules (profiles/ai-news/analysis.md), the article text, and engagement figures such as upvotes and comment counts. Claude returns JSON with a score from 0 to 10, a reason, a one-line summary, and 3–5 tags. If the JSON is malformed it gets one retry.
Claude · ~100 calls
Items scoring below their profile's threshold are dropped. That's 6 for AI news and 5 for the deep-dive blogs.
No AI
Different links about the same event, such as five articles on one model launch, are grouped by Claude. Only the highest-scoring version is kept, with the others' text folded in.
Claude · 1 call
Items are sorted by score, then each source category may only fill its quota (see the quota chart). The briefing is capped at 20 items. Write-ups are only done after this, so no tokens are spent on items that wouldn't make it in.
No AI
Claude writes the final sections for each item. It has two tools: web_search for facts the article doesn't include, and history_search, which looks through your earlier briefings so it can say what has changed since a previous report.
Claude · ~10 calls + tools
The items are grouped under "AI News" and "Technology Blog" and rendered as Markdown. The Markdown is saved and converted to HTML. Then it's sent with a plain-text copy through Gmail, using an encrypted SMTP connection on port 465 and your App Password.
No AI