hacker-news-tui 0.3.0

A delightful terminal UI for browsing Hacker News
hacker-news-tui-0.3.0 is not a library.

Hacker News TUI

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

hacker-news-tui demo

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 s and revisit them in the ★ Saved view (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 OP badge so you can follow the original poster. J / K skip 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

cargo run --release

The first build compiles dependencies; subsequent runs are instant.

Installing

Homebrew (macOS / Linux):

brew install danfry1/tap/hacker-news-tui

Scoop (Windows):

scoop bucket add danfry1 https://github.com/danfry1/scoop-bucket
scoop install hacker-news-tui

Nix (flakes):

nix run github:danfry1/hacker-news-tui          # run without installing
nix profile install github:danfry1/hacker-news-tui

Cargo — from crates.io:

cargo install hacker-news-tui

Or grab a prebuilt binary from the Releases page — each tagged release ships archives (with SHA-256 checksums) for:

  • Linux: x86_64 and aarch64
  • 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, …):

alias hnt='hacker-news-tui'

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):

export HN_TUI_BROWSER=lynx                   # text browser
export HN_TUI_BROWSER='firefox --new-window'

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.lock is 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 std in src/util.rs rather than extra crates.

To audit the locked dependency tree for known advisories:

cargo install cargo-audit   # one-time
cargo audit

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):

just            # full gate: fmt-check + clippy + test (what CI runs)
just fmt        # apply formatting
just test       # run the test suite
just audit      # security-audit the locked dependencies (needs cargo-audit)
just run        # run the app

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.