News Agent
An AI-powered daily tech news aggregator that fetches articles from RSS feeds, filters them by relevance to your interests, generates AI summaries, and emails you a beautifully formatted digest every morning.
Features
- RSS Aggregation: Fetches from 15+ tech news sources covering Development, Self-hosting, Enterprise Architecture, and Gadgets
- AI Filtering: Uses OpenRouter AI to score articles based on your interests (0-10 scale)
- Smart Summarization: Generates concise 2-3 sentence summaries of each relevant article
- Beautiful Emails: HTML email with responsive design, categorized sections, and relevance scores
- Deduplication: SQLite database prevents duplicate articles
- Automated Scheduling: Runs daily at 07:00 Europe/Oslo time via systemd timer
- Production Ready: Error handling, logging, resource limits, and monitoring
Architecture
news-agent/
├── src/
│ ├── aggregator/ # RSS feed fetching
│ ├── ai/ # OpenRouter client, filtering, summarization
│ ├── storage/ # SQLite database operations
│ ├── email/ # Email generation and sending
│ └── main.py # Main orchestrator
├── config.yaml # Configuration
├── .env # Secrets (API keys)
└── systemd/ # Service and timer files
Prerequisites
- Fedora Linux (or other systemd-based distribution)
- Python 3.11+
- SMTP Server (your own mail server or service like Gmail, Outlook, etc.)
- OpenRouter API Key (get from https://openrouter.ai)
Installation
1. Clone/Copy Project
# Copy this project to your home directory
mkdir -p ~/news-agent
cd ~/news-agent
2. Install Python and Dependencies
# Install Python 3.11+ if not already installed
sudo dnf install python3.11 python3-pip
# Create virtual environment
python3.11 -m venv .venv
source .venv/bin/activate
# Install dependencies
pip install -e .
3. Configure News Agent
# Run setup script to copy config files
./setup.sh
# OR manually copy files:
cp .env.example .env
cp config.yaml.example config.yaml
Edit .env file:
nano .env
Add your credentials (NO quotes needed):
# OpenRouter API Key
OPENROUTER_API_KEY=sk-or-v1-...your-key-here...
# SMTP Credentials for your mail server
SMTP_USERNAME=your-email@yourdomain.com
SMTP_PASSWORD=your-smtp-password
Edit config.yaml file:
nano config.yaml
Update the email section:
email:
to: "your-email@example.com" # Where to receive the digest
from: "news-agent@yourdomain.com" # Sender address
smtp:
host: "mail.yourdomain.com" # Your mail server hostname
port: 587 # 587 for TLS, 465 for SSL
use_tls: true # true for port 587
use_ssl: false # true for port 465
Common SMTP Settings:
- Your own server: Use your mail server hostname and credentials
- Gmail:
smtp.gmail.com:587, use App Password - Outlook/Office365:
smtp.office365.com:587 - SendGrid:
smtp.sendgrid.net:587, use API key as password
Important settings to adjust:
ai.model: Useopenai/gpt-4o-mini(recommended, ~$0.05/day) or see MODELS.mdai.filtering.min_score: Lower = more articles (5.5 recommended, was 6.5)ai.filtering.max_articles: Maximum articles per digest (default: 15)email.to: Your email addressemail.from: Sender addresssmtp: Your mail server settings- RSS sources (add/remove feeds)
- Your interests for AI filtering
4. Test Run
# Activate virtual environment
source .venv/bin/activate
# Run manually to test
python -m src.main
Check:
- Console output for progress
- Logs in
data/logs/news-agent.log - Your email inbox for the digest
5. Set Up Systemd Timer
# Copy systemd files to user systemd directory
mkdir -p ~/.config/systemd/user
cp systemd/news-agent.service ~/.config/systemd/user/
cp systemd/news-agent.timer ~/.config/systemd/user/
# Edit service file to update paths if needed
nano ~/.config/systemd/user/news-agent.service
# Reload systemd
systemctl --user daemon-reload
# Enable and start timer
systemctl --user enable news-agent.timer
systemctl --user start news-agent.timer
# Check timer status
systemctl --user list-timers
systemctl --user status news-agent.timer
Enable lingering (allows user services to run when not logged in):
sudo loginctl enable-linger $USER
Usage
Manual Run
cd ~/news-agent
source .venv/bin/activate
python -m src.main
Check Status
# Check timer status
systemctl --user status news-agent.timer
# View logs
journalctl --user -u news-agent.service -f
# Or check log file
tail -f data/logs/news-agent.log
Trigger Manually
# Run service immediately (without waiting for timer)
systemctl --user start news-agent.service
View Last Run
systemctl --user status news-agent.service
Configuration
RSS Sources
Add or remove sources in config.yaml:
sources:
rss:
- name: "Your Source"
url: "https://example.com/feed.xml"
category: "tech" # tech, development, selfhosting, architecture, gadgets
AI Configuration
Models (from cheap to expensive):
google/gemini-flash-1.5-8b- Fast, cheap, good quality (recommended)google/gemini-2.0-flash-exp:free- Free, experimental (good for testing)meta-llama/llama-3.1-8b-instruct:free- Free, decent qualityanthropic/claude-3.5-haiku- Better quality, slightly more expensiveopenai/gpt-4o-mini- Good quality, moderate price
See MODELS.md for detailed comparison and selection guide. Full list at: https://openrouter.ai/models
Filtering:
ai:
filtering:
enabled: true
min_score: 6.5 # Articles below this score are filtered out
max_articles: 15 # Maximum articles in daily digest
Interests:
ai:
interests:
- "Your interest here"
- "Another topic"
Schedule
Change time in ~/.config/systemd/user/news-agent.timer:
[Timer]
OnCalendar=07:00 # 24-hour format
Then reload:
systemctl --user daemon-reload
systemctl --user restart news-agent.timer
Troubleshooting
No Email Received
-
Check logs:
journalctl --user -u news-agent.service -n 50 -
Check Postfix:
sudo systemctl status postfix sudo tail -f /var/log/maillog -
Test email manually:
echo "Test email" | mail -s "Test" your-email@example.com
API Errors
Error: "No endpoints found for [model]"
- The model name is incorrect
- Check correct model names in
MODELS.md - Update
config.yamlwith correct model ID
Other API errors:
- Verify API key in
.env - Check OpenRouter credit balance: https://openrouter.ai/credits
- Check rate limits in logs
- Try a different model (see
MODELS.md)
Service Not Running
# Check service status
systemctl --user status news-agent.service
# Check timer status
systemctl --user status news-agent.timer
# View detailed logs
journalctl --user -xe -u news-agent.service
Database Issues
# Reset database (WARNING: deletes all history)
rm data/articles.db
python -m src.main
Cost Estimation
Using google/gemini-flash-1.5-8b (recommended):
- Daily: ~$0.05-0.15 (varies by article count)
- Monthly: ~$1.50-4.50
- Yearly: ~$18-54
Free Options:
google/gemini-2.0-flash-exp:free- Completely free (experimental)meta-llama/llama-3.1-8b-instruct:free- Completely free
Factors affecting cost:
- Number of new articles
- Content length
- Filtering threshold (lower = more articles = higher cost)
Maintenance
Update Dependencies
cd ~/news-agent
source .venv/bin/activate
pip install --upgrade -e .
View Statistics
# Check database
sqlite3 data/articles.db "SELECT COUNT(*) FROM articles;"
sqlite3 data/articles.db "SELECT category, COUNT(*) FROM articles GROUP BY category;"
Logs Rotation
Logs automatically rotate at 10MB with 5 backups (configured in config.yaml).
Advanced Features
Add API News Sources
Extend src/aggregator/api_fetcher.py to support NewsAPI, Google News API, etc.
Customize Email Template
Edit src/email/templates/daily_digest.html for different styling.
Web Dashboard
Add Flask/FastAPI to create a web interface for viewing past digests.
Contributing
This is a personal project template. Feel free to fork and customize to your needs.
License
MIT License - Free to use and modify
Support
For issues with:
- OpenRouter: https://openrouter.ai/docs
- Postfix: Fedora documentation
- This code: Check logs and configuration
Credits
Built with:
- Python 3.11+
- OpenRouter AI (https://openrouter.ai)
- Feedparser, Jinja2, Pydantic, and other open-source libraries