A terminal IRC client with vim-style modes, full IRCv3 support, encrypted DMs, inline images, and more.
$ cargo build --release && ./target/release/rvirc
Everything you need in a modern terminal IRC client.
NORMAL, INSERT, and COMMAND modes with distinct status bar colors. Navigate like you would in Vim — i to type, : for commands, Esc to return.
Connect to multiple IRC servers simultaneously. The channels pane groups everything by server. Switch between servers and channels seamlessly.
End-to-end encrypted direct messages using X25519 key exchange and ChaCha20-Poly1305 encryption. TOFU key pinning and SAS verification built in.
Send and receive files via magic-wormhole relay. Accept/reject popups, in-chat progress, and built-in file browser. Works inside encrypted DM sessions.
Image URLs render inline in chat via Sixel, Kitty, or iTerm2 protocols. Animated GIF support included. Works inside encrypted DMs too.
Desktop notifications and optional sound for unviewed buffers. Highlight words trigger mention-style alerts. :mute / :unmute to control.
Track nicks with MONITOR. Green = online, yellow = away, red = offline. Presence updates in real time via away-notify and extended-monitor.
After unexpected disconnect, retries up to 3 times with exponential backoff (5s, 15s, 30s). Manual :connect or :quit cancels.
Bold, italic, strikethrough, colors, spoilers — all rendered. Plus rvIRC-exclusive @@rainbow@@ and $$scared$$ text effects.
:search opens a filterable popup over the current buffer. :superlist fetches channel lists from all servers in one combined view.
Press e to enter edit-select mode — your recent messages are numbered in yellow. Pick one to open an edit popup, modify, and send.
Press r to reply to a message. React with emoji via :react. Reactions display inline below the target message.
Full coverage of the IRCv3 specification — stable, draft, and client tags.
| Capability | What rvIRC Does |
|---|---|
sasl | SASL PLAIN and EXTERNAL authentication |
multi-prefix | Shows all mode prefixes per nick (e.g. @+nick) |
away-notify | Friends pane updates in real time as nicks go away/return |
account-notify | Tracks nick→account mapping changes |
account-tag | Shows account name alongside messages |
extended-join | Account name and real name on JOIN |
invite-notify | Notifies when someone else is invited to your channel |
chghost | Updates ident@host cache on host changes |
cap-notify | Handles dynamic CAP NEW/DEL |
userhost-in-names | Stores full user@host from NAMES reply |
server-time | Displays server-provided timestamps on all messages |
message-tags | Full tag support: typing, reactions, replies, bot flags |
batch | Chathistory batches; netsplit/netjoin collapsed to one line |
echo-message | Server echoes sent messages for correct msgids |
labeled-response | Tags requests to correlate responses |
standard-replies | Color-coded FAIL / WARN / NOTE labels |
setname | Change your real name; display others' changes |
| Capability | What rvIRC Does |
|---|---|
monitor | Base presence monitoring for the friends list |
extended-monitor | Extended MONITOR for friend presence tracking |
draft/chathistory | Fetches last N messages on join; :more / :history for older |
draft/read-marker | Sends MARKREAD on buffer switch; syncs across clients |
draft/multiline | Multi-line pastes sent as a single batch |
draft/pre-away | AWAY sent before CAP END on reconnect |
draft/no-implicit-names | Suppresses automatic NAMES on JOIN |
draft/channel-rename | RENAME moves channel in all panes, preserves history |
draft/message-redaction | Redact messages; shows [Message redacted] |
draft/message-edit | Edit messages via EDIT command with (edited) marker |
draft/message-delete | Delete messages; shows [Message deleted] |
draft/account-registration | Register accounts with :register |
draft/extended-isupport | Early ISUPPORT; parses NETWORK and NETWORKICON |
| Tag / Spec | What rvIRC Does |
|---|---|
+reply | Threaded replies — r shows numbers on last 10 messages |
+draft/react | Emoji reactions displayed inline below messages |
+draft/channel-context | Bot DMs with channel context appear in the channel buffer |
+typing | Sends and displays typing indicators |
| Token | What rvIRC Does |
|---|---|
UTF8ONLY | Shows notice when server enforces UTF-8 |
NETWORK | Network name displayed on connect |
NETWORKICON | Network icon URL shown on connect |
WHOX | Extended WHO fetches account names |
STS | Persists TLS upgrade policies |
Type : to enter COMMAND mode. Tab-completion works on command names.
Vim-style modes with familiar navigation.
All config lives in ~/.config/rvIRC/.
| File | Contents |
|---|---|
config.toml | Main config — servers, nickname, preferences |
identity.toml | Persistent X25519 identity keypair (auto-generated) |
known_keys.toml | TOFU key store — peer identity keys, verification status |
friends.toml | Friends list (nicks to MONITOR) |
highlight.toml | Highlight word list |
read_markers.toml | Per-buffer read position |
sts.toml | Persisted STS upgrade policies |
username = "myuser"
nickname = "mynick"
real_name = "My Name"
# alt_nick = "mynick_" # fallback nick if primary is in use
# download_dir = "~/Downloads/" # default save directory for files
# render_images = true # inline image display (default: true)
# offline_friends = "show" # "show" or "hide" offline friends
# notifications = true # desktop notifications (default: true)
# sounds = true # terminal bell (default: true)
[[servers]]
name = "Libera"
host = "irc.libera.chat"
port = 6697
tls = true
# identify_password = "your_password" # NickServ or SASL password
# sasl_mechanism = "plain" # "plain" or "external"
# auto_connect = "yes" # connect on startup
# auto_join = "#rvirc, #rust" # join after identify
# proxy_url = "socks5://127.0.0.1:1080" # SOCKS5 proxy
[[servers]]
name = "Hackint"
host = "irc.hackint.org"
port = 6697
tls = true
End-to-end encryption that works transparently over standard IRC.
Fresh ephemeral X25519 keypairs generated per session. DH shared secret expanded via HKDF-SHA256 into directional keys (rvIRC-dm-init / rvIRC-dm-resp).
ChaCha20-Poly1305 AEAD cipher with directional keys. Each side uses a different key to prevent (key, nonce) reuse. Monotonically increasing nonces for replay protection.
Peer identity keys stored in known_keys.toml with fingerprint, verification status, and timestamps. Key changes trigger a red warning and block the handshake.
6-word Short Authenticated String derived from DH secret + both identity keys. Compare out-of-band with your peer, then :verified to mark as trusted.
X25519 keypair in identity.toml (0600 permissions). Used for TOFU and SAS — not for DH exchange, so forward secrecy is preserved.
:secure → accept popup → key exchange → encrypted chat (🔒 in channel list) → :verify → compare codes → :verified (✔ marker).