Feedr is a feature-rich terminal-based RSS feed reader written in Rust. It provides a clean, intuitive TUI interface for managing and reading RSS feeds with elegant visuals and smooth keyboard navigation.
tmlShift+F, or auto-extract on refresh per feed with fulltext = true? for a scrollable keybinding reference overlayfeedr --import <file.opml>j/k alongside arrow keys for navigationAuthorization: Bearer ...) for private/authenticated RSS feedsalways/never override in configfeedr config), or use the interactive TUI config editor (feedr config --tui)[keybindings] section in config.tomlpipe-to, exec) bound to keys, plus exec_on_new notifications fired per new item — all with shell-free argument templatingcargo install feedr
Feedr is available on the AUR. Install it using your preferred AUR helper:
paru -S feedr
yay -S feedr
git clone https://github.com/bahdotsh/feedr.git cd feedr cargo build --release
The binary will be available at target/release/feedr.
Run the application:
feedr
Import feeds from an OPML file:
feedr --import feeds.opml
View and modify settings from the command line:
feedr config list # List all settings with current values feedr config get ui.theme # Get a single value feedr config set ui.theme light # Set a value (with validation) feedr config --tui # Open interactive TUI config editor
Available config keys use dot-notation (e.g. general.max_dashboard_items, network.http_timeout, ui.theme, ui.compact_mode). Run feedr config list to see all keys. Feed management (default_feeds) is only available through the TUI editor.
a to add a feedhttps://news.ycombinator.com/rss)1, 2, or 3 to quickly add Hacker News, TechCrunch, or BBC Newsj/k) to navigate and Enter to view itemso to open the current article in your browsert to toggle between dark and light themesAll keybindings below show their defaults. You can remap any action via the [keybindings] section in your config file — see Configurable Keybindings.
| Key | Action |
|---|---|
Tab |
Cycle forward through views |
Shift+Tab |
Cycle backward through views |
q |
Go back (quit from Dashboard) |
h / Esc / Backspace |
Go back one view |
Home |
Return to Dashboard |
Ctrl+Q |
Quit from any view |
r |
Refresh all feeds |
t |
Toggle dark/light theme |
/ |
Search mode |
? |
Help overlay (scrollable keybinding reference) |
| Key | Action |
|---|---|
↑/↓ or k/j |
Navigate items |
g / G or End |
Jump to top / bottom |
Enter |
View selected item |
f |
Filter articles |
c |
Cycle category filter |
Ctrl+C |
Open category management |
a |
Add a new feed |
s |
Toggle starred |
Space |
Toggle read/unread |
m |
Mark all items as read |
p |
Toggle preview pane |
Shift+J / Shift+K |
Scroll preview down / up |
o |
Open link in browser |
1/2/3 |
Quick-add demo feeds (HN, TechCrunch, BBC) |
| Key | Action |
|---|---|
q / h / Esc |
Go to dashboard |
↑/↓ or k/j |
Navigate feeds |
Enter |
View feed items |
Space |
Expand/collapse category (tree view) |
a |
Add a new feed |
d |
Delete selected feed |
c |
Assign category to feed |
| Key | Action |
|---|---|
q / h / Esc / Backspace |
Back to feeds list |
Home |
Go to dashboard |
↑/↓ or k/j |
Navigate items |
g / G or End |
Jump to top / bottom |
Enter |
View item details |
s |
Toggle starred |
Space |
Toggle read/unread |
m |
Mark all items as read |
o |
Open item in browser |
| Key | Action |
|---|---|
q / h / Esc / Backspace |
Back to feed items |
↑/↓ or k/j |
Scroll content |
Ctrl+U / Ctrl+D |
Scroll content (page) |
Page Up / Page Down |
Scroll content (page) |
g |
Jump to top |
G / End |
Jump to bottom |
s |
Toggle starred |
o |
Open item in browser |
l |
Extract and show all links |
Shift+F |
Toggle/fetch full-text (Readability) |
| Key | Action |
|---|---|
↑/↓ or k/j |
Navigate items |
Enter |
View item details |
s |
Remove from starred |
o |
Open item in browser |
| Key | Action |
|---|---|
n |
Create new category |
e |
Rename category |
d |
Delete category |
Space |
Expand/collapse category |
Enter |
Select category |
r |
Refresh |
? |
Help |
h / Esc / q |
Back |
f on Dashboard)| Key | Action |
|---|---|
c |
Filter by category |
t |
Filter by time/age |
a |
Filter by author |
r |
Filter by read status |
s |
Filter by starred status |
l |
Filter by content length |
x |
Clear all filters |
| Action | Effect |
|---|---|
| Left click | Select item |
| Scroll up/down | Navigate items |
Feedr supports customization through a TOML configuration file that follows XDG Base Directory specifications. You can edit the file directly, use feedr config get/set from the command line, or use feedr config --tui for an interactive editor.
~/.config/feedr/config.toml%APPDATA%\feedr\config.tomlThe configuration file is automatically generated with default values on first run if it doesn't exist.
[general] max_dashboard_items = 100 # Maximum number of items shown on dashboard auto_refresh_interval = 0 # Auto-refresh interval in seconds (0 = disabled) refresh_enabled = false # Enable automatic background refresh refresh_rate_limit_delay = 2000 # Delay in milliseconds between requests to same domain
[network] http_timeout = 15 # HTTP request timeout in seconds user_agent = "Mozilla/5.0 (compatible; Feedr/1.0; +https://github.com/bahdotsh/feedr)"
[ui] tick_rate = 100 # UI update rate in milliseconds error_display_timeout = 3000 # Error message duration in milliseconds theme = "dark" # Theme: "dark" (cyberpunk) or "light" (zen) compact_mode = "auto" # Compact layout: "auto", "always", or "never"
[[default_feeds]] url = "https://example.com/feed.xml" category = "News"
[[default_feeds]] url = "https://private.example.com/feed.xml" [default_feeds.headers] Authorization = "Bearer your_token_here"
"dark" (cyberpunk aesthetic with neon colors) or "light" (zen minimalist with organic colors). Can also be toggled at runtime with t."auto" (default) enables compact mode when terminal height is ≤30 rows, "always" forces compact mode, and "never" disables it. Compact mode uses single-line items, a minimal title bar, and an abbreviated help bar to maximize screen real estate.To enable automatic refresh every 5 minutes with rate limiting:
[general] refresh_enabled = true auto_refresh_interval = 300 # 5 minutes refresh_rate_limit_delay = 2000 # 2 seconds between requests to same domain
Note: Rate limiting groups feeds by domain and staggers requests to prevent hitting API limits. For example, if you have multiple Reddit feeds, they will be fetched with a 2-second delay between each request to avoid getting blocked.
You can define feeds to be automatically loaded on first run:
[[default_feeds]] url = "https://news.ycombinator.com/rss" category = "Tech"
[[default_feeds]] url = "https://example.com/feed.xml" category = "News"
[[default_feeds]] url = "https://example.com/fast-feed.xml" refresh_interval = 60
Some RSS feeds require authentication or custom HTTP headers. You can configure per-feed headers:
[[default_feeds]] url = "https://private.example.com/feed.xml" [default_feeds.headers] Authorization = "Bearer your_api_token"
[[default_feeds]] url = "https://another-api.example.com/rss" [default_feeds.headers] X-API-Key = "your_api_key" Cookie = "session=abc123"
Headers are sent with every request for that feed, including refreshes.
Most RSS feeds ship only short summaries. Feedr can fetch the linked article URL and run Mozilla Readability (via the dom_smoothie crate) to extract the actual article body and render it inline.
Shift+F to extract the focused article. Press Shift+F again to toggle back to the original summary, or after a failure to retry.fulltext = true on a feed and Feedr will auto-extract newly-seen items on each refresh (same "no firehose" rule as exec_on_new — the first observation of a feed seeds silently).[[default_feeds]] url = "https://example.com/summary-only-feed.xml" fulltext = true
Notes:
Authorization would leak credentials).Feedr supports newsboat-style external commands for two workflows: macros (key-triggered chains that act on the focused article) and exec_on_new (a notification hook fired per newly-seen item after each refresh).
Commands are not run through a shell. Templates are tokenized once at config load, and %X placeholders are substituted into individual argv tokens — feed content can never break out of an argument. For pipes, redirection, or globbing, write a small shell script and invoke that.
Expanded in every argv token of macro and hook commands:
| Variable | Expands to |
|---|---|
%t |
Article title |
%u |
Article URL |
%a |
Author |
%d |
Formatted publish date |
%f |
Feed title |
%F |
Feed URL |
%% |
Literal % |
A macro binds a key to an ordered chain of steps. Trigger with <prefix><key> (default prefix is ,). Steps are separated by ;. An optional trailing -- "description" overrides the help-overlay label.
[macros] y = 'open-in-browser ; pipe-to "yt-dlp %u"' w = 'pipe-to "wallabag-cli add %u" -- "Save to Wallabag"' n = 'pipe-to "tee /tmp/out.txt" stdin=metadata'
[macro_options] prefix = "," # the macro-prefix key pipe_default_stdin = "body" # body | title | url | metadata | none
Step kinds:
<action> — invoke a built-in action. Supported in macros: open-in-browser, toggle-star, toggle-read, mark-all-read, refresh, toggle-theme, extract-links, fetch-full-text, help.pipe-to "cmd %u" [stdin=…] — suspend the TUI, run the command, and pipe article content to its stdin. stdin is one of body (default), title, url, metadata, or none.exec "cmd %u" — spawn the command detached (no stdin, no terminal takeover).Chains halt on the first step error. Press Esc after the prefix to cancel; an unbound follow-up surfaces a "No macro bound" error. Macros are also rendered in the help overlay (?).
exec_on_new NotificationsFire a command once per newly-seen item after each refresh. The first successful fetch of each feed seeds the seen-set silently — you do not get a firehose on initial load or first run.
[hooks] exec_on_new = 'notify-send "New: %t" "%f"'
Children are spawned detached so the TUI never blocks on them. Crash semantics are at-most-once: feedr persists the seen-set before spawning, so a kill mid-fire loses a notification rather than re-firing on the next launch. Prefer idempotent commands (e.g. wallabag-cli add is safe; mail-me is not).
%t / %a / etc. cannot escape an argument.sh -c "... %t ..." — that reintroduces shell injection through item titles. Write a script file and invoke it instead.~ / $HOME / $VAR are not expanded — use absolute paths.Remap any action by adding a [keybindings] section to your config file. Each action can be bound to a single key string or an array of keys:
[keybindings] quit = "x" # Single key move_up = ["Up", "k", "w"] # Multiple keys force_quit = "Ctrl+x" # Modifier keys toggle_theme = "F5" # Function keys
Available actions:
| Action | Default | Description |
|---|---|---|
quit |
q |
Go back / quit from Dashboard |
force_quit |
Ctrl+q |
Quit from any view |
back |
h, Esc, Backspace |
Go back one view |
home |
Home |
Return to Dashboard |
toggle_theme |
t |
Switch dark/light theme |
refresh |
r |
Refresh all feeds |
help |
? |
Show help overlay |
open_search |
/ |
Enter search mode |
move_up |
Up, k |
Navigate up |
move_down |
Down, j |
Navigate down |
page_up |
PageUp, Ctrl+u |
Page up |
page_down |
PageDown, Ctrl+d |
Page down |
jump_top |
g |
Jump to top |
jump_bottom |
G, End |
Jump to bottom |
select |
Enter |
Select / open |
add_feed |
a |
Add new feed |
delete_feed |
d |
Delete selected feed |
toggle_read |
Space |
Toggle read/unread |
toggle_star |
s |
Toggle starred |
mark_all_read |
m |
Mark all items as read |
open_in_browser |
o |
Open in browser |
toggle_preview |
p |
Toggle preview pane |
open_filter |
f |
Open filter mode |
cycle_category |
c |
Cycle category filter |
open_category_management |
Ctrl+c |
Category management |
assign_category |
c |
Assign category to feed |
extract_links |
l |
Extract links from article |
fetch_full_text |
Shift+F |
Toggle/fetch full-text (Readability) |
scroll_preview_up |
Shift+K, Shift+Up |
Scroll preview up |
scroll_preview_down |
Shift+J, Shift+Down |
Scroll preview down |
toggle_expand |
Space |
Expand/collapse in tree view |
next_tab |
Tab |
Next view |
prev_tab |
Shift+Tab |
Previous view |
Supported key formats: Single characters (q, ?, /), special keys (Enter, Space, Tab, Esc, Backspace, Up, Down, Left, Right, Home, End, PageUp, PageDown, Delete, F1–F5), and modifier combos (Ctrl+q, Shift+Tab, Alt+x).
Feedr stores your bookmarks, categories, read/unread state, and starred articles in:
~/.local/share/feedr/feedr_data.json%LOCALAPPDATA%\feedr\feedr_data.jsonFeedr automatically migrates data from older versions to the new XDG-compliant locations. Your existing data will be preserved and automatically moved to the correct location on first run.
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)