A terminal client for RCQ, driven from a shell. No app store, no browser, no GUI. Runs anywhere Node 22+ runs: a laptop, a VPS, a Raspberry Pi.
The crypto is the real thing, shared with the phone, web and desktop clients: libsignal v=2 with sealed sender, per-device fan-out, sender-key group broadcasts. The client is smaller than they are, and the Known gaps at the bottom say exactly where.
It registers as a secondary device of your account: your phone keeps the primary slot, and every device gets its own copy of each 1:1 message.
Download and unpack the latest release:
curl -sL https://github.com/rcq-messenger/rcq-cli/releases/latest/download/rcq.tar.gz | tar xz
./rcq/rcq --help
Optional, to make it a real command:
sudo ln -sf "$PWD/rcq/rcq" /usr/local/bin/rcq
rcq register --nick alice # prints your UIN and the 24-word phrase, WRITE IT DOWN
rcq # and you are chatting
Bare rcq is the client. It opens on your most recent conversations,
prints incoming messages as they arrive, and sends whatever you type to
whoever the prompt names:
#396 Ivan (#396) 07:22:36 see you at ten
g21 [Работа] 06:41:36 you: will look tonight
rcq> /to 396
[07:22:36] Ivan (#396): see you at ten
Ivan (#396)> on my way
[07:31:02] me -> Ivan (#396): on my way
[07:31:03] ✓ delivered to Ivan (#396): on my way
To reach somebody new: rcq find "name" or rcq who <uin> to see who a
number belongs to, /add <uin> to ask them into your contacts,
/accept <uin> when somebody asks you. Writing to a person who is neither
a contact nor anybody you have written to is confirmed once first: the
mailbox is open by design, hitting a stranger by typo is not.
/help lists everything: rooms (/g), history (/log, /recent),
requests, blocking, /quit. Up-arrow walks back through the commands you
have typed. Ctrl+C on a half-typed line drops the line; on an empty line it
leaves, and so does Ctrl+D.
Start here, the bare command IS the client:
rcq the conversation: live incoming + a prompt that sends
rcq register [--nick NAME] [--island URL] create an account
rcq restore "<24 words>" [--island URL] restore an account from its phrase
For scripts and one-shots:
rcq whoami uin, nickname, island, device id
rcq contacts list contacts
rcq who <uin> | rcq find "NAME" who is this number, or who is called that
rcq add <uin> send a contact request
rcq requests | accept <uin> | decline <uin> | cancel <uin>
rcq block <uin> | unblock <uin> | remove <uin> [--yes]
rcq groups | join <id> your rooms, and joining an open one
rcq log [<uin>|g<id>] [n] last n lines of a thread, from the history file
rcq send <uin>|g<id> "text" [--yes] one-shot: drain, send, wait for the receipt, exit
rcq watch [--groups] read-only stream of incoming messages
rcq export history file path and line count
rcq lang [en|ru] show or set the language
rcq island trust <host[:port]> <fp> [--replace] pin an island by its certificate fingerprint
rcq island fingerprint [host] how an island is trusted, and its address with the fingerprint
rcq island forget <host[:port]> drop the pin
An island without a certificate authority (the installer's fingerprint
mode, or one reachable only by IP) is trusted by the SHA-256 fingerprint of
its certificate, like an ssh host key. --island host:port#fingerprint, the
address the operator hands out, pins it before the first connection; an
island met without one is pinned on first use and the fingerprint is said
once on stderr; a certificate that later differs is refused, with both
fingerprints and the island trust … --replace line that accepts it, and
the command does not run. The flagship is only ever trusted through an
authority. A certificate whose SAN does not name the address, or an expired
one, cannot be an anchor here even though the phone and desktop apps pin it.
The client speaks English and Russian: unset, it follows LC_ALL/LANG
(a ru* locale answers Russian), and rcq lang ru persists the choice in
the state dir. Data output for scripts (uin numbers, history lines, whoami
values) stays byte-identical in either language.
For the subcommands, stdout carries data only; status goes to stderr,
pipes and scripts welcome. Bare rcq on a pipe prints usage instead of
hanging: the prompt is for people, send/watch are for scripts.
Protocol internals are quiet by default; RCQ_VERBOSE=1 shows them, and
NO_COLOR strips colour.
State (identity, keys, history) sits in $RCQ_CLI_HOME (default
~/.config/rcq), file mode 0600. The 24-word phrase IS the account:
anyone holding it holds the account, and nobody can recover it for
you. One rcq process per state dir: a second one refuses to start
rather than corrupt the encryption state, which also means the prompt and
a one-shot command cannot run at the same time (every verb worth having at
a prompt has a /slash of its own). A second account is one
RCQ_CLI_HOME=/path away.
Messages you receive and send are appended to history-<uin>.jsonl in
that directory, in plaintext. rcq export prints the path. Commands typed
at the prompt are remembered for up-arrow in prompt-history; the text of
your messages deliberately is not written there.
Real ones, so nothing here is a surprise on the day it matters:
- No files or photos. Inbound media is announced (kind, name, size) and cannot be downloaded; nothing can be uploaded.
- Groups: read and post, not administer. Rooms work in both directions, including encrypt-once broadcasts, and you can join an open one by id. Creating, renaming, and moderating a room belong where you can see it.
- No circumvention. No CDN front, no proxy support, no relay use: on a network that blocks the island's host, this client cannot connect. If you already run your own tunnel, put the whole process behind it.
- No device management, no burn, no QR link. A second box takes the 24-word phrase on a command line for now.
- Reactions, edits, deletes and replies are dropped. A message the sender retracts on their phone stays in this client's history file.
- No cross-island send. Messages from another island do arrive and are
labelled
#500@other.islandso they cannot be mistaken for a local number, but there is no way to answer one from here. - No calls, rooms, stories or nearby, and a terminal has no business with them. An incoming call is currently invisible, which it should not be.
- No typing notifications, deliberately: sending them from a headless box would leak keystroke timing from the client whose whole point is running where nobody is watching.
The CLI lives in the web/desktop client repo (one protocol core, several clients); this repo is the distribution point:
git clone https://github.com/rcq-messenger/rcq-desktop
cd rcq-desktop && npm install
npm run cli:build # -> cli/dist/rcq.mjs
npm run cli:test # offline v=2 round-trip under Node
Source: https://github.com/rcq-messenger/rcq-desktop/tree/main/cli
AGPL-3.0, like the rest of RCQ.