A terminal UI for browsing and posting to Discourse forums. It behaves like a lightweight browser client and supports reading topic lists, viewing full topics, replying, liking, and searching.
- Browse latest/hot/private messages/new/unread/top topic lists.
- Read full topics with scrollable posts and a progress bar.
- Create new topics from the topic list.
- Choose a category when creating a new topic.
- Reply to topics or specific posts (Markdown supported).
- Like/unlike posts.
- Search posts and jump directly to the matching topic context.
- View notifications in a dedicated list and jump straight to the related topic/post.
- Live status-bar badges for notifications and PMs, driven by MessageBus with automatic reconnect recovery when using cookie-based login auth.
- Inline composer with cursor movement, line breaks, and a live character counter.
- Emoji replacements for common
:emoji:tokens and:)-style smiles. - YAML-driven themes (
default,slate,fairground,rust) with per-color overrides. - Inline image previews in expanded posts (uses
chafa, falls back toviu). - UI localization with built-in
en,fr,de, andes. - Username/email + password login (cookie-based session login; supports TOTP/backup codes and realtime MessageBus updates).
- API key + username login (fallback for SSO-only or locked-down sites; HTTP-only, no realtime MessageBus session).
| Capability | Status | Notes |
|---|---|---|
Topic lists (latest, unread, private, hot, new, top) |
Full | Includes Top period cycling and PM-specific layouts. |
| Topic reading and navigation | Full | Scrollable topic view with progress/footer bar. |
| Posting and replying | Full | New topics, topic replies, and post replies. |
| Likes | Full | Like/unlike from Topic View. |
| Search | Full | Search results open directly into matching topic/post context. |
| Notifications | Full | Dedicated notifications list with direct open into the related topic/post. |
| Localization | Full | Built-in en, fr, de, and es, selectable by --lang or TERMCOURSE_LANG. |
| Theming | Full | Built-in themes plus YAML overrides. |
| Inline images | Full | chafa primary, viu fallback/override. |
| Live list update notification | Partial | Uses Discourse MessageBus channels and shows New/updated (n) in the topic-list status area, with reconnect recovery. Current implementation tracks core list filters only; category/tag-scoped refinement is planned. |
git clone https://github.com/merefield/termcourse
cd termcourse
bundle install
# Option A: username/password login
DISCOURSE_USERNAME="you@example.com" DISCOURSE_PASSWORD="your_password" \
bundle exec bin/termcourse --theme slate --lang fr https://your.discourse.host
# Option B: API key fallback (no realtime PM/topic updates)
DISCOURSE_API_KEY="your_key" DISCOURSE_API_USERNAME="your_username" \
bundle exec bin/termcourse --theme fairground https://your.discourse.hostLanguage selection:
bundle exec bin/termcourse --lang de https://your.discourse.host
TERMCOURSE_LANG=es bundle exec bin/termcourse https://your.discourse.hostThis uses a cookie-based browser session and works across most Discourse installs that allow local login. It is also the recommended mode for realtime behavior: live PM/topic updates and MessageBus-driven status changes require this cookie-backed session.
DISCOURSE_USERNAME="you@example.com" DISCOURSE_PASSWORD="your_password" \
bundle exec bin/termcourse https://your.discourse.hostIf MFA (TOTP) is enabled, you’ll be prompted for a 6-digit code. If backup codes are enabled, you can choose that method instead.
This mode works for normal HTTP actions such as browsing, posting, and polling-backed badge refreshes, but it does not create a browser session cookie. That means realtime MessageBus features such as live PM/topic replies and live topic-channel updates are not available in API-key mode.
DISCOURSE_API_KEY="your_key" DISCOURSE_API_USERNAME="your_username" \
bundle exec bin/termcourse https://your.discourse.hostYou can set any of these in your shell or .env file. .env is auto-loaded if present.
DISCOURSE_API_KEY: API key for fallback auth.DISCOURSE_API_USERNAME: Username tied to the API key.DISCOURSE_USERNAME: Username or email for password login.DISCOURSE_PASSWORD: Password for password login.TERMCOURSE_HTTP_DEBUG: Set to1to log HTTP/auth debug responses to/tmp/termcourse_http_debug.txt.TERMCOURSE_LINKS: Set to0to disable OSC8 clickable links.TERMCOURSE_THEME: Theme name (defaultdefault). Built-ins:default,slate,fairground,rust.TERMCOURSE_LANG: UI language:en,fr,de, ores. If unset, termcourse usesLANG/LC_*and falls back toen.TERMCOURSE_COLOR_MODE: UI color mode:auto(default),truecolor,256,16.autouses256on macOS andtruecolorelsewhere.TERMCOURSE_THEME_FILE: Optional path to theme YAML. If unset, termcourse checks./theme.ymlfirst, then~/.config/termcourse/theme.yml.- CLI override:
--theme NAMEapplies only to the current run and overridesTERMCOURSE_THEME. - CLI override:
--lang LANGapplies only to the current run and overrides locale env detection. TERMCOURSE_IMAGES: Set to0to disable inline image previews.TERMCOURSE_IMAGE_BACKEND: Choose image backend:auto(default),chafa,viu, oroff.TERMCOURSE_IMAGE_MODE: Generic image mode for bothchafaandviu:stable(default) orquality.TERMCOURSE_IMAGE_COLORS: Chafa quality color mode:auto(default),none,16,240,256,full.TERMCOURSE_IMAGE_LINES: Target image preview height in terminal lines (default14).TERMCOURSE_IMAGE_DEBUG: Set to1to write image debug logs to/tmp/termcourse_image_debug.txt.TERMCOURSE_IMAGE_QUALITY_FILTER: Set to0to allow low-quality blocky previews (default filters them out).TERMCOURSE_IMAGE_MAX_BYTES: Maximum image download size per preview (default5242880bytes).TERMCOURSE_TICK_MS: UI resize/input poll interval in milliseconds (default100).TERMCOURSE_EMOJI: Set to0to disable emoji substitutions.TERMCOURSE_CREDENTIALS_FILE: Optional path to host-mapped YAML credentials. If unset, termcourse checks./credentials.ymlfirst, then~/.config/termcourse/credentials.yml.
- Supported UI languages:
en,fr,de,es. - Per-run override:
--lang LANG - Session/environment default:
TERMCOURSE_LANG=LANG - Fallback detection order:
TERMCOURSE_LANG, thenLC_ALL, thenLC_MESSAGES, thenLANG, thenen. - Discourse-provided content such as category names, notification type data, topic titles, and post bodies is shown as returned by the server.
Auth selection order:
- CLI flags (
--username,--password,--api-key,--api-username) have highest priority. - Then host credentials from YAML using lookup order:
TERMCOURSE_CREDENTIALS_FILEpath if set, else./credentials.yml, else~/.config/termcourse/credentials.yml. - Then generic env vars (
DISCOURSE_*). - If both login and API pairs are present, login is tried first unless the host entry sets
auth: api. - If a host entry explicitly sets
auth: loginorauth: api, termcourse only tries that auth method for that host. - For username/password auth, termcourse prompts only for missing fields (for example, prompts just for password if username is already known).
- For API auth, both
api_usernameand API key must resolve to non-empty values. If either is missing (including missing*_envtarget values), API login fails. - Realtime MessageBus features require login auth. If a host is pinned to
auth: api, termcourse will run in HTTP-only mode for PM/topic updates.
Example .env:
DISCOURSE_USERNAME=you@example.com
DISCOURSE_PASSWORD=your_passwordExample credentials.yml:
sites:
acmeforum.example:
auth: api
api_username: system
api_key_env: TERMCOURSE_API_KEY_ACME
meta.discourse.org:
auth: login
username: you@example.com
password_env: TERMCOURSE_PASSWORD_METAA ready-to-edit sample is included at credentials.example.yml.
An aligned env template is included at .env.example.
A ready-to-edit theme template is included at theme.example.yml.
Example theme.yml:
slate:
primary: "#e6edf3"
highlighted: "#355f8a"
highlighted_text: "#ffffff"
borders: "#5f6f80"
bar_backgrounds: "#1f2733"
separators: "#8ca0b3"
list_numbers: "#8fbce6"
post_username: "#9ab0c6"Supported theme keys: primary, background, highlighted, highlighted_text, borders, bar_backgrounds, separators, list_numbers, list_text, post_username, list_meta, accent.
Color translation:
- When
TERMCOURSE_COLOR_MODE=256or16, theme hex colors are translated to the nearest terminal palette color. - This is applied automatically when
TERMCOURSE_COLOR_MODE=autoon macOS.
- Image previews are shown only for the expanded post in Topic View.
- Backend selection:
TERMCOURSE_IMAGE_BACKEND=autotrieschafafirst, thenviu.- Set
TERMCOURSE_IMAGE_BACKEND=chafaorTERMCOURSE_IMAGE_BACKEND=viuto force one backend. - Set
TERMCOURSE_IMAGE_BACKEND=offorTERMCOURSE_IMAGES=0to disable previews. - Chafa modes:
TERMCOURSE_IMAGE_MODE=stablefavors stability and conservative output.TERMCOURSE_IMAGE_MODE=qualityenables higher-detail/color symbol rendering.- Color depth:
TERMCOURSE_IMAGE_COLORS=autodetects terminal support (truecolor,256, etc.) for chafa quality mode.- Set
TERMCOURSE_IMAGE_COLORS=fullto force 24-bit if your terminal supports it. - Height control:
TERMCOURSE_IMAGE_LINEScontrols preview height (line count), default14.viupath uses line-targeted rendering to preserve aspect ratio better.- Image debugging:
TERMCOURSE_IMAGE_DEBUG=1writes renderer diagnostics to/tmp/termcourse_image_debug.txt(backend choice, URL detection, download and render line counts, fallback decisions).- Quality filtering:
TERMCOURSE_IMAGE_QUALITY_FILTER=1(default) suppresses very noisy block-only previews.- Set
TERMCOURSE_IMAGE_QUALITY_FILTER=0to always show renderer output. - Download safety:
TERMCOURSE_IMAGE_MAX_BYTESlimits how much data is fetched per image preview.- Discourse
upload://...markdown image links are resolved to/uploads/short-url/...automatically. - Practical guidance for WSL/Windows Terminal:
- If
viulooks good in your shell, forceTERMCOURSE_IMAGE_BACKEND=viu. - If output is unstable/noisy, use
TERMCOURSE_IMAGE_BACKEND=chafaand tuneTERMCOURSE_IMAGE_MODE.
- Termcourse redraws reactively on terminal resize without requiring a key press.
- Polling interval is controlled by
TERMCOURSE_TICK_MS(default100ms). - Lower values feel more responsive but can increase CPU usage and repaint churn.
- Use Up/Down arrows to navigate.
- Press Enter to open a topic.
- Press
1-0to open the first 10 visible topics directly. - Press
cto create a new topic. - Press
nto open notifications. - Press
sto search. - Press
fto cycle the list filter (Latest, Unread, Private Messages, Hot, New, Top). - Press
pto change Top period (daily, weekly, monthly, quarterly, yearly). - Press
gto refresh. - Press
qto quit.
The status bar shows the current list filter and your logged-in username.
If you have unread non-PM notifications, an accent badge like [3] appears beside the username.
If you have unread private messages, a separate PM Unread (n) badge appears in the status bar.
If new topics arrive on the current list, a New/updated (n) indicator appears in the right side of the status bar.
Private Messages list view:
- Uses PM-specific columns in wide layouts.
- No category or views columns.
- Includes a
Userscolumn (up to 3 usernames, otherwiseN users) andReplies. - In compact view, bracket metadata shows users (not reply count).
- Compact titles are ellipsized to avoid line wrapping.
- Enter inserts a new line.
- Arrow keys move the cursor within the editor.
- Backspace deletes.
Ctrl+Dsubmits.Esccancels.
- Up/Down moves between posts.
- Left/Right scrolls the expanded post content.
llike/unlike a post.rreply to the topic.preply to the selected post.ssearch from within a topic.nopens notifications.xtoggle fullscreen image view when the selected post shows an image preview.escgoes back to the list.qquits.
The bottom bar shows your position in the topic (current/total).
In fullscreen image view, press x or esc to return to the topic.
- Press
sto open search. - Type your query; Enter runs the search.
- Press
nto open notifications. - Arrow keys move through results; Enter opens the topic at the matching post.
- From a search-opened topic,
escreturns to search results. - From search results,
escreturns to the topic list.
- Press
nfrom the topic list, topic view, or search results to open notifications. - Arrow keys move through notifications; Enter opens the related topic/post.
- Press
fto cycle notification filters (All,Responses,Likes,Mentions,Edits,Links,Messages). - Opening a notification marks it read in termcourse after the server confirms the change.
escreturns to the previous screen.
- HTTP debug logs are opt-in: set
TERMCOURSE_HTTP_DEBUG=1. - Logs are written to
/tmp/termcourse_http_debug.txt. - Logs may include usernames and server responses. Disable when not needed and delete after use.
- Prompt-based login is supported by default when no full credential pair is found in env/flags, which avoids putting passwords on the command line.
- Session cookies are in-memory only. The app does not write cookies to disk; closing the app ends the session on this client.
- No password storage. Credentials are only used for the login request and are not persisted by the app.
- Some sites disable local login. If a site requires SSO or blocks scripted login, use an API key or a dedicated test account.
- MFA support is limited to TOTP/backup codes. Hardware keys (WebAuthn/passkeys) are not supported in terminal mode.
- Replies support Markdown.
- If a site returns login errors with MFA enabled, ensure TOTP is configured and enter a fresh 6-digit code when prompted.
- If both login and API env pairs are set, username/password is used first.
- On some networks (often macOS with broken IPv6 routes), the client may time out on initial requests. Termcourse automatically retries once over IPv4 and will stick to IPv4 for the remainder of the session after the first timeout.
