Hacker News TUI
A fast, delightful terminal UI for browsing Hacker News, built with Ratatui.

Features
- Six feeds — Top, New, Best, Ask, Show, and Jobs, switchable instantly.
- Infinite scroll — the next batch of stories loads about a screen ahead of you, so you can keep reading without paging. The Top feed marks the end of the front page (its first 30 stories), a natural place to stop.
- Bookmarks — save stories with
sand revisit them in the★ Savedview (b); saved stories are marked with a star in every list. - In-app settings pane (
,) — opt in to remembering read-state and bookmarks across runs. Both are off by default: nothing is written to disk unless you turn it on. - Threaded comments with colored depth guides, collapsible subtrees, and an
OPbadge so you can follow the original poster.J/Kskip between top-level threads, and text is kept to a comfortable reading width. Quotes, code blocks, italics and links keep their formatting. - Async, non-blocking UI — stories and whole comment trees are fetched concurrently in the background while the interface stays responsive, with a live loading spinner.
- Read-state tracking — visited stories dim so you can see where you've been.
- Open in browser — jump to the article or the HN discussion with one key.
- Smart HTML rendering — HN's markup and entities are cleaned into readable, word-wrapped text.
Running
The first build compiles dependencies; subsequent runs are instant.
Installing
Homebrew (macOS / Linux):
Scoop (Windows):
scoop bucket add danfry1 https://github.com/danfry1/scoop-bucket
scoop install hacker-news-tui
Nix (flakes):
Cargo — from crates.io:
Or grab a prebuilt binary from the Releases page — each tagged release ships archives (with SHA-256 checksums) for:
- Linux:
x86_64andaarch64 - macOS:
aarch64(Apple Silicon) - Windows:
x86_64
Intel Macs aren't shipped as a prebuilt binary; install with
cargo install hacker-news-tui instead.
The installed command is hacker-news-tui. For something shorter, add an alias
to your shell config (~/.zshrc, ~/.bashrc, …):
Maintainers: see RELEASING.md for cutting a release, including publishing the Homebrew bottles.
Keyboard shortcuts
Stories
| Key | Action |
|---|---|
j / k, ↑ / ↓ |
Move selection |
g / G |
Jump to top / bottom |
: + number |
Jump to that story (e.g. :10 then enter); loads further stories if needed |
/ + text |
Search loaded titles and domains, moving as you type |
n / N |
Next / previous search match (wraps around) |
enter |
Open comments |
o |
Open the article in your browser |
O |
Open the Hacker News discussion page in your browser |
s |
Bookmark / unbookmark the story |
b |
View bookmarks (★ Saved) |
1–6, tab / shift+tab |
Switch feed |
r |
Refresh |
, |
Settings |
? |
Help |
q |
Quit |
Comments
| Key | Action |
|---|---|
j / k, ↑ / ↓ |
Move selection |
J / K |
Next / previous top-level thread, skipping the current conversation |
p |
Parent comment |
space / enter |
Collapse / expand a thread |
/ + text, n / N |
Search comment text and authors; next / previous match |
o / O |
Open the article / the HN discussion page |
u |
Open a link from the selected comment (press again for the next one) |
s |
Bookmark / unbookmark |
esc / h / ← |
Back |
Settings (,) & Bookmarks (b)
In the settings pane, j/k move, space/enter toggle, ,/esc close.
Mouse support (wheel scrolling; click a story to select it, click again to open
its comments) is off by default and can be enabled there. Capturing the mouse
takes over the terminal's own click-and-drag text selection; most terminals
bypass it while a modifier (usually shift) is held.
In the bookmarks view, enter opens comments, o opens the article, s
removes a bookmark, and b/esc returns to the feed. : jumps and /
searches there too.
In the : and / prompts, enter confirms, esc cancels (restoring the
previous selection), and an empty / search clears the highlighting.
Colours
The interface is designed for 24-bit colour. On terminals without it, such as
macOS Terminal.app, colours are mapped to the nearest of the standard 256. The
app follows NO_COLOR: when it is set, colours are
dropped and the selection and search matches are shown in reverse video. To
override detection, set HN_TUI_COLOR to truecolor, 256, or none.
Choosing a browser
o opens links in a browser of your choice — including a terminal one. Set
HN_TUI_BROWSER to a command (arguments are allowed):
# text browser
HN_TUI_BROWSER only affects this app, so you can export it in your shell
profile (~/.zshrc, ~/.bashrc, …) without changing your system default
browser. The standard $BROWSER variable is also honored as a fallback, and
when neither is set, links open in your OS default browser as before.
Persistence & privacy
Read-state and bookmarks can be remembered across runs, but only when you
enable them in the settings pane (,). Both are off by default, so a fresh
install writes nothing to disk; disabling them again removes the file entirely.
When enabled, state lives in a single JSON file:
| Platform | Location |
|---|---|
| macOS | ~/Library/Application Support/hacker-news-tui/state.json |
| Linux | $XDG_DATA_HOME/hacker-news-tui/state.json (or ~/.local/share/…) |
| Windows | %APPDATA%\hacker-news-tui\state.json |
Delete that file to clear everything. All file operations are best-effort and fail silently — losing local UI state never interrupts browsing.
Supply-chain security
This project is built with a deliberately small, auditable dependency surface:
Cargo.lockis committed, pinning every transitive crate to an exact version and checksum for reproducible builds.- Pure-Rust TLS via
rustls— no linkage to a system OpenSSL. Root certificates come from the OS trust store, so the app works behind corporate proxies that present a privately-issued root CA. - No avoidable dependencies — browser opening and HTML decoding are a few
lines of
stdinsrc/util.rsrather than extra crates.
To audit the locked dependency tree for known advisories:
Architecture
| File | Responsibility |
|---|---|
src/main.rs |
Terminal setup and the async event loop (input · fetch results · tick) |
src/api.rs |
Hacker News API clients (Firebase, Algolia) and data types |
src/app.rs |
Application state, input handling, async orchestration |
src/app/tests.rs |
State-machine tests for App, driven without I/O |
src/color.rs |
Adapts rendered frames to 256-colour or NO_COLOR terminals |
src/ui.rs |
All rendering — pure functions of the app state |
src/store.rs |
Best-effort persistence of settings, read-state, bookmarks |
src/util.rs |
Time/URL/HTML/wrapping helpers (unit-tested) |
Development
A justfile wraps the common tasks (or run the
underlying cargo commands directly):
GitHub Actions (.github/workflows/ci.yml) runs formatting, Clippy (warnings as
errors), the test suite, and cargo audit on every push and pull request.
Data source
Feeds and stories come from the official Hacker News API. Comment threads come from Algolia's HN Search API, which returns a whole thread in one request, so even very long discussions load in full. Comments too new for Algolia's index are filled in from the official API, and if Algolia can't be reached the thread is loaded from the official API alone (limited to the first 250 comments). Neither needs an API key.