Deterministic RSS feed aggregator that outputs Markdown. No AI, no generative content -- just fetches, filters, and formats RSS/Atom feeds from a curated list.
Get started in 60 seconds: Copy this prompt into Claude Code and it'll set everything up for you -- finds your feeds, builds your config, schedules the daily task, done.
Copy and paste this prompt into Claude Code to have it walk you through the entire setup interactively:
Click to expand the setup prompt (copy button appears in top-right of code block)
I want you to help me set up Gazzeton (https://github.com/gregqualls/gazzeton) as a daily
news aggregator on my machine. Walk me through the entire process interactively.
IMPORTANT: Start by reading the README.md in the gazzeton repo after cloning — it has full
documentation on how the tool works, the config format, CLI options, and examples.
Here's what I need you to do, step by step:
1. CLONE & INSTALL
- Clone the repo to a sensible location on my machine
- Detect whether I'm on macOS, Linux, or Windows
- Read the README.md to understand how gazzeton works
- Check that Python >= 3.10 is available
- Run `pip install -e .`
- Copy feeds.example.yaml to feeds.yaml
2. DISCOVER MY INTERESTS
Ask me what topics and interests I want to follow. Be conversational — ask about:
- My profession/industry (for work-relevant feeds)
- Hobbies and personal interests
- Specific companies, products, or people I want to track
- Local area (city/region) for local news and events
- Whether I want any Twitter/X accounts included
- How much content I want (light briefing vs comprehensive)
3. BUILD MY feeds.yaml
Based on my answers:
- Search the web for the best RSS feeds for each topic
- Verify each feed URL actually works by testing it with:
python -c "import feedparser; f = feedparser.parse('URL'); print(len(f.entries), 'entries')"
- Remove any feeds that return 0 entries or parse errors
- Organise feeds into logical categories
- Set per-feed `hours` overrides for infrequent sources (blogs: 168h, local events: 72h)
- Write the final feeds.yaml
4. TEST RUN
Run `python -m gazzeton --stdout --hours 48` and show me a sample of the output
to confirm everything is working. Fix any feeds that error.
5. SCHEDULE IT
Ask me two things:
- What time should it run daily? (default: 3am)
- Where should the daily output file be saved? (default: ~/Documents/gazzeton-latest.md)
Then set it up based on my OS:
macOS:
- Create a launchd plist at ~/Library/LaunchAgents/com.gazzeton.daily.plist
- Set it to run at my preferred time
- Output to my chosen path
- Load it with: launchctl load ~/Library/LaunchAgents/com.gazzeton.daily.plist
Linux:
- Add a cron job pointing to my chosen output path
Windows:
- Create a run-daily.bat script with my chosen output path
- Create a Windows Task Scheduler task using:
powershell.exe -Command "schtasks /create /tn 'Gazzeton Daily News' /tr 'C:\path\to\run-daily.bat' /sc daily /st 03:00 /rl limited /f"
- Include cleanup of dated files older than 30 days
6. SET UP A COWORK SKILL (if I use Claude Cowork)
Ask if I use Claude Cowork or Claude Code with scheduled tasks. If yes:
- Create a news-briefing skill that reads from my chosen output path
- The skill should curate the top stories, group by category, skip noise,
and flag anything relevant to my work
- Save it as a Cowork skill in the appropriate location
7. VERIFY EVERYTHING
- Run gazzeton once to confirm the output file is created at my chosen path
- Show me a summary of what was set up
- Tell me how to manually re-run it if needed
- Tell me how to add/remove feeds later
Start by cloning the repo, reading the README, detecting my OS, and then asking about
my interests and preferences.
AI assistants like Claude are great at summarising and curating news, but they struggle with web searches: results are inconsistent, stories repeat across runs, and sandboxed environments (like Claude Cowork) can't make outbound network requests at all.
Gazzeton solves this by running on your machine as a scheduled task. It fetches RSS feeds deterministically, writes a clean Markdown file, and your AI assistant reads that local file instead of searching the web. The result is a reliable daily news pipeline:
- Gazzeton runs at 3am (or whenever), fetches all your feeds, writes
gazzeton-latest.md - Your AI assistant reads that file and gives you a curated, summarised briefing
- You get consistent, fresh, never-repeated news every morning
No API keys. No web scraping. No AI in the loop. Just RSS.
git clone https://github.com/gregqualls/gazzeton.git
cd gazzeton
pip install -e .
# Create your feed config from the example
cp feeds.example.yaml feeds.yamlEdit feeds.yaml to add your own feeds, categories, and settings. The example comes pre-loaded with popular tech, AI, and gaming feeds to get you started.
Run from the gazzeton project directory (where feeds.yaml lives):
# Default: fetch last 24h, all categories, save to ./output/gazzeton-YYYY-MM-DD.md
python -m gazzeton
# Print to stdout (useful for piping to Claude or other tools)
python -m gazzeton --stdout
# Custom time window
python -m gazzeton --hours 48
# Filter to specific categories (repeatable, case-insensitive)
python -m gazzeton --category "Warhammer" --category "Dungeons & Dragons"
# Custom output file
python -m gazzeton -o /path/to/briefing.md
# Point to a different config file
python -m gazzeton --config /path/to/feeds.yaml| Flag | Description |
|---|---|
--hours N |
Time window in hours (default: 24, configurable in feeds.yaml) |
--category NAME |
Filter to named categories, repeatable |
-o, --output PATH |
Write output to a specific file |
--stdout |
Print Markdown to stdout |
--config PATH |
Path to feeds.yaml config file |
- Status messages (feed count, article count, errors) go to stderr
- Markdown output goes to stdout (with
--stdout) or a file - Exit code 0 on success, 1 on config errors
All configuration lives in feeds.yaml. Edit this file to add, remove, or reorganise feeds.
settings:
hours: 24 # Default time window
output_dir: ./output # Where output files are saved
max_articles_per_feed: 20
fetch_timeout: 10 # Per-feed timeout in seconds
rsshub_url: https://rsshub.app # RSSHub instance for Twitter/XEach feed entry needs a name and url. The URL can be:
Direct RSS/Atom feed URL (used as-is):
- name: xkcd
url: https://xkcd.com/rss.xmlRegular website URL (RSS feed is auto-discovered from <link> tags or common paths):
- name: Goonhammer
url: https://www.goonhammer.comTwitter/X profile URL (converted to RSS via RSSHub):
- name: Anthropic
url: https://x.com/AnthropicAIAny feed can have its own hours override. This is useful for feeds that post infrequently (blogs, local event sites) so you don't miss content when you skip a day or weekend:
- name: D&D Beyond
url: https://www.dndbeyond.com/posts.rss
hours: 168 # look back 7 days even if global setting is 24h
- name: BBC Manchester
url: https://feeds.bbci.co.uk/news/england/manchester/rss.xml
hours: 72 # 3 days - catch weekend posts on MondayFeeds without hours use the global settings.hours value (or the --hours CLI flag).
Feeds are grouped into categories. Categories control the section headings in the output and can be filtered with --category.
categories:
- name: "AI / Machine Learning"
feeds:
- name: OpenAI News
url: https://openai.com/news/rss.xml
- name: HuggingFace Blog
url: https://huggingface.co/blog/feed.xml
- name: "Warhammer"
feeds:
- name: Goonhammer
url: https://www.goonhammer.com
- name: Reddit r/Warhammer40k
url: https://www.reddit.com/r/Warhammer40k/.rssOutput is a Markdown file structured by category, then by source within each category. Articles are sorted newest-first.
# Gazzeton - 2026-04-13
*Generated 2026-04-13 07:00 UTC | Last 24h window*
## AI / Machine Learning
### OpenAI News
- [Article Title](https://example.com/article) -- *2h ago*
> First ~200 characters of the article description...
## Warhammer
### Goonhammer
- [Another Article](https://example.com/another) -- *5h ago*
> Description text...
---
**45** articles from **41** feeds checkedA stats footer shows total articles and feed count. If any feeds failed, errors are listed in a collapsible <details> block.
- Reads
feeds.yamlfor the list of categories and feed URLs - Discovers RSS feeds from any URL type (direct RSS, website, or Twitter/X)
- Fetches all feeds in parallel (10 concurrent threads)
- Filters articles to the configured time window (default 24h)
- Formats results as Markdown grouped by category and source
- Writes the output to a file and/or stdout
Deduplication is time-window based: only articles published within the last N hours are included. No persistent database is needed. Each run produces a fresh snapshot.
cd /path/to/gazzeton && python -m gazzeton --stdout
Claude reads the stdout output directly. The --stdout flag sends Markdown to stdout while status goes to stderr.
Since Cowork's sandbox often blocks outbound network requests, the recommended setup is:
- Schedule gazzeton to run on your machine (cron, Task Scheduler, launchd)
- Write the output to a known file path
- Your Cowork skill reads that local file
Linux/macOS cron (daily at 3am):
0 3 * * * cd /path/to/gazzeton && python -m gazzeton -o /path/to/gazzeton-latest.mdWindows Task Scheduler:
Create a .bat file:
@echo off
cd /d "C:\path\to\gazzeton"
python -m gazzeton --config feeds.yaml -o "%USERPROFILE%\Documents\gazzeton-latest.md"Here's a starter skill that reads gazzeton output and generates a curated briefing. Save this as a Cowork skill and adjust the file path:
---
description: "Daily news briefing from RSS feeds. Use when the user asks for news, a morning briefing, or 'what's happening today'."
---
# Daily News Briefing
Read the gazzeton RSS digest and produce a curated briefing for the user.
## Steps
1. Read the latest gazzeton output:
```
~/Documents/gazzeton-latest.md
```
2. If the file doesn't exist or is more than 36 hours old, inform the user that gazzeton hasn't run recently and suggest they run it manually:
```bash
cd /path/to/gazzeton && python -m gazzeton -o ~/Documents/gazzeton-latest.md
```
3. From the gazzeton output, curate a briefing:
- **Lead with the top 3-5 most significant stories** across all categories
- Group remaining stories by category
- For each story, write a 1-2 sentence summary (don't just copy the RSS description)
- Skip low-signal items (job postings, listicles, routine press releases)
- Flag anything that might require action or is directly relevant to the user's work
4. End with a quick count: "X articles reviewed across Y categories"Customise the file path and curation criteria to match your setup and interests.
gazzeton/
feeds.example.yaml # Example config — copy to feeds.yaml to get started
feeds.yaml # Your personal feed config (gitignored)
pyproject.toml # Python package config
LICENSE # MIT
src/gazzeton/
cli.py # CLI entry point (click)
config.py # YAML config loader
discover.py # RSS autodiscovery + Twitter/X support
fetcher.py # Parallel RSS fetcher with time filtering
formatter.py # Markdown output formatter
output/ # Default output directory (gitignored)
- Open
feeds.yaml - Add a new entry under the appropriate category (or create a new category)
- Use any URL -- RSS feed, website, or Twitter/X profile
- Run
python -m gazzeton --stdout --hours 48to verify it works
Twitter doesn't provide native RSS feeds. Gazzeton routes Twitter/X URLs through RSSHub, an open-source RSS bridge.
The default public instance (https://rsshub.app) has rate limits. If you hit them, you can self-host RSSHub and update the rsshub_url setting in feeds.yaml.
Gazzeton is a read-only tool with a small attack surface:
- No credentials or API keys -- nothing to leak. No
.envfile, no auth tokens. - No inbound network access -- it only makes outbound HTTP requests to fetch RSS feeds.
- HTML sanitization -- feedparser strips HTML content by default, preventing injection via malicious feed content.
- User-controlled config -- gazzeton only fetches URLs you put in
feeds.yaml. It never fetches arbitrary URLs from external input. - Local output only -- results are written to a local Markdown file. Nothing is sent to external services.
- No code execution -- feed content is treated as data, never evaluated or executed.
The only external network calls are HTTP GETs to the RSS feed URLs in your config and (if you use Twitter/X feeds) to your configured RSSHub instance.
- Python >= 3.10
- feedparser -- RSS/Atom parsing
- PyYAML -- config file
- click -- CLI