ideas.
April 29, 2026 2 min read self-hostedconsumeraicontent

Self-hosted RSS reader with AI triage

A self-hosted feed reader that scores incoming articles by relevance using a local LLM, so the most useful items surface first instead of drowning in chronological noise.

The idea

A web app you run on your own server that polls RSS and Atom feeds and ranks every incoming article by how well it matches a plain-English interest profile you write once. Instead of a flat reverse-chronological list, you see a scored queue — highest relevance at the top. The scoring runs entirely locally via Ollama, so no reading history leaves your machine.

Why build this

Anyone following more than a dozen feeds knows the firehose problem: volume overwhelms signal within days of subscribing to anything interesting. Commercial services like Feedly and Inoreader offer some filtering, but they require a subscription and log your reading habits on their servers. The missing piece has been affordable, private inference. Running a capable language model locally — llama3 or Mistral on modest hardware — is now routine, which makes per-article relevance scoring cheap enough to do on every poll cycle. The integration layer tying feed fetching to LLM scoring is a thin, buildable gap.

Stack sketch

  • Backend: Python with FastAPI; handles feed polling, scoring queue, and the REST API
  • Feed parsing: feedparser for RSS/Atom normalization, httpx for async fetching
  • LLM scoring: Ollama HTTP API running llama3.2:3b locally — small enough to score a batch of articles in a few seconds
  • Database: SQLite via sqlite-utils; one table for feeds, one for articles with score and read status
  • Frontend: HTMX + Jinja2 templates served by FastAPI, no JavaScript build step
  • Deployment: single Docker container, SQLite database on a mounted volume

Scope for v1

  • Add and remove feed URLs through a settings page; store the interest profile as an editable text field in the same settings view
  • Poll feeds on a configurable interval (default: every 30 minutes) via APScheduler running in-process
  • Score each new article's title + summary snippet against the interest profile; store the 0–10 float returned by the LLM
  • Render articles sorted by score descending; show source, publish date, and score badge
  • One-click "mark as read"; unread count in the page title
  • Out of scope for v1: OPML import, multi-user accounts, full-text fetch, email digest, mobile app

Where it could go

The obvious next step is a feedback loop. When you mark an article as "useful" or explicitly skip it, the system logs that signal and can periodically re-prompt the LLM with a refined profile, or train a small logistic regression classifier on top of the raw scores. Over a few weeks the rankings get meaningfully more accurate without any manual tuning.

A second path is lightweight sharing. One instance, multiple interest profiles — each user logs in with a password, maintains their own profile, and sees their own ranked queue. Add a "share" button that sends an article link to a teammate's unread queue, and the reader doubles as a low-friction internal link-sharing tool for small teams.

Watch out for

Not all feeds publish a stable guid field; without one, deduplication after a feed hiccup requires a fallback key (URL + title hash). Scoring every article synchronously during polling will block the queue on slower hardware — run scoring as a background task so the UI stays responsive even when Ollama is busy with a larger batch.