A lightweight, local-first RSS/Atom reader for Windows, macOS, Linux, Android and the web. No account, no backend, no telemetry: subscriptions, read/starred state, rules, preferences and cached articles stay on your device. Built with React and Tauri, inspired by Fluent Reader.
Windows desktop (64-bit): download the latest installer from Releases.
- Requires Windows 10/11 with WebView2.
- The installer is unsigned for now: SmartScreen → More info → Run anyway.
- Installing over a previous version keeps feeds, read state, stars, rules and cache.
macOS (Apple Silicon): download the .dmg from Releases. It is unsigned, so
right-click the app → Open the first time (or allow it in System Settings → Privacy &
Security).
Linux: download the .AppImage, make it executable (chmod +x RSS.Reader_*.AppImage)
and run it. It needs the distribution's WebKitGTK 4.1/GTK libraries (standard on Ubuntu 22.04+).
Android: download the .apk from Releases (Android 8+, arm64), allow installs from
your browser/file manager and open it. The current APK is debug-signed for testing;
a Play Store / stable signing key is not configured yet.
Web / PWA: build the app and install it from Chrome or Edge:
npm install
npm run build
npm run preview # http://localhost:4173 → Install appThe installed PWA opens offline but needs the local preview/proxy server for feed refreshes. The desktop app fetches natively and needs no Node process at runtime.
Each GitHub release includes SHA256SUMS.txt. After downloading an asset:
sha256sum -c SHA256SUMS.txtOn Windows PowerShell, use Get-FileHash and compare the SHA-256 value with the
matching line. Builds are currently unsigned on Windows/macOS and the Android APK
uses the development key; see docs/SIGNING.md for what is needed
to add Authenticode, Apple notarization or Play Store signing.
About → Check for updates queries the latest GitHub release and offers the installer or APK for the current platform. Running it replaces the installed version; there is no need to uninstall first. Silent in-app installation is not enabled because it needs a Tauri updater signing key stored as a CI secret; the current build uses the simple download-and-install path.
- Four layouts — cards, list, magazine and compact. List keeps the article pane beside the rows; magazine and card open the reader as a blurred popup.
- Filters and search — all/unread/starred, plus case-sensitive, full-text and regular-expression options attached to the search field.
- Stars and rules — keep articles, or automatically mark/star new arrivals with contains or regex rules scoped to a source or group.
- Reader tools — copy link, load the original full article text (cached for the session) and play podcast audio at 0.75–2× speed.
- Local backups — OPML plus a compressed ZIP backup (JSON inside) with subscriptions,
folders, read state, stars, rules, preferences and every cached article. Plain JSON
backups remain importable. Desktop keeps seven daily snapshots, gzip-compressed
(
.json.gz) and still readable from older plain-JSON files. - Media — YouTube, Vimeo, Spotify, SoundCloud, Deezer and Apple Podcasts play inline without API keys.
- Desktop extras — tray icon, close-to-tray, background refresh, native notifications and start-at-login.
- English and Spanish — the whole interface follows the system language, or pick one in Settings → Preferences → Language. A missing translation falls back to English.
Sources and groups. Subscribe by feed URL or website; the feed link is discovered automatically. Organize with A–Z folders/groups, resize the sidebar, collapse all, and bulk-select sources or groups in Settings for move/merge/delete. Sources includes an import action when the device has no subscriptions yet. Feed failures back off from 5 minutes to 6 hours; manual refresh retries immediately. ETag/Last-Modified validators keep unchanged feeds on a 304.
Telegram and Reddit. Subscribed t.me/<channel> sources are read from the public
channel preview page and converted into articles; up to three older preview pages are
fetched so a quiet channel still has a useful history. Reddit retired its public RSS
feeds in November 2026. Subscribed
reddit.com/r/<sub> sources are read through the public Arctic Shift archive and
mapped into normal articles; the legacy RSS URL is still used as a fallback while it
exists. Reddit posts also open in an inline card in the reader.
Reading. Card, list, magazine and compact layouts. Automatic feed refresh is off by default; choose 15 min, 30 min, 1 hour or 3 hours in Preferences, or refresh manually whenever you want. Wide windows use two panes for list/compact; magazine and card use an overlay with previous/next arrows. Article HTML is sanitized, relative URLs are resolved, and external links open safely in a new tab. Mark as read works per article, all visible, or older than 1/3/7 days.
Language. The interface ships in English and Spanish with a system default. Every
label, dialog, toast and error message goes through the same tiny catalog, so new strings
fall back to English instead of breaking the UI.
Settings. Six sections: Preferences, Manage, Rules, Services, Data and About. Theme, density, reading typeface (sans, serif, mono) and font size live in Preferences. Manage holds the Sources and Groups tabs. Data owns import/export, backups and the local cache. Services includes a sync-provider selector (Fever, Feedbin, Inoreader, Miniflux, Nextcloud News, NewsBlur) and the optional YouTube API key. Server and username are stored locally; the password/token is session-only. Two-way sync remains future work — use OPML or a full backup today. The feed context menu can edit a source's name, group and feed link in one dialog; changing the link resets that source's cached articles and read state.
Privacy. No sync service, account or telemetry. Everything is stored in
localStorage and IndexedDB on this device. The web/PWA build only contacts feeds and
the configured proxy; the desktop build fetches feeds from Rust with HTTPS-first,
SSRF/private-host blocking and a 5 MB response cap.
| Key | Action |
|---|---|
j / k or ↓ / ↑ |
Move through articles |
← / → |
Previous / next article |
Enter / o |
Open the selected article |
m |
Toggle read/unread |
r |
Refresh all feeds |
/ |
Focus search |
a |
Add feed |
Esc |
Close article, drawer or dialog |
Alt+← / Alt+→ |
Back / forward through views |
Requirements: Node 20+; Rust and WebView2 for the desktop build.
npm install
npm start # build if stale, serve :4173 and open the app
npm run dev # http://localhost:5173 with hot reload
npm run build # production bundle in dist/
npm run preview # serve dist/ with the local feed proxy
npm run test:unit # Vitest
npm run test:e2e # Playwright smoke suite (needs npm run dev running)
npm run test:pwa # installability + offline check (needs npm run preview)
npm run check # typecheck + unit tests + Rust fmt/clippy/tests
npm run desktop:dev # Tauri dev window
npm run desktop:build # native bundle → src-tauri/target/release/bundle/
# Per-platform bundles:
npm run desktop:build -- --bundles nsis # Windows installer
npm run desktop:build -- --bundles appimage # Linux AppImage
npm run desktop:build -- --bundles dmg # macOS disk image
npm run android:build # Android APK (needs Android SDK/NDK)CI runs the web suite on Ubuntu and the Rust checks plus Windows installer build on
Windows. See .github/workflows/ci.yml. The release
process is documented in docs/RELEASING.md.
- Storage:
localStoragefor preferences, subscriptions, read/starred IDs and rules; IndexedDB for cached articles, with a quota guard that evicts cache before state. - Fetching: the web build tries a direct fetch, then the local
/proxy(orVITE_PROXY_URL), then public proxies as a last resort. The desktop build makes one native Rust request with validators and retry backoff. - Security: feed HTML crosses a DOMPurify allow-list boundary with relative-URL resolution and forced safe external links. The proxy and desktop fetcher enforce HTTPS-first, block private/loopback hosts and cap responses.
- Offline shell: a production service worker precaches the app shell; feed responses
and
/proxyare never cached.
Key folders:
src/components/ UI, settings managers and dialogs
src/lib/ fetching, parsing, sanitization, backups, rules, storage
src/store/ framework-agnostic app store and selectors
src-tauri/ Tauri shell, native fetch, tray and snapshots
server/ shared local feed proxy
- State is per device. Use the full ZIP backup to move it.
- The Spanish catalog is hand-written; native-speaker review is welcome.
- Feed refresh is manual by default; Settings → Preferences can enable 15 min, 30 min, 1 hour or 3 hours while the window is visible.
- Below 1100 px the article view becomes single-pane and the sidebar becomes a compressed left-side drawer.
- The Windows installer and macOS disk image are unsigned; macOS needs a first-run right-click → Open. The Android APK is debug-signed.
- Android file import/export uses the WebView download flow; the desktop save dialog and daily snapshots remain desktop-only.
- The Android APK is arm64 debug-signed with a committed keystore so updates install over earlier builds; Play Store signing is not configured.
- Services has a sync-provider selector, but two-way sync is not implemented yet; the server and username are stored locally (the password/token is session-only) and excluded from backups.
- “Load full content” depends on the page structure and on the proxy being reachable.
MIT. See LICENSE.