A terminal RSS reader built with Bubble Tea and Lipgloss.
The reusable themed UI toolkit derived from Tide is available as
tideui.
Feeds refresh on their own. Every 30 minutes by default — Settings → Feeds
→ Refresh every (minutes), or feed.refresh_interval_minutes; 0 turns it off
and goes back to f / F only. Fetches run through a queue capped at four at a
time, so a large library no longer opens a socket per feed the moment Tide
starts, and each feed's own last-fetched time decides when it is due — restarting
does not re-fetch what was just refreshed.
Articles can expire. Settings → Feeds → Delete read after (days)
(feed.retention_days) drops read articles once they pass that age, and the
Feeds section shows how much the database currently holds. It is off by
default — an upgrade will not quietly delete a library you already have — and
even when on it never touches starred articles, articles with a saved AI
summary, or anything still unread.
Vim-style selection in the content pane. v selects character-wise and V
line-wise, both anchored where the cursor is; h/l move by character, j/k
by line, the other visual key switches mode, and the same key again — or esc —
cancels. c / y copies the selection, or the whole article when nothing is
selected. L copies the article's link from either the list or the content pane.
Panes have borders. Each pane is drawn in its own frame, square or rounded,
and the frame follows focus. Turn it off in Settings → Display
(display.show_pane_borders) to go back to plain divider lines and hand every
pane two more rows of content; display.pane_corners picks square or round.
The selected article is arrow-marked. The article list marks its cursor with
→ in place of the read/unread dot, the way the feeds pane already did, so the
selection stays readable in an unfocused pane.
Settings keeps your place. Saving settings used to drop the sidebar back on
Saved and the article list back at the top. It now returns to the feed, article
and scroll position you left, and no longer resets a live u unread-only toggle
unless you changed that setting yourself.
Earlier: pane header bars are toggleable in Settings → Display
(display.show_pane_headers); when hidden, the focused pane's title and
shortcuts move to the status bar. After a successful in-app update Tide keeps the
completion modal open and can restart cleanly into the installed binary — press
Enter to restart, Esc to restart later.
- Three-pane layout: feeds, articles, content, with optional per-pane borders (Settings → Display)
- Cursor markers in both list panes: the selected feed and the selected article are arrow-marked, so the cursor stays readable in an unfocused pane
- Status bar reminders: feed manager, settings, search, and help keys (
m·S·/·?) - Comfortable or compact list spacing (Settings → Display; configurable in
config.toml) - Live theme switching with full preview
- Theme-aware dialogs and overlays
- Feed manager: add, edit, delete, import/export OPML
- Google Reader-compatible source support, including FreshRSS
- Background refresh on a configurable interval, with fetches queued rather than fired all at once
- Optional retention: expire read articles after N days, never touching starred, summarized or unread ones
- Full-text search across stored local articles, including titles, content, and AI summaries
- Vim-style visual selection in the content pane (
vcharacter-wise,Vline-wise) with copy to clipboard (c/y), plusLto copy an article's link - Unread-only filtering and in-article find
- Mark read/unread, open in browser
- Optional actionable links in content pane (Settings → Display)
- Optional article images in the content pane (Kitty graphics; Settings → Display; off by default) — text wraps beside the image,
itoggles per article, clean text-only fallback everywhere else - AI summaries with copy and save-to-Markdown actions
- 19 built-in themes, including customizable VT52 and VT100 palettes, plus
match-omarchywhich follows your current Omarchy desktop theme (contrast-corrected, updates live) - Terminal background sync (OSC 11)
catppuccin-mochacatppuccin-lattecatppuccin-frappecatppuccin-macchiatonorddraculagruvbox-darkgruvbox-lighttokyo-nighttokyo-night-dayrose-pinerose-pine-moonrose-pine-dawnone-darkmagenta-geodecoral-sunsetlavender-fields-forevervt100vt52match-omarchy— follows the current Omarchy desktop theme, remapped and contrast-corrected to the same readability bar as the built-ins. Works for light and dark Omarchy themes and repaints within a couple of seconds when you switch your desktop theme. Falls back tocatppuccin-mochawhen Omarchy isn't installed.
curl -fsSL https://raw.githubusercontent.com/allisonhere/tide/main/install.sh | shInstalls to ~/.local/bin — no sudo, and in-app updates land there too, so you
never need a password again. Make sure ~/.local/bin is on your PATH. To
install system-wide instead:
INSTALL_DIR=/usr/local/bin curl -fsSL https://raw.githubusercontent.com/allisonhere/tide/main/install.sh | sh(with a system-wide install, in-app updates fall back to a manual sudo command.)
Upgrading from an older install that put tide in /usr/local/bin: re-run
the installer above (or take an in-app update). It installs to ~/.local/bin and
prints a one-time sudo rm -f /usr/local/bin/tide to clear the old copy — after
that, no more prompts.
Or build from source:
git clone https://github.com/allisonhere/tide
cd tide
go build -o tide .tideConfig and database are stored in ~/.config/rss/.
If you have no feeds yet, use a (add) or m (feed manager) to subscribe. Enter does not open the add dialog on an empty feed list.
The bottom status line always shows m feed manager, S settings, / search, and ? help on the left (alongside feed status). That matches the shortcuts documented in ? help.
Open the feed manager with m. Tide keeps one shared manager flow for local feeds and Google Reader-compatible sources.
- Press
ato open the add dialog from the main screen - Opening the manager with
mstarts on the left list/details pane - From a text field,
←moves back to the left pane once the cursor is already at the start of the field - The
Sourcetoggle in the add form switches betweenLocalandGReader
Local source:
- Feed names come from the feed metadata. Add/edit only asks for
URL, folder, and optional new-folder color.
GReader source (FreshRSS, etc.):
- Feed names come from the server: the add form explains that the name is taken from the feed when you subscribe (no separate rename field). Article and feed titles are shown with HTML entities decoded (for example apostrophes), including in the sidebar.
- Fields: optional feed
URL,API URL,Login,Password - If
URLis blank, Tide saves the connection and loads your existing remote subscriptions - If
URLis set, Tide quick-adds that subscription on the remote server - Press
eon a remote feed to edit GReader connection settings (credentials and read-only name/URL summary). Saving applies API credentials and keeps labels aligned with the remote feed - Folder placement for remote feeds is not changed from that screen; existing folder prefs stay in Tide’s database
- Selecting a remote feed in the manager shows connection info on the right, with the password masked
FreshRSS works through its Google Reader-compatible endpoint. Use the full API URL, for example:
https://example.com/FreshRSS/p/api/greader.php
Saved Google Reader credentials are stored in ~/.config/rss/config.toml under [source]. Treat this file like a secret (it can contain passwords and API keys). Local folder assignments and remote-feed prefs are stored in Tide’s SQLite database.
Open settings with S.
The settings overlay uses a category list on the left and a focused detail pane on the right. Current categories are DISPLAY, FEEDS, UPDATES, AI, and ABOUT.
Display options:
- Toggle Unicode icons for pane headers and item state markers
- Toggle pane header bars; when hidden, the focused pane's title and shortcuts move to the status line
- Toggle pane borders, and pick square or rounded corners for the frames
- Switch between relative and absolute dates
- Toggle mark-read-on-open
- Toggle mark-read-on-focus
- Toggle the content focus line
- Start feeds in unread-only mode
- Select any built-in theme, with custom background, foreground, and accent colors for VT52/VT100
- Set the article reading width (
0means no limit) - Toggle actionable article links (shows a
LINKSblock in content pane) - Filter links out of article body text
- Toggle article images (renders the lead image at the top of the content pane on Kitty-capable terminals; default off)
- Layout density: comfortable (extra vertical spacing in lists) or compact (default; more rows on small terminals)
- Set a custom browser command
- Toggle the quit confirmation
Feed options:
- Refresh every (minutes): how often feeds re-fetch in the background.
0disables it, leaving the startup fetch andf/F. Fetching is queued at four feeds at a time, and each feed's stored last-fetched time decides when it is due, so feeds spread themselves across the interval instead of moving in lockstep - Delete read after (days): retention.
0keeps everything (the default). Starred articles, articles with a saved AI summary, and unread articles are never deleted at any age, and neither are articles a feed served without a publication date - Shows the current article count and database size, so the cost of keeping everything is visible next to the setting that changes it
- Set the maximum feed body size accepted during parsing
Update options:
- Toggle startup update checks
- Check for the latest Tide release manually
- Install the latest release: in place when the binary's directory is writable,
otherwise migrated to
~/.local/bin/tide - Shows download/install progress, then asks whether to restart Tide; Enter restarts cleanly, while Esc leaves the updated app ready to restart later
- After a migrating install, shows a one-time
sudo rm -f ...for any older copy still earlier onPATH - If neither location is writable, shows the exact
sudo install ...command
AI summary options:
- Provider:
none,OpenAI,Claude,Gemini, orOllama - API key for OpenAI, Claude, or Gemini
- Ollama URL and model for local summaries
- Test the configured provider connection
- Save path for exported Markdown summaries
- Optionally mark an article read after summarizing it
About:
- Open the Tide repository and issues page from inside Settings
- Includes a small signed note and project tagline
Settings are saved to ~/.config/rss/config.toml.
Tide can render an article's lead image at the top of the Content pane. It is off by default and text stays first-class:
- Enable it under
Settings → Display → Article images, or setarticle_images = truein the[display]block ofconfig.toml. - It uses the Kitty graphics protocol. Supported terminals: Kitty, Ghostty, WezTerm, and Konsole 22.04+. On any other terminal the setting is inert — articles render exactly as before, with no error and no placeholder.
- The image is chosen from the feed metadata (Media RSS
media:content/media:thumbnail, an imageenclosure, the item<image>), falling back to the first meaningful<img>in the article HTML. Tracking pixels, spacers, avatars, icons and logos are skipped. - It is fetched lazily the first time you open the article, cached on disk under
~/.cache/rss/images/, and capped at roughly 8–12 rows. - On a wide enough reading column the image floats at the top-left and the first lines of the article wrap to its right, magazine style. On a narrow column it falls back to a full-width image with the text below it.
- The image is part of the top of the article: scroll past it and it hides (the text reflows to full width); scroll back to the top and it returns. It is also cleared automatically on resize, overlays (Settings/help/search/feed manager), theme changes, article changes and quit.
- Press
i(focus in the Content pane) to hide/show the image for the current article without changing the global setting.
Terminal detection runs once at startup. If you enable the setting while running in a terminal that does not advertise Kitty support in its environment, restart Tide to activate it.
Troubleshooting. Run go run ./cmd/imgcheck [feed-url] to exercise each stage
(terminal detection, image extraction, download, decode, resize, and a real draw) in
isolation. Set TIDE_IMAGE_DEBUG=/path/to/log before launching Tide to log the image
lifecycle (detection result, fetch outcome, and every placement).
Tide can summarize the currently selected article when focus is in the Articles or Content pane.
- Press
sto open an AI summary for the selected article - Press
cin the summary dialog to copy the summary - Press
Min the summary dialog to save it as.md - If AI is not configured, Tide shows a prompt to open Settings with
S
Supported providers and current built-in models:
- OpenAI
Uses
gpt-4o-mini - Claude
Uses
claude-haiku-4-5-20251001 - Gemini
Uses
gemini-1.5-flash - Ollama
Uses your configured local model, default
llama3.2
Provider requirements:
- OpenAI: set an OpenAI API key
- Claude: set an Anthropic API key
- Gemini: set a Google AI Studio API key
- Ollama: run a local Ollama server and choose a model
Summary behavior:
- Tide sends the article title and up to the first 4000 characters of article content
- The app asks the provider for a concise 3-5 sentence summary
- Requests use a 30 second timeout
- Generated summaries are cached per article and can be reopened without regenerating them
- Saved summaries are written as Markdown files to your configured save path
Default Ollama settings:
- URL:
http://localhost:11434 - Model:
llama3.2
Example config.toml:
theme = "catppuccin-mocha"
[display]
icons = false
show_pane_headers = true
show_pane_borders = true
pane_corners = "square" # or "round"
date_format = "relative"
mark_read_on_open = true
mark_read_on_focus = false
focus_line = true
default_unread_only = false
actionable_links = false
filter_links = false
article_images = false
reading_width = 0
feed_pane_width_percent = 28
article_pane_height_percent = 40
confirm_quit = true
browser = ""
density = "compact"
[feed]
max_body_mib = 10
refresh_interval_minutes = 30 # 0 disables the background refresh
retention_days = 0 # 0 keeps every article forever
[ai]
provider = "ollama" # openai | claude | gemini | ollama | ""
openai_key = ""
claude_key = ""
gemini_key = ""
ollama_url = "http://localhost:11434"
ollama_model = "llama3.2"
save_path = "~/"
mark_read_on_summarize = false
[source]
greader_url = ""
greader_login = ""
greader_password = ""Feed fetch limits:
feed.max_body_mibcontrols the maximum feed response size accepted for parsing- Default is
10 - If a feed exceeds this limit, Tide returns a clear “feed is too large to parse” error instead of a misleading XML syntax error
Tide can check GitHub releases for a newer version and install the matching binary for your platform.
- Startup checks are enabled by default and run at most once every 24 hours
- Manual checks and installs live in the
UPDATESsection of Settings (S) - Tide never downloads or installs an update until you explicitly choose
Update now - While the download and install run, the update overlay shows a progress bar
- After a successful install, Tide keeps the update modal open and asks whether to restart now; Enter restarts after terminal cleanup, while Esc lets you restart later
- Updates replace the binary in place. If its directory is not writable, Tide
migrates the install to
~/.local/bin/tideinstead — nosudo. When an older copy is still earlier on yourPATH, Settings shows a one-timesudo rm -f ...to remove it - Only if neither location is writable does Tide fall back to a manual
sudo install ...command instead of failing silently
Maintainers can prepare and publish a release with the deployment TUI:
./release.shThe TUI:
- Detects the latest semantic-version tag and offers patch, minor, or major bumps
- Shows every worktree change before staging it
- Requires a second release confirmation before making remote changes
- Checks that Git author name and email are configured before doing any release work
- Runs the complete Go test suite and checks the patch for whitespace errors
- Fetches
origin/main, refuses to release from another branch, and stops if localmainis behind - Stages all worktree changes, creates the chosen release commit when needed, and pushes
main - Creates and pushes an annotated version tag
Pushing the tag starts the GitHub Actions release workflow. CI tests again, builds Linux and macOS archives for x86-64 and ARM64, publishes SHA-256 checksums, generates release notes, and creates the GitHub release. The installer verifies those checksums when they are available. If the final tag push fails after the local tag was created, the TUI prints the exact command needed to resume safely.
| Key | Action |
|---|---|
Tab / ], Shift-Tab / [ |
Cycle panes forward or backward |
h/← l/→ |
Move between panes |
j/↓ k/↑ |
Navigate within pane |
Shift+← / Shift+→ |
Resize feed pane |
Shift+↑ / Shift+↓ |
Resize articles/content split |
Enter |
Open article |
Esc |
Back |
| Key | Action |
|---|---|
r |
Toggle read/unread |
R |
Mark the selected feed or folder read |
* / b |
Star article (save for later) |
u |
Toggle unread-only view |
o |
Open selected content link (when enabled) or article URL |
Ctrl+N / Alt+N |
Next actionable link in content pane |
Ctrl+P / Alt+P |
Previous actionable link in content pane |
Ctrl+F |
Find text in the current article; Enter/↓ selects the next match and ↑ the previous match |
i |
Show/hide the lead image for the current article (only when Article images is on and the focus is in the Content pane) |
/ |
Search titles, content, and summaries across all stored local articles |
v |
Character-wise selection in the content pane |
V |
Line-wise selection in the content pane |
c / y |
Copy the selection, or the whole article when nothing is selected |
L |
Copy the article's link |
Search results are ranked by relevance and include their source feed and a matching excerpt. Press Enter to jump to a result. Google Reader-compatible articles are loaded from the remote service rather than stored locally, so they are not included in library search.
The content pane has vim-style visual selection. v starts a character-wise
selection and V a line-wise one, both anchored where the cursor is:
| Key | Action |
|---|---|
h / l |
Move the cursor by character |
j / k |
Move the cursor by line |
v / V |
Switch between character-wise and line-wise, keeping the anchor |
v / V again, or Esc |
Cancel the selection |
c / y |
Copy the selection |
The cursor only exists while a selection is open — at any other time h/l go
on switching panes. During a selection j/k move a line at a time rather than
hopping between readable lines, and the column is sticky in vim's sense: drop
onto a short line and back off it and the cursor returns to where h/l put it.
With nothing selected, c / y copies the whole article, so the common case
does not need visual mode. Line-wise copies arrive flush — the pane's left indent
is layout rather than article text, so it is stripped, while indentation the
article meant keeps its shape. Character-wise copies exactly the characters
covered.
L copies the current article's link, and works in the article list as well as
the content pane.
Starring is separate from read state, so an article stays starred after you have
read it. Press * or b on any article to toggle it; starred articles show a ★
in a dedicated column between the read marker and the title.
★ Saved is a virtual feed pinned to the top of the sidebar. It collects every starred article across all feeds, newest first, with a badge showing the total.
In search, the is:starred filter limits results to starred articles:
| Query | Result |
|---|---|
is:starred |
Browse everything starred |
rust is:starred |
Starred articles matching "rust" |
is:saved and is:star are accepted as aliases. The filter can appear anywhere
in the query and combines with the unread-only toggle.
Note that "star" is the action and Saved is the place it puts things — "save" on its own is reserved elsewhere in Tide for writing an edit (saving a feed, a folder, or settings).
Starring requires a locally stored article. Google Reader feeds are fetched live and never persisted, so starring a remote article is refused rather than silently lost. Starred articles are never pruned, but deleting a feed removes its articles, starred ones included.
When Display → Focus line is enabled, the content pane highlights the current readable line. j/↓ and k/↑ move the focus line and scroll only when needed.
When Display → Actionable article links is enabled, the content pane renders a LINKS block at the bottom. The currently selected link is highlighted and opened with o.
| Key | Action |
|---|---|
s |
AI summary for selected article when focus is in Articles or Content |
c |
Copy summary in summary dialog |
M |
Save summary as .md in summary dialog |
| Key | Action |
|---|---|
f |
Refresh the selected feed |
F / I |
Refresh every feed, due or not |
m |
Feed manager |
a |
Add a feed or GReader source from anywhere |
Feeds also refresh on their own; see Settings → Feeds → Refresh every
(minutes). Manual and background fetches share one queue, capped at four at a
time, so pressing F during a background refresh cannot stack duplicate fetches
for the same feed.
| Key | Action |
|---|---|
a |
Add feed or GReader source |
n |
Add folder |
Enter |
Browse selected remote feed, edit selected local feed, or enter the form from the left pane |
e |
Edit selected local feed or GReader settings |
v |
Move the selected feed to a folder |
d |
Delete selected local feed |
i |
Import OPML |
x |
Export OPML |
| Key | Action |
|---|---|
T |
Theme picker |
S |
Settings |
/ |
Search stored local articles across all feeds |
? |
Help |
q |
Quit |
The same m, S, /, and ? shortcuts are repeated on the status bar (bottom line) whenever the main reader is visible.

