Chat in a terminal sounds like a trade. Images preview inline, reactions
render, threads open beside the conversation, drafts follow you to the webapp — none of
it is missing, all of it is text.
matterbox — orbit/releases
╭─────╮╭─────────╮╭────────╮╭───────────╮╭─────────╮│DMs││Feed 1!││Search││Orbit [1]││Lab [2]│├─────┴┴─────────┴┴───────┬┴┘ └┴─────────┴───────────────────────────────────┬┬────────────────────────────────────────────────────────────┐│Channels│#releases││Thread · 4 replies││#general 3│││sofie12:03· root││#random 1│││ Cutting 0.9 tomorrow — anything still open? ││> #releases│▾ 🖼️ DSCF5311.jpg (4416×2944, 6.1MB)││teun12:11││ #terminal │jonas12:07││ Only the docs pass, and that is not a blocker. │││ The octant fallback for terminals without the new block ││mira12:17│││ glyphs — small, up in an hour. ││ It is if the rules examples are wrong — people copy │││👍 2││ those verbatim. │││mira12:30││teun12:21│││ Semantic search reindexes on every start since the ││ Fair. I'll take the rules page then. │││ embedding-dim change: ││corne13:29│││││ Fixed in docs/rules.md — every: 15m. │││```sh│││││matterbox embed --reset│││││```│││││teun12:39│││││ Confirmed on a cold cache: 12k messages, ~40s on CPU. │││││ Fine, just quiet about it. │││││👀 1│││││deploybot12:47│││││ pipeline #4812 passed on main — linux/amd64, linux/arm64, │││││ darwin/arm64 built in 2m18s │││││sofie12:58│││││ Nice. @corne did drag-and-drop get the macOS paste-is-a- │││││ path check? │││││corne13:02│││││ Both now. A paste that is nothing but existing file paths │││││ becomes an attachment; attach_on_drop: false opts out. │││││🎉 3│││││jonas13:13│││││ Then we're good. I'll tag once the octant patch lands. │││││mira13:25│││││ One more: the rules docs still say every: takes seconds. │││││▎↳ corne13:29│││││▎ Fixed in docs/rules.md — every: 15m. │├────────────────────────────────────────────────────────────┤││││> message…│└─────────────────────────┴────────────────────────────────────────────────────────────┘└────────────────────────────────────────────────────────────┘icompose • ↵open thread • /search channel • ffilter • ?help • f1command palette • Ichannel info • Rreact • alt+1…9go to team◦corne
╭─────╮╭─────────╮╭────────╮╭───────────╮╭─────────╮│DMs││Feed 1!││Search││Orbit [1]││Lab [2]│├─────┴┴─────────┴┴───────┬┴┘ └┴─────────┴───────────────────────────────┐│Channels│#releases││#general 3│teun12:39││#random 1│ Confirmed on a cold cache: 12k messages, ~40s on ││> #releases│ CPU. Fine, just quiet about it. ││ #terminal │👀 1│││deploybot12:47│││ pipeline #4812 passed on main — linux/amd64, │││ linux/arm64, darwin/arm64 built in 2m18s │││sofie12:58│││ Nice. @corne did drag-and-drop get the macOS paste- │││ is-a-path check? │││corne13:02│││ Both now. A paste that is nothing but existing file │││ paths becomes an attachment; attach_on_drop: false│││ opts out. │││🎉 3│││jonas13:13│││ Then we're good. I'll tag once the octant patch │││ lands. │││mira13:25│││ One more: the rules docs still say every: takes │││ seconds. │││▎↳ corne13:29│││▎ Fixed in docs/rules.md — every: 15m. ││├────────────────────────────────────────────────────────┤││> message…│└─────────────────────────┴────────────────────────────────────────────────────────┘icompose • ↵open thread • /search channel • ffilter • ?help…◦corne
The feed
Everything unread across every team and DM in one list, newest first,
each channel with a couple of already-read messages above the divider so you know
what you are walking into. Muted channels stay out unless you ask.
matterbox — unread feed
╭─────╮╭─────────╮╭────────╮╭───────────╮╭─────────╮│DMs││Feed 1!││Search││Orbit [1]││Lab [2]│├─────┴┘ └┴────────┴┴───────────┴┴─────────┴─────────────────────────────────────────────────────────────────────────────────────────────────┐│Unread Feed 3 channels · ↵ open · R reply · m mark read · r refresh Mark all read (A) │├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤│┌─ Orbit › #general · 3 new ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│││teun11:56Coffee machine is fixed. That is the whole announcement.││││mira12:20Heroic. Who do we thank?││││─ new ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││││teun13:07 Whoever left the descaling kit on my desk, anonymously. ││││sofie13:19 Heads up: the office router reboots at 19:00, so `listen` drops its socket for a minute. ││││jonas13:28 It reconnects on its own — you lose the WebSocket, not the cache. │││└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘││││┌─ DMs › @sofie · 2 new · 1 mention ─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│││corne10:31Sent you the branch — the octant table is the only interesting part.││││─ new ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││││sofie13:22 Read it. One question about the tie-breaking and then I am happy. ││││sofie13:27@corne why keep the earlier family on an exact tie? │││└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘││││┌─ Orbit › #random · 1 new ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐│││mira08:31My terminal now has more fonts than my laptop has RAM.││││─ new ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││││teun12:44 That is not a problem, that is a hobby. │││└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘│││└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘↑/kup • ↓/jdown • ↵open • mmark read • ?help • Rreply in thread • rrefresh • Mshow/hide muted channels • tabfocus next…◦corne
What it does
Everything below runs against a stock Mattermost server, self-hosted
or not. Nothing here needs a plugin, an admin, or anyone else to install anything.
A terminal UI, not a wrapper
Teams, channels, DMs, threads, reactions, attachments, image and video previews,
per-channel drafts synced with the webapp — live over WebSocket, in a client that
starts instantly and never asks you to wait for a spinner. It runs wherever a
terminal does, SSH included.
A scriptable CLI
send, read, search, react,
unread, digest — most with --json, all with
shell completion. Chat becomes something cron and pipes can reach.
Every subcommand, and its flags →
Your history, on your disk
Every message you see lands in a local SQLite database, so reopening a channel is
instant and history stays searchable with the network off. There is a read-only SQL
tab if you would rather ask it yourself.
The schema, and queries to paste →
Search that finds it
FTS5 keyword search over the cache, optionally blended with vector search from a
local embeddings model. End a query with ? and a local model digs
through your channels to answer it. Nothing leaves the machine.
A rules engine
The listen daemon reacts to what happens on your server: match on team,
channel, author, text or mention and notify, run a command, POST a webhook, post
back, react — or fire on a cron. It stays quiet about whatever you are reading.
The rules reference →
Jira and GitLab inline
Press v on an issue link or a merge request and a side panel opens.
Edit status, priority, points and assignee; check the pipeline; approve or merge —
without leaving the terminal.
Install
One line on Linux and macOS, or a clone and a make.
One line
$ curl -fsSL https://matterbox.work/install.sh | sh
It downloads the release binary and checks it against the checksums the
release publishes. That binary has FFmpeg linked into it, so inline video and
HEIC/AVIF/JPEG XL images work with nothing installed alongside — the one
thing only a local build gets is the --demo soundtrack, which needs
ALSA at runtime. Pass --source for that. It says which path it took,
and which features went in.
No root, nothing outside your home directory, and no file of yours is edited —
where something needs to go on your PATH or in your shell rc, it is printed for
you to paste. Read it before you run it:
matterbox.work/install.sh is served as plain text for
exactly that reason. Flags go after sh -s -- —
--source compiles here instead,
--version pins a release, --dir puts it somewhere other
than ~/.local/bin:
$ curl -fsSL https://matterbox.work/install.sh | sh -s -- --prebuilt
The release binaries carry FFmpeg inside them, so inline video and
HEIC/AVIF/JPEG XL images work with nothing installed alongside, and the
Linux ones are fully static. Only the --demo soundtrack needs a
build from source. The tarballs are on the
releases page
if you would rather take one by hand.
From source
$ git clone https://github.com/cornedor/matterbox
$ cd matterbox
$ make install # builds, installs to ~/.local/bin, sets up completion
Optional extras need C libraries; make compiles in whatever your
machine already has and make tags says what it picked. Plain Go works
too, without them:
$ go build -o matterbox .
First run
Just run it. With no saved login the wizard opens by itself — the screen behind
this page — points it at your server and logs you in.
$ matterbox
Or write ~/.config/matterbox/config.yaml yourself; the only required
key is server_url. Then matterbox login opens your browser
for SSO and saves the token. matterbox welcome replays the wizard later,
to change an answer.
The short version. The installation page →
has every flag the installer takes, the build tags behind inline video and the
--demo soundtrack, the background listen service, and
how to upgrade or remove it again.
The CLI
Mattermost from the command line. Run matterbox with no
arguments for the TUI; the subcommands are for scripts. Channels are addressed as
team/channel, or @username for a DM.
Command
What it does
matterbox send <channel> [msg]
Post a message (--file to attach, repeatable)
matterbox reply <post-id> [msg]
Reply in a thread, recording which message you answered
Search the local cache (--semantic, --channel, --context)
matterbox channels
List every team and channel with its address
matterbox listen
Background daemon: keeps the cache warm, runs your rules
matterbox rules test
Say which rules a message fires, and why the rest do not
matterbox keys
Every keyboard action, its default key, and your overrides
Nine of twenty. The CLI reference →
has all of them, the JSON Lines shape --json emits, and what to
script with it.
The optional parts
Summaries, semantic search and agentic search talk to any OpenAI-compatible endpoint.
Point them at a local llama.cpp
server and nothing leaves your machine — or leave them off entirely and matterbox
never asks again.
The listen daemon is optional too. It holds a WebSocket open, writes
every message into the cache, and — if you configure it — bridges your mentions and
DMs to Telegram, quietly skipping anything you are already reading on screen.