8000 feat(sources): RSS and Atom news feeds as a source by adeelahmad · Pull Request #453 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(sources): RSS and Atom news feeds as a source - #453

Merged
adeelahmad merged 16 commits into
mainfrom
claude/project-thread-8xn6n8
Oct 17, 2026
Merged

adeelahmad merged 16 commits into
mainfrom
claude/project-thread-8xn6n8

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 16, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: Lens had no way to follow a blog or news site. RSS and Atom feeds could not be added as a source.

After: on the Sources page, Add → News feed (RSS or Atom) takes a feed's address, or a site's page that names its feed (<link rel="alternate">). Each post shows as a file (2026-09-30 New buoys.atom), and a watch imports new and edited posts as text resources with the post's link, author, feed and dates, so answers cite the post. The same works through the API (POST /api/v1/sources with type: "rss").

How: rss.py is a non-storage source module beside iCal and Google Calendar (feeds.OWN). The address is sealed like an iCal link. Feeds are fetched through the existing SSRF guard (netguard, public addresses or documents.web_networks), with conditional GET (ETag / Last-Modified) so an unchanged feed costs a tiny request and no parsing. The iCal download code moved into a shared feeds.get both use. Feeds are parsed with feedparser (BSD-2) from bytes, with external entities off; post HTML is sanitized and links made absolute. Each post is stored as an Atom entry document (RFC 4287), read as Markdown text for indexing. A feed's posts leave memory five minutes after a read; its listing stays. A new feed_post content type recognises .atom files, and .atom can be imported directly. The README lists news feeds as built, with their checks in docs/requirements.md.

The threat model's news feed entries (a "News feed sources" entry point, and news feeds beside iCal in P-SECRETS, P-ADMIN-GUARD and N-EGRESS) follow in their own small pull request right after this one: every other change to the threat model conflicted with this pull request while its CI ran, five times.

Motivation and Context

Adeel asked "Do we allow rss feeds?" and said yes to adding them.

Steps to reproduce (if appropriate):

  1. Sources → Add → News feed, paste https://example.org/blog.
  2. Watch it into a namespace with backfill on: every post is imported as text, titled and dated by the post.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests. (tests/api/test_news_feed_source.py, test_content_types.py, __tests__/sources-model.test.ts)
  • My change requires documentation updates, and I have updated docs/ accordingly. (processing.md News feeds, sensors.md, configuration.md, requirements.md, README)
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Done questions (AGENTS.md)

  • Goal: delivers what the user wanted, merged on green CI. (Merging on green; the threat model entry, activity events for automations and MCP subscribe tools follow in small PRs.)
  • Agents: usable through the API (/api/v1/sources, /watches); dedicated MCP/assistant tools follow in a later PR.
  • Zero setup: feedparser is a pure-Python dependency installed with the backend; nothing to configure.
  • Fewest clicks and keystrokes: one field (the address); a site's page works, the feed is found from it.
  • Configurable: optional user/password in the source form; everything else uses the source and watch settings that exist.
  • Light: text only, no Chromium or conversion; posts dropped from memory after five minutes; conditional GET.
  • Private and secure: address sealed, SSRF guard, password only to the feed's own server, XXE off, HTML sanitized. The threat model entry lands in the next PR.
  • Cost: no model call to read a feed; posts go through the usual analysis pipeline and its budgets.
  • User decides: nothing is subscribed until the user adds a source; defaults unchanged.
  • Upgrades: the new content type is seeded idempotently; no stored-data shape changes.
  • Honest: each post keeps its link, author and feed, so answers cite it; README lists it as built only with this merge.
  • Tests, docs and generated files updated (make openapi, make requirements).
  • Open standards (RSS, Atom RFC 4287, Dublin Core creator); feedparser is BSD-2, sgmllib3k PSF.
  • Result reported with evidence; "refine later" in docs/processing.md (JSON Feed, full-article fetch, OPML import).
  • Reuse: feedparser for parsing, the existing iCal fetch path (feeds.get), netguard and the source/watch machinery.

🤖 Generated with Claude Code

https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK

A news feed is a new non-storage source type, "rss". Its address (a feed,
or a site's page that names one) is sealed like an iCal link; each post is
listed as its own Atom entry file (.atom), watched like any source and
imported as a text resource with its link, author and dates, so answers
cite the post. Feeds are fetched through the SSRF guard with conditional
GET, parsed with feedparser (BSD) with external entities off, and post HTML
is cleaned before it is kept. Adds the feed_post content type, docs, the
threat model entry point and the web app's source form.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
@adeelahmad adeelahmad self-assigned this Oct 16, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
adeelahmad added a commit that referenced this pull request Oct 16, 2026
Automations merged (#432 to #464): the stream now holds every kind of
activity, the Timeline page reviews it, and automations act on it with
triggers, conditions, actions, approvals, limits and budgets, made by
agents over MCP and in the assistant or drafted from a sentence. Say so
under Automate it, with the studio labelled planned as
docs/automations.md does; add the open RSS feeds (#453) and condition
operators (#434) to In progress; link the timeline from the docs index.


Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.json
#	threat-model.md
#	threat-model.yaml
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
…-8xn6n8

# Conflicts:
#	CHANGELOG.md
#	threat-model.yaml
The threat model's news feed entries move to their own pull request, so this one stops conflicting with every
other change to the threat model while its CI runs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK
@adeelahmad
adeelahmad merged commit 563548d into main Oct 17, 2026
19 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-8xn6n8 branch October 17, 2026 07:29
adeelahmad added a commit that referenced this pull request Oct 17, 2026
News feeds (#453) are fetched like iCal feeds: through netguard, with their address and password sealed. The
threat model now says so: a News feed sources entry point, and news feeds beside iCal in P-SECRETS, P-ADMIN-GUARD,
N-EGRESS, the outbound domains and the web networks hazard.


Claude-Session: https://claude.ai/code/session_01SWH8a26M9wkAPq2eRrfWZK

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0