npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rss-ai

v0.1.12

Published

A powerful CLI RSS/Atom feed reader with OPML support, smart caching, full-text search, content extraction, and interactive TUI

Readme

RSS CLI

A powerful CLI RSS/Atom feed reader with OPML support, smart caching, full-text search, content extraction, broken link repair, and an interactive TUI. Built with Bun, Drizzle ORM, and SQLite.

Installation

# Run directly with bunx (no install required, requires Bun)
bunx rss-ai --help

# Or install globally
bun install -g rss-ai
rss-ai --help

The published npm package requires Bun 1.3.3 or newer. To produce a local standalone executable, clone the repository and run bun run build as shown under Development; releases do not currently publish prebuilt platform binaries.

All examples below use rss as shorthand for bunx rss-ai.

Quick Start

# Add a feed (database auto-initializes on first use)
rss feed add https://hnrss.org/frontpage

# Fetch all feeds
rss fetch all

# List unread articles
rss article list --unread

# Read an article
rss article show 1

# Launch interactive TUI
rss tui

Features

  • RSS & Atom feed support with lenient parsing
  • OPML import/export (1.0, 1.1, 2.0)
  • Smart caching with ETag, Last-Modified, and content hashing
  • Full-text search via SQLite FTS5
  • Content extraction from original article links
  • Broken link repair (HTTP/HTTPS, www toggle, archive.org fallback)
  • Flexible date filtering (ISO, relative, natural language, ranges)
  • JSON output on every command for scripting and agent workflows
  • Interactive TUI with keyboard navigation and markdown rendering
  • Auto-migration database on every boot via Drizzle ORM
  • Per-process, per-domain rate limiting to avoid server hammering
  • Concurrent fetching with configurable parallelism

Global Options

| Flag | Description | |------|-------------| | -d, --database <path> | Path to SQLite database (default: ~/.config/rss-ai/rss.db) | | -j, --json | Output as JSON | | -q, --quiet | Suppress non-essential output | | -v, --verbose | Show full error stack traces |

Commands

Feed Management

rss feed add <url>                       # Add a new feed
  -t, --title <title>                    # Custom title
  -c, --category <category>              # Assign category
  --no-fetch                             # Skip initial fetch

rss feed list                            # List all feeds
  -c, --category <category>              # Filter by category
  --active / --inactive / --errors       # Filter by status

rss feed remove <id>                     # Remove feed and its articles (prompts in a TTY)
  -f, --force                            # Required for scripts, JSON, and non-interactive use
rss feed update <id>                     # Update feed properties
  -t, --title / -c, --category           # New title or category
  --activate / --deactivate              # Toggle active status

rss feed categories                      # List all categories

rss feed cleanup --force                 # Remove feeds with errors
  -e, --errors <n>                       # Min error count (default: 1)
  --dry-run                              # Preview only
  --force                                # Required for deletion

Fetching

rss fetch all                            # Fetch all active feeds
  -l, --limit <n>                        # Max feeds to fetch
  -f, --force                            # Ignore cache
  -c, --concurrency <n>                  # Parallel fetches (1-20, default: 5)
  --timeout <ms>                         # Request timeout (default: 30000)

rss fetch feed <id>                      # Fetch a single feed
  -f, --force                            # Ignore cache

rss fetch content [ids...]               # Fetch full article content
  -l, --limit <n>                        # Max articles (default: 50)
  --fix-broken                           # Try to repair broken URLs
  --flag-broken                          # Mark definitively missing (404/410) URLs in DB
  --no-skip-broken                       # Re-check known broken articles
  --allow-private-network                # Allow private/LAN Article destinations
  -c, --concurrency <n>                  # Parallel fetches (1-20, default: 5)

Article content fetching blocks loopback, private, link-local, reserved, and cloud metadata destinations by default, including redirects and DNS answers that mix public and non-public addresses. Use --allow-private-network only for trusted feeds that intentionally link to services on your LAN; cloud metadata destinations remain blocked. This policy applies to publisher-controlled Article URLs, not to feed subscription URLs or the explicit rss article check command. Because Bun's process-level proxy routing can override a pinned transport address, protected Article fetching fails closed when the process starts with proxy environment variables. Restart with those variables unset to fetch Article content.

Articles

rss article list                         # List articles with filtering
  -f, --feed <id>                        # Filter by feed
  -u, --feed-url <url>                   # Filter by feed URL
  -c, --category <category>              # Filter by category
  --unread / --read / --starred          # Filter by status
  --broken                               # Filter broken links
  --author <name>                        # Filter by author
  -s, --search <term>                    # Full-text search
  --today / --yesterday                  # Date presets
  --this-week / --this-month             # Date presets
  --from <date> / --to <date>            # Date range
  -l, --limit <n> / -o, --offset <n>    # Pagination
  --sort <field> --asc/--desc            # Sorting

rss article show <id>                    # Show article details
  -w, --web                              # Open in browser

rss article read <id>                    # Mark as read
  -u, --unread                           # Mark as unread

rss article star <id>                    # Star article
  -u, --unstar                           # Remove star

rss article read-all                     # Mark all as read
  -f, --feed <id>                        # Only this feed
  --older-than <date>                    # Only older articles

rss article stats                        # Article statistics

rss article check <url>                  # Check URL accessibility
  --fix                                  # Try to repair

rss article cleanup --read --force       # Remove articles by criteria
  --broken / --read                      # Filter criteria
  --older-than <date>                    # Age filter
  -f, --feed <id>                        # Scope to feed
  --dry-run                              # Preview only
  --force                                # Required for deletion

rss article remove-broken --force        # Remove definitively missing (404/410) articles
  -f, --feed <id>                        # Scope to feed
  --dry-run                              # Preview only
  --force                                # Required for deletion

Bulk cleanup commands never delete without --force; use --dry-run to preview first. For article cleanup, --feed only limits scope, so one of --broken, --read, or --older-than is also required.

Import & Export

rss import <file|url>                    # Import feeds from OPML
  -c, --category <category>              # Default category
  --dry-run                              # Preview only
  --skip-errors                          # Skip invalid feeds

rss export opml                          # Export feeds to OPML
  -o, --output <file>                    # Output file (default: stdout)
  -f, --force                            # Atomically replace an existing file

rss export json                          # Export articles to JSON
  -o, --output <file>                    # Output file (default: stdout)
  --force                                # Atomically replace an existing file
  -f, --feed <id>                        # Scope to feed
  -l, --limit <n>                        # Max articles (default: 1000)

File exports never overwrite an existing path by default. They are written and synced to a temporary file in the destination directory, then published atomically, so a failed export does not leave a partial target. Pass --force to atomically replace an existing file only after the complete replacement has been written and synced.

Database

rss db init                              # Initialize database (auto on first use)
rss db stats                             # Show feed/article counts
rss db vacuum                            # Compact database file
rss db cleanup --days <n>                # Remove old cache entries (default: 30)

Interactive TUI

rss tui                                  # Launch interactive terminal UI

| Key | Action | Key | Action | |-----|--------|-----|--------| | q | Quit | / | Search | | Tab | Next panel | ? | Help | | ↑/↓ or j/k | Navigate | Enter | Select/Open | | a | Add feed | d | Delete feed | | f | Fetch feed | F | Fetch all | | r | Toggle read | s | Toggle star | | u | Toggle unread filter | t | Cycle sort | | o | Open in browser | h/Esc | Go back | | n/p | Next/prev article | Space | Page down | | g/G | Top/bottom | R | Mark all read | | [ / ] | Resize sidebar | 1/2/3 | Layout mode |

Date Formats

| Format | Examples | |--------|---------| | ISO | 2024-01-15, 2024-01-15T10:30:00 | | Relative | today, yesterday, week, month, year, this week, this month, this year | | Expressions | 3 days ago, 2 weeks ago, 6 months ago | | Ranges | 2024-01-01..2024-06-30, 2024-01-01 to 2024-06-30 |

Smart Caching

Three-layer caching minimizes bandwidth:

  1. HTTP conditional requests -- ETag and If-Modified-Since headers. Servers return 304 Not Modified instantly.
  2. Content hashing -- MD5 of response body detects changes even without HTTP cache headers.
  3. Article deduplication -- Incoming GUIDs and canonical, fragment-free HTTP links are matched with indexed lookups and in-memory Sets, preventing duplicate inserts without loading the full Article history.

Use --force to bypass conditional requests and content-hash short-circuiting. Identity deduplication always remains active so a forced refresh cannot create duplicate Articles.

Resource Limits

Publisher-controlled input is bounded before expensive parsing and again before persistence:

| Limit | Value | |-------|-------| | Feed/OPML response | 10 MB | | Feed XML structure | 50,000 elements / 256 levels | | Feed title / description | 1,000 / 20,000 characters | | Feed category | 512 characters | | HTTP URL identities | 8,192 characters | | Article title / author / summary / content | 2,000 / 2,000 / 20,000 / 100,000 characters | | Article GUID / link | 4,096 / 8,192 characters; overlong identities are discarded or rejected, never truncated | | Article categories | 100 entries, 512 characters each, 10,000 characters aggregate | | OPML structure | 10,000 outlines / 50 levels |

Error Handling

Feeds with repeated failures are auto-deactivated:

| Error Type | Examples | Deactivation Threshold | |-----------|----------|------------------------| | Permanent | 404, 410, 403, parse failures | 3 consecutive errors | | Transient | 5xx, 429, timeouts, DNS | 5 consecutive errors |

Error count resets on successful fetch. Reactivate with rss feed update <id> --activate.

Environment Variables

| Variable | Description | |----------|-------------| | RSS_DB_PATH | Default database path (overridden by --database) | | RSS_DEBUG=1 | Include stack traces in error output (equivalent to verbose error reporting) | | RSS_ALLOW_PRIVATE_NETWORK=1 | Allow Article content requests to private/LAN destinations; metadata remains blocked |

Development

# Clone and install
git clone https://github.com/briansunter/rss-ai.git
cd rss-ai && bun install

# Run in development
bun run src/cli/index.ts <command>

# Run tests
bun test

# Lint
bun run lint

# Build standalone binary
bun run build
./rss-ai --help

# Generate migration after schema change
bun run db:generate

License

MIT