Neon Modem Overdrive is a BBS-style command line client that supports Hyperuplink, Discourse, Lemmy, Lobsters and Hacker News as backends, and seamlessly integrates all of them into a streamlined TUI. And yes, you heard that right, I really did call it Neon Modem Overdrive.
Neon Modem is built in Go, using Charm's Bubble Tea TUI framework.
| System | Available | List Forums | List Posts | List Replies | Create Post | Create Reply |
|---|---|---|---|---|---|---|
| Hyperuplink | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Discourse | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Lemmy | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Lobsters | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Hacker News | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
Creating posts and replies needs an account on the system. Every system can also be connected without one, for reading only.
Download the latest release and unpack it:
$ tar -xzf ./neonmodem_*.tar.gzThe binary is called neonmodem. Feel free to move it to e.g. /usr/local/bin.
Clone this repository
$ git clone https://tty.fail/mrus/neonmodem.gitThen cd into the cloned directory and run:
makeBuilding needs Go 1.26.7 or newer. The binary is called neonmodem. Feel free
to move it to e.g. /usr/local/bin.
For Arch Linux an AUR package is available here: https://aur.archlinux.org/packages/neonmodem
Install with your favorite AUR helper.
On NetBSD, a package is available from the official repositories. To install it,
simply run pkgin install neonmodem.
Before launching Neon Modem Overdrive it requires initial setup of the services
(a.k.a. systems). Run neonmodem connect --help to find out more.
Connecting a service will add it to the configuration TOML. The configuration
file location depends on the operating system. On Unix systems, it is in
$XDG_CONFIG_HOME/neonmodem.toml if $XDG_CONFIG_HOME is non-empty, otherwise
$HOME/.config/neonmodem.toml is used. On Darwin, the configuration is in
$HOME/Library/Application Support/neonmodem.toml. On Windows, it is in
%AppData%\neonmodem.toml.
Connecting a system that is already connected asks whether to keep the existing connection or to replace it. Replacing a Hyperuplink connection revokes the previous API key on the board, unless the key comes from a command. For every other system the previous credentials stay valid on the site until you revoke them there, since Neon Modem can't do that everywhere.
Credentials are stored in plain text unless they are read from a command, so the
file is created with mode 0600. When the file can't be written, for example
because it's a link into the Nix store, the command prints the [[Systems]]
tables to add by hand.
Note: Comments in the file are lost on a write.
Every credential can be read from a command instead of being stored in the file.
Add _cmd to its name and use the command as the value:
[Systems.Config.credentials]
username = 'vera'
token_cmd = 'pass show lemmy/token'neonmodem connect asks for every credential whether to enter it or to read it
from a command, and stores only the command. When both token and token_cmd
are set, the command is used.
The commands run when Neon Modem starts, before the interface opens. They run
with $SHELL -c (cmd.exe on Windows) in the current terminal and environment,
so prompts from tools like pass and gpg-agent work. The first line a command
prints to stdout is used as the credential. Prompts have to go to stderr or the
terminal, and pinentry-curses needs GPG_TTY to be exported.
A command that exits with a status other than 0, prints an empty first line or runs longer than 60 seconds makes a system unavailable.
OpenWith entries define commands that run on the post shown in the post view.
Each entry has a name, which the dialog lists, and a cmd:
[[OpenWith]]
name = 'Save page'
cmd = 'wget -q -P ~/Downloads "$NM_POST_URL"'
[[OpenWith]]
name = 'Bookmark in nb'
cmd = 'nb bookmark "$NM_POST_URL" --tags incoming'O in the post view lists the commands. The picked command runs in the
background with $SHELL -c (cmd.exe on Windows) and gets these variables:
| Variable | Value |
|---|---|
NM_SYSTEM_TYPE |
the system's type, e.g. lemmy |
NM_SYSTEM_URL |
the system's URL |
NM_FORUM_ID |
the forum's ID on that system |
NM_FORUM_NAME |
the forum's name |
NM_POST_ID |
the post's ID on that system |
NM_POST_URL |
the post's page, which o opens |
NM_POST_SUBJECT |
the post's title |
NM_POST_CREATED |
the creation time in RFC 3339, in UTC |
NM_POST_LINK |
the linked page of a link post |
A value that doesn't apply is empty and t'he values never become part of the command line, so post content can't run as code.
Note: Quote the variables, as in "$NM_POST_URL", because the shell splits
unquoted values into words. On Windows, they're written as %NM_POST_URL%.
The command's output, up to 1000 lines per stream, and its exit status are
written to the log. Keep in mind that commands have no terminal. This means that
programs that need one fail, and interactive tools have to open their own
window, for example with tmux new-window. When Neon Modem quits, it ends the
commands that still run, including the programs they started. setsid -f in
front of a program keeps it running.
Note: On Unix, commands from a configuration file that every user can write to, or that belongs to a user other than you or root, are not run for safety reasons.
Neon Modem supprts the JSON API of a Hyperuplink internet bulletin board. Give
that address without the /api/v1 path. With an account, sign in with your
username and password and the board issues an API key named
neonmodem on <hostname>. Neon Modem stores the instance URL, the username and
that key, but no password. If you have two-factor authentication enabled you
will have to enter the current code. Instead of the password you can also enter
an API key issued on the board's API page under your account settings. Choose
No account when asked for the username for a read-only connection to a board
that serves guests.
neonmodem connect --type hyperuplink --url https://api.hyperup.linkFor connecting to a Discourse instance with an account, Neon Modem will open the browser to authorize a user API key and store the instance URL, username and the key, but no password. The key can also be read from a command. Neon Modem then shows the key once, so it can be saved e.g. in a password manager. It stays in the terminal's scrollback until that is cleared. Choose No account when asked for the username to connect without an account, which allows you to read public categories, but not posted anything. The key is checked once before it's stored, and a key the instance stops accepting later makes the status line name the connect command.
neonmodem connect --type discourse --url https://www.keebtalk.comFor connecting to a Lemmy instance with an account, Neon Modem logs in once and stores the instance URL, username and the session token Lemmy issues, but no password. For accounts with two-factor authentication, the connect command asks for the current code from the authenticator app. The token can also be read from a command. Neon Modem then shows it once, so it can be saved e.g. in a password manager.
The session stays valid until it's ended on the server, for example by a password change. Neon Modem then lists nothing from that instance and shows the connect command to run. Make sure to restart Neon Modem after running it.
Note: Replacing a connection doesn't end its old session. A password change, however, ends all of them.
Important: Lemmy connections made with Neon Modem 1.x store a password instead of a token and have to be connected again.
Choose No account when asked for the username to connect without an account.
The connect command also asks which feed to list. Either subscribed, the
default feed, requiring an account, local or all. The choice is stored as
listing in the system's options table.
neonmodem connect --type lemmy --url https://lemmy.mlLobsters has no API for posting, so Neon Modem logs in through the site's login form and posts through its web forms, like a browser would. With an account, the instance URL, username and password are stored. Choose No account when asked for the username to connect for reading only. Accounts with two-factor authentication can't be used for posting as of right now.
neonmodem connect --type lobsters --url https://lobste.rsHacker News has no API for posting either, so Neon Modem uses the site's login and submission forms. With an account, username and password are stored. Choose No account when asked for the username to connect for reading only. The forums are Ask HN, Show HN and Jobs HN, while top and new stories are sort orders. Posting from the Ask HN or Show HN forum prefixes the title accordingly.
neonmodem connect --type hackernewsThe UI can be fully customized via the Theme section in the configuration
file. Colors are given as Light and Dark pairs and the one that matches the
terminal background is used. To reset settings, all theme related configurations
can simply be deleted from the configuration.
After setup Neon Modem can be launched by calling neonmodem without any
arguments. It will briefly display a splash screen (any key skips it), then
switch to the posts list, which aggregates the latest posts from all connected
systems. Each system's posts appear as soon as they're loaded. Errors from
single systems are shown in a line below the header as well as in the log inside
~/.cache/neonmodem.log.
In the posts list:
j: Scroll downk: Scroll up/: Filter the listr/enter: Open selected postn: Write new post in on the system/forum of the current selected postC-r: Reload the posts listC-e: Open system selectorC-t: Open forum selectorC-o: Open sort order selector!: Show the recent noticesesc: Cancel or clear the filterC-q: Quit, from every view and dialog
In the post view dialog:
j/k: Scrollr: Reply to post#r: Reply to specific comment # in post, e.g.3rto reply to the reply #3z: Load older replies (if available)o: Open the post in the browserO: Open the post with one of the configured commands, see Open withesc: Close dialog
In the new post / new reply dialog:
tab: Switch between elements (only in new post dialog)C-s: Submit post/replyesc: Close dialog
Note: A post whose body is a single URL is submitted as a link post on systems that distinguish links from text posts (e.g. Hacker News).
The posts list is sorted by New by default. C-o opens the sort order selector
with New, Active, Hot, Top for the past day, week, month or year or for all
time, and Most comments.
| Order | Discourse | Lemmy | Lobsters | Hacker News | Hyperuplink |
|---|---|---|---|---|---|
| New | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ |
| Active | ✔️ | ✔️ | ✔️ | ✔️ | |
| Hot | ✔️ | ✔️ | ✔️ | ✔️ | |
| Top | ✔️ | ✔️ | ✔️ | ||
| Most comments | ✔️ | ✔️ | ✔️ |
A system without the chosen order keeps its own order, or sorts the posts it listed by date or replies for New and Most comments. The line below the header points out those systems. With all systems selected, New sorts every post by date, and every other order mixes the systems' lists by position, so no system's posts sink to the bottom.
Note: A Lobsters tag supports only New, and Jobs HN only New and Hot.
The order at start is set with Sort in the configuration, for example
Sort = 'top-week', or through NEONMODEM_SORT. The keys are new, active,
hot, top-day, top-week, top-month, top-year, top-all and comments.
- Q: The post view is really slow when using a large terminal.
A: Turning off image rendering will improve performance significantly on very large terminal windows and can be done by settingRenderImages = falsein the configuration. - Q: Can I haz Reddit?
A: I won't do the heavy lifting of integrating a proprietary platform with a $15 billion valuation that can't even be bothered to maintain a solid set of client API libraries. If you feel like, go ahead and PR!
Copyright © 2026 マリウス and the Neon Modem Overdrive authors.
Neon Modem Overdrive is released under Version 1.1 of the SEGV License, whose full text is included in the LICENSE file.


