An automated system that generates a daily tech digest from your Bluesky timeline using Claude Code, running every weekday morning at 5am to start your Claude API quota window.
This system fetches your Bluesky timeline, uses Claude to identify and categorize tech-related posts, and generates a beautiful HTML digest that automatically opens in your browser.
Three-stage pipeline for reliability and efficiency:
- Fetch & Parse (
fetch-bsky-posts.py): Fetches 500 posts from Bluesky MCP, parses XML to clean JSON (~180KB) - Analyze (Claude): Reads JSON, identifies tech themes, outputs structured analysis JSON (~3KB)
- Generate HTML (
generate-digest-html.py): Transforms analysis JSON into beautiful HTML digest (~24KB)
Why separate analysis from HTML generation?
- ✅ Claude outputs small JSON instead of large HTML (8x smaller = more reliable, lower cost)
- ✅ Python ensures accurate post links and consistent formatting
- ✅ Easier to debug and test each stage independently
- Claude Code installed
- Bluesky MCP server configured
- macOS (for launchd automation)
-
Copy scripts to
~/bin/:fetch-bsky-posts.py- Fetches posts from Blueskygenerate-digest-html.py- Generates HTML from analysisbsky-digest.sh- Main orchestration script
-
Make scripts executable:
chmod +x ~/bin/{fetch-bsky-posts.py,generate-digest-html.py,bsky-digest.sh} -
Install launchd plist:
cp com.lizf.bsky-digest.plist ~/Library/LaunchAgents/ launchctl load ~/Library/LaunchAgents/com.lizf.bsky-digest.plist
-
Configure system wake (so your Mac wakes up for the 5am job):
sudo pmset repeat wake MTWRF 04:59:00
Run manually to test:
~/bin/bsky-digest.shCheck logs:
tail -f /tmp/bsky-digest.logDefense in depth:
- ✅ Working directory sandboxed to
/tmp - ✅ Only
Read,Writetools allowed (noBash) - ✅ Read-only Bluesky MCP access (no posting/liking)
- ✅ No dynamic code execution from Claude
- ✅ Pre-vetted Python scripts only
- ✅
--permission-mode dontAskfor headless execution
Why this matters:
- Prevents "lethal triad" (Write + Bash + untrusted data)
- No prompt injection risk from malicious Bluesky posts
- Predictable, auditable behavior
Files generated daily:
/tmp/bsky-posts-YYYY-MM-DD.json- Raw posts (180KB)/tmp/bsky-analysis-YYYY-MM-DD.json- Claude's analysis (3KB)/tmp/bsky-tech-digest-YYYY-MM-DD.html- Final digest (24KB)
HTML features:
- Gradient header with stats
- Posts organized by theme
- Theme summaries
- Direct links to original posts
- Responsive design
Typical run:
- Fetches ~400 posts
- Claude identifies 20-30 tech posts
- Groups into 5-8 themes
- Takes ~30 seconds total
Claude usage:
- Input: ~180KB JSON (posts)
- Output: ~3KB JSON (analysis)
- Model: Haiku or Sonnet via
claude -p
Why run at 5am?
- Starts your Claude API quota usage window early in the day
- Fresh tech news digest with your morning coffee
- Automated workflow - no manual intervention needed
Customization:
- Edit tech keywords in the prompt
- Adjust theme count (5-8 default)
- Change schedule in launchd plist
- Modify HTML styling in
generate-digest-html.py
MCP Integration:
Uses claude --mcp-cli call bluesky/get-timeline-posts to fetch posts
XML Parsing: Bluesky MCP returns XML-formatted posts. Uses regex parsing (more robust than XML parsers for this malformed data)
Claude Invocation:
echo "$PROMPT" | claude -p \
--permission-mode dontAsk \
--allowed-tools "Read,Write"Created by @lizthegrey.com
Powered by Claude Code and the Bluesky MCP server
MIT