news-tui
v2.2.0
Published
Feedline — The Quiet Wire. A portable, keyboard-first terminal news reader.
Maintainers
Readme
Feedline
The Quiet Wire — a calm, keyboard-first terminal news reader powered by React and neo-blessed.
Package/command compatibility remains
news-tuifor now.
┌──────────────────────────────────────────────────────────────────────────────┐
│ 1:ALL 2:NEWS 3:TECH 4:BLOGS 5:HN TIME ALL 128 │
├──────────────────┬──────────────────────────────┬────────────────────────────┤
│ Sources │ Stories │ Reader │
│ > All sources 128│ > 1 A quieter news workflow│ example.com · 6 min │
│ Hacker News 24│ 2 A new runtime release │ │
│ OpenAI 8│ 3 Show HN: terminal tool │ A quieter news workflow │
│ │ │ │
│ │ │ Semantic article content… │
├──────────────────┴──────────────────────────────┴────────────────────────────┤
│ 128 articles · TECH · READY · wide · truecolor │
│ j/k move Enter read o browser / search b save Tab sources │
└──────────────────────────────────────────────────────────────────────────────┘✨ Features
- Responsive workspace — three columns on wide terminals, stacked list/reader on standard terminals, and one focused pane on compact terminals
- Embedded semantic reader — preserves headings, paragraphs, lists, quotes, code, tables, links, and media captions instead of dumping stripped text
- Browser-rendered fallback — JavaScript-heavy pages can be loaded through Playwright and translated into the same portable reader
- Wire overview — press
vfor a dense headline stream with current-story context and source activity - 3 contrast-verified themes — Quiet, Daylight, and Contrast; the initial theme follows the terminal background
- 10 built-in feeds across 4 categories (tech / news / blogs / hn)
- Vim-style navigation —
j/k, arrow keys, Tab cycles Stories → Sources → Reader - Live search — press
/to filter articles in real-time - Bookmarks —
bto save, persisted to~/.newsbookmarks.json - Inline reader images — iTerm2 renders the publisher's original pixels directly inside the Reader with no
imgcatinstall; other terminals and standard tmux sessions receive bounded ANSI artwork, whileItoggles the region andiopens the external adapter - Progressive external image viewing — Kitty, iTerm/WezTerm, Sixel, chafa, and timg are detected; the default browser is the explicit final fallback
- External browser remains optional —
oopens the original page;Enterkeeps reading inside Feedline - Auto-refresh — feeds refresh every 5 minutes, or press
r - Automatic feed discovery - validated RSS/Atom feeds from recent story sites are kept in a quiet suggestion inbox for one-key review and addition
- Feed repair - paused or failing sources can search for validated replacement URLs from site metadata, common paths, Feedly, and RSSHub
- Sort cycling — press
sto cycle between time / source / title - Color-coded sources — each source gets a distinct color
- Relative timestamps — "2h ago", "1d ago" style dates
- Focus indicators —
>plus a high-contrast border identifies the active pane without relying on color
Portable reader
Feedline renders article meaning, not browser pixels. Standard pages are fetched and parsed with Mozilla Readability. JavaScript-rendered pages fall back to Playwright using, in order:
NEWS_TUI_BROWSER_EXECUTABLE- a Playwright-managed Chromium installation
- an installed Google Chrome or Microsoft Edge channel
If no browser runtime is available, Feedline keeps the RSS excerpt visible and reports the degraded state. To install an isolated Chromium runtime:
bunx [email protected] install chromiumThe reader itself never depends on iTerm2, Kitty, a graphical protocol, a Nerd Font, or a particular editor.
🚀 Install
One-liner (bunx — no install needed)
bunx news-tuiHomebrew (macOS)
brew tap yashness/tap
brew install news-tuiNix
# Run without installing
nix run github:yashness/news-tui
# Add to your flake inputs
nix profile install github:yashness/news-tuiGlobal install
bun install -g news-tui
news-tuiClone & run locally
git clone https://github.com/yashness/news-tui.git
cd news-tui
bun install
bun start⌨️ Keyboard Shortcuts
| Key | Action |
|-----|--------|
| j / ↓ | Next article |
| k / ↑ | Previous article |
| Tab | Cycle focus: Stories → Sources → Reader |
| 1-5 | Switch category (all/news/tech/blogs/hn) |
| Enter | Read selected article inside Feedline; in Reader, open the selected link |
| o | Open original article in the default browser |
| [ / ] | Select previous / next link in Reader |
| Backspace | Return from Reader to Stories |
| PageUp / PageDown | Scroll Reader by a page |
| I | Toggle inline lead image in Reader |
| c | Open comments in browser (HN) |
| / | Search / filter articles |
| Escape | Clear search |
| b | Bookmark current article |
| S | Generate/show an AI brief directly under the Reader headline |
| i | Open the article image with the best external terminal/browser adapter |
| r | Refresh feeds |
| s | Cycle sort (time → source → title) |
| t | Cycle theme (Quiet → Daylight → Contrast) |
| v | Toggle the dense Wire overview |
| A | Review discovered feeds, quick-add, search, or import |
| H | Open Feed Health; press F on a source to find alternatives |
| ? | Show help overlay |
| q / Ctrl-C | Quit |
📡 Built-in Sources
| Category | Sources | |----------|---------| | News | BBC, Times of India | | Tech | Facebook Eng, Google Research, Netflix, OpenAI, Spotify Eng, GitHub | | Blogs | WoodFromEden | | HN | Hacker News (with top comments from HN API) |
🤖 AI Features (Managed or BYOK)
The reader is free. Feedline AI is the managed Pro option: the CLI sends an explicit AI request to the Feedline API, which checks the current entitlement before calling Azure OpenAI. Azure and Razorpay secrets stay on the server and are never bundled into npm, written to settings, or returned by an endpoint.
BYOK Azure, Anthropic, OpenAI, and local Ollama remain available for users who prefer to pay their provider directly. These modes do not consume Feedline-managed AI capacity.
Press $, then a, to choose feedline, azure, anthropic, openai, or ollama. When Feedline AI is selected, the server is the authoritative paywall. Editing the local entitlement cache cannot unlock provider calls.
Set the managed service once:
export NEWS_TUI_API_BASE_URL=https://feedline.example.comFeedline creates a random per-installation token on first contact and stores it in ~/.newstui-account.json with mode 0600.
Azure OpenAI (auto-detected)
Feedline loads Azure credentials directly from ~/.env-azure-ai; secrets are never copied into the repository or settings file.
AZURE_OPENAI_ENDPOINT=https://YOUR-RESOURCE.openai.azure.com/
AZURE_OPENAI_KEY=...
AZURE_OPENAI_CHAT_DEPLOYMENT=gpt-5.4-mini
AZURE_OPENAI_IMAGE_DEPLOYMENT=gpt-image-2
AZURE_OPENAI_VERSION=2025-04-01-previewWhen this file is complete, Azure becomes the default provider. The chat deployment powers summaries, digests, feed Q&A, comparisons, recommendations, entity extraction, and focus mode. The image deployment is reserved for generated-image features; inline article images use the publisher's original media.
Press S on a story to open the Reader and place its AI brief immediately below the headline. Cached briefs appear in the same location.
Anthropic
Place your key in ~/.env-claude-token-work:
ANTHROPIC_API_KEY=sk-ant-api03-...Default model: claude-haiku-4-5-20251001
OpenAI
Configure via $ → a — the provider-scoped key is stored in ~/.newstui-settings.json (chmod 600).
Ollama (local, no key required)
Run ollama serve locally, then select ollama via $ → a.
Default model: llama3.2:3b
Privacy: No data is sent to AI providers without an explicit user action. Managed prompts transit the Feedline API; BYOK prompts go directly to the selected provider. No telemetry is added.
➕ Custom Sources
Add your own RSS feeds by creating ~/.newsources.json:
[
{ "name": "Ars Technica", "url": "https://feeds.arstechnica.com/arstechnica/index", "category": "tech" },
{ "name": "The Verge", "url": "https://www.theverge.com/rss/index.xml", "category": "news" }
]Use any category name — new categories auto-appear as tabs (6, 7, etc).
Automatic discovery and feed repair
Feedline periodically scans a bounded set of high-signal article domains plus paused or unhealthy sources. It checks site-published RSS/Atom metadata first, then standard feed paths, Feedly's public index, and supported RSSHub routes. Every candidate is fetched, parsed, deduplicated, and required to contain real items before it appears.
Press A to review the discovery inbox:
Downenters the suggestion list;j/kmoves within it.Enterpreviews its recent headlines and posting frequency.aquick-adds the selected validated feed.ddismisses it for 30 days.Aadds every visible validated suggestion.Ctrl-Rruns a fresh deterministic scan.Rexplicitly asks the configured AI provider for niche recommendations, then independently validates every returned URL before showing it.
Press H for Feed Health, select a paused or failing source, and press F to inspect validated alternatives. Enter replaces the URL of a custom source while preserving its category and metadata. Built-in definitions remain immutable, while the broken URL is retired and a user-owned alternative takes its place.
The inbox is stored in ~/.newstui-feed-discovery.json. Core discovery does not require AI credentials and does not send article context to an AI provider. AI recommendation generation only runs through the existing explicit or weekly opt-in flow, and generated URLs never bypass feed validation.
Requirements
- Bun ≥ 1.0
- Any terminal with keyboard input and at least 16 colors
- Unicode is recommended but not required; core markers have ASCII fallbacks
Optional environment controls:
| Variable | Values | Purpose |
|---|---|---|
| NEWS_TUI_COLOR_MODE | mono, 16, 256, truecolor | Override color capability detection |
| NEWS_TUI_GRAPHICS | text, iterm, kitty, sixel | Override image protocol detection |
| NEWS_TUI_NATIVE_IMAGES | 0, false, off | Disable native inline pixels while retaining the ANSI fallback |
| NEWS_TUI_REDUCED_MOTION | 1, true | Disable ticker movement |
| NEWS_TUI_TERMINAL_BG | dark, light | Override initial theme selection |
| NEWS_TUI_BROWSER_EXECUTABLE | absolute path | Use a specific Chromium-compatible browser |
| NEWS_TUI_INLINE_IMAGES | 0, false, off | Disable inline Reader images |
| NEWS_TUI_AUTO_DISCOVERY | 0, false, off | Disable background feed discovery; manual scans remain available |
| NEWS_TUI_AI_PROVIDER | feedline, azure, anthropic, openai, ollama | Override the saved AI provider |
| NEWS_TUI_API_BASE_URL | HTTPS URL | Enable Feedline accounts, Razorpay checkout, entitlements, and managed AI |
| NEWS_TUI_ALLOW_PRIVATE_NETWORK | 1, true | Allow article/image/browser fetches to private or local addresses; disabled by default |
🔑 Installation Account
Feedline uses a private installation token rather than a shared client API key or a caller-supplied user ID.
# Connect this installation and sync its plan
news-tui --login
# Show the current installation and plan
news-tui --whoami
# Unlink this installation
news-tui --logout
# Recover a purchase using its Razorpay payment ID and email
news-tui --restoreThe token is saved to ~/.newstui-account.json with mode 0600. Only its SHA-256 hash is stored by the server. Recovery rotates the active installation instead of cloning paid access.
Press U from Account to enter the recovery email used for the Razorpay receipt, then continue to checkout. The email is fixed for that order so a captured purchase cannot become unrecoverable.
💳 Razorpay Billing and Managed AI Service
src/billing-server.ts starts the production API. It uses SQLite in WAL mode, renewable 30-day Pro access, signed Razorpay webhooks, payment and order idempotency, persisted rate limits, and an entitlement-gated Azure OpenAI proxy.
- Copy
deploy/azure/feedline.env.exampleto/etc/feedline/feedline.envand set:RAZORPAY_KEY_IDRAZORPAY_KEY_SECRETRAZORPAY_WEBHOOK_SECRETAPP_BASE_URLAZURE_OPENAI_ENDPOINTAZURE_OPENAI_API_KEYAZURE_OPENAI_CHAT_DEPLOYMENT
- Configure Razorpay to send
payment.capturedandorder.paidevents tohttps://YOUR_DOMAIN/v1/billing/webhooks/razorpay. - Run locally with
task server:start, or deploy the TLS-terminated stack:docker compose \ --env-file /etc/feedline/feedline.env \ -f deploy/azure/compose.yml \ up -d --build - Set
NEWS_TUI_API_BASE_URL=https://YOUR_DOMAINin the client environment.
The default price is INR 499 (49900 paise) for 30 days. Override price, currency, duration, AI quotas, and database path with values from the example environment file.
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/health | Readiness without secret values |
| POST | /v1/installations | Issue one private installation token |
| POST | /v1/installations/recover | Rotate access using payment ID and matching email |
| GET | /v1/entitlements/me | Read the bearer installation's plan |
| POST | /v1/billing/orders | Create a server-owned Razorpay order |
| POST | /v1/billing/webhooks/razorpay | Verify and credit captured payment |
| POST | /v1/ai/complete | Pro-gated managed completion |
| POST | /v1/ai/stream | Pro-gated managed SSE stream |
Never put Razorpay or Azure credentials in the CLI environment. The API must be exposed through HTTPS; the provided Caddy configuration handles certificates and security headers.
📄 License
MIT
