- unmatched quotes in scrollback made syntax-ppss see the input line inside a string, so electric-pair-mode inserted a spurious pair when typing a closing double quote - text-mode-style punctuation syntax fixes pairing and skip-over |
||
|---|---|---|
| .github/workflows | ||
| images | ||
| recipes | ||
| tests | ||
| .envrc | ||
| .gitignore | ||
| clatter-actions.el | ||
| clatter-cap.el | ||
| clatter-chathistory.el | ||
| clatter-commands.el | ||
| clatter-completion.el | ||
| clatter-config.el | ||
| clatter-connection.el | ||
| clatter-dcc.el | ||
| clatter-evil.el | ||
| clatter-feed.el | ||
| clatter-format.el | ||
| clatter-handlers.el | ||
| clatter-hl-nicks.el | ||
| clatter-image.el | ||
| clatter-list.el | ||
| clatter-log.el | ||
| clatter-model.el | ||
| clatter-nicklist.el | ||
| clatter-notify.el | ||
| clatter-org.el | ||
| clatter-pals.el | ||
| clatter-protocol.el | ||
| clatter-rawlog.el | ||
| clatter-read-marker.el | ||
| clatter-sasl-scram.el | ||
| clatter-search.el | ||
| clatter-smart.el | ||
| clatter-socks.el | ||
| clatter-soju.el | ||
| clatter-sts.el | ||
| clatter-track.el | ||
| clatter-ui.el | ||
| clatter-url-preview.el | ||
| clatter.el | ||
| GUIDE.org | ||
| LICENSE | ||
| Makefile | ||
| manifest.scm | ||
| README.org | ||
clatter.el
clatter.el - An IRCv3 Client for Emacs
A dedicated, fully IRCv3-compliant IRC client for Emacs. Pure Elisp, no Emacs Lisp dependencies. Buffer per channel, newest message at the top with the input prompt above it, and multi-network support out of the box.
Spiritual successor to CLatter (the Common Lisp TUI client), redesigned from scratch for Emacs.
Full reference: GUIDE.org - slash commands, keybindings, every user option, and the details of SASL, bouncers, proxies and troubleshooting.

Requirements
| Requirement | Notes |
|---|---|
| Emacs 30.1+ | No Emacs Lisp dependencies |
| GnuTLS | Needed for TLS connections; check (gnutls-available-p) |
curl |
Runtime, for async URL title and image fetching |
Most Emacs builds ship with GnuTLS support. If yours does not:
| Platform | Install |
|---|---|
| Debian / Ubuntu | apt install gnutls-bin libgnutls28-dev |
| Fedora / RHEL | dnf install gnutls |
| Arch | pacman -S gnutls |
| macOS (Homebrew) | brew install gnutls |
Installation
From MELPA
clatter is available on MELPA. Add MELPA to your archives if you have not
already, then M-x package-install RET clatter RET:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
Manual (from source)
(add-to-list 'load-path "~/path/to/clatter.el")
(require 'clatter)
(require 'gnutls)
(clatter-setup)
clatter-setup
Loading clatter has no side effects: it installs no global hooks and enables
no features. Call clatter-setup once from your configuration to install the
disconnect and exit cleanup handlers and to turn on the bundled extras. Each
extra is gated by its own option, so set anything you want to change before
calling it:
| Extra | Option | Default |
|---|---|---|
| Activity tracking | clatter-track-enabled |
on |
| Desktop notifications | clatter-notify-enabled |
on |
| Chat history | clatter-chathistory-enabled |
on |
| Read markers | clatter-read-marker-enabled |
on |
| soju bouncer fan-out | clatter-soju-enabled |
on |
| Channel logging | clatter-log-enable |
off |
| URL title preview | clatter-url-preview-enable |
off |
| All-channels feed | clatter-feed-enabled |
off |
Quick Start
(setopt clatter-networks
'(("libera"
:server "irc.libera.chat"
:port 6697
:tls t
:nick "yournick"
:autojoin ("#emacs" "#commonlisp"))))
(clatter-setup)
Then M-x clatter and pick libera. To try clatter without configuring
anything, M-x clatter-quick-connect prompts for a server and nick.
Everything else is a defcustom in the clatter group, so
M-x customize-group RET clatter RET is always the complete option list.
Configuration
Libera.Chat with SASL
Register your nick with NickServ first, then put the account password in
~/.authinfo.gpg and leave :password out of the config:
machine irc.libera.chat login yournick port 6697 password yourpassword
(use-package clatter
:ensure t
:bind (:map clatter-mode-map
("C-c ." . clatter-track-switch)
("C-c :" . clatter-track-list)
("C-c n" . clatter-nicklist-toggle))
:custom
(clatter-networks
'(("Libera.Chat"
:server "irc.libera.chat"
:port 6697
:tls t
:nick "yournick"
:realname "Your Name"
;; 'plain, 'scram-sha-256 or 'external (see GUIDE.org for CertFP)
:sasl plain
:autojoin ("#emacs" "#commonlisp" "#systemcrafters"))
("OFTC"
:server "irc.oftc.net"
:nick "yournick"
:realname "Your Name"
:autojoin ("#debian"))))
:config
(require 'gnutls)
(clatter-setup))
soju bouncer
One entry connects to the bouncer and fans out into a separate connection per
upstream network. :bouncer t with a bare :username makes this a control
connection: clatter negotiates soju.im/bouncer-networks, runs
BOUNCER LISTNETWORKS, and spawns one child connection per network the
bouncer knows about, each named after that network.
(use-package clatter
:ensure t
:custom
(clatter-networks
'(("soju"
:server "soju.example.com"
:port 6697
:tls t
:nick "yournick"
;; Bare bouncer username: fans out to every upstream network.
:username "sojuuser"
:sasl plain
:bouncer t)))
:config
(require 'gnutls)
(clatter-setup))
To bind a single upstream network instead, use the user/network username
form and no fan-out happens:
'(("soju-libera"
:server "soju.example.com" :port 6697 :tls t
:nick "yournick" :username "sojuuser/libera"
:sasl plain :bouncer t))
Notes:
:autojoinis deliberately not propagated to child connections - soju replays your saved JOINs upstream-side.:bouncer talso suppresses NickServ auto-identify and nick reclaim, since the bouncer owns that identity.- The bouncer password is looked up under either the network name (
soju) or the server hostname; see GUIDE.org for the exact auth-source matching rules, which differ from a direct connection.
Everything on
Every optional extra enabled at once, as a starting point to trim down:
(use-package clatter
:ensure t
:custom
(clatter-networks
'(("Libera.Chat"
:server "irc.libera.chat" :port 6697 :tls t
:nick "yournick" :sasl plain
:autojoin ("#emacs"))))
;; Off by default - turn them on.
(clatter-log-enable t) ; log to ~/.emacs.d/clatter/logs/
(clatter-url-preview-enable t) ; fetch and show URL titles
(clatter-feed-enabled t) ; *clatter-feed* live inbox of all channels
(clatter-feed-hide-visible t) ; hide sources you already have open
(clatter-feed-hide-channels '("#bots")) ; denylist, all networks
(clatter-image-enable t) ; inline images (GUI frames only)
(clatter-rawlog-enabled t) ; raw protocol inspector buffers
;; Tweaks to the on-by-default features.
(clatter-track-show-in-clatter-buffers t) ; activity crumbs in every buffer
(clatter-notify-keywords '("emacs" "lisp"))
(clatter-notify-rules '((:target "#emacs" :level mentions :schedule (9 . 22))
(:target "#bots" :level none)))
(clatter-compact-system-messages 'compact) ; terse joins/parts/quits
(clatter-group-messages-by-nick t) ; show a nick once per burst
(clatter-group-messages-gap 0.2) ; slight space between bursts (GUI)
;; Fixed typing row keeps activity crumbs from shifting.
(clatter-typing-indicator-location 'input-separator)
(clatter-track-shorten 4) ; e.g. #systemcrafters -> #syst
(clatter-timestamp-format "%H:%M:%S")
(clatter-timestamp-side 'inline) ; end of line; also left/right/divider
(clatter-timestamp-interval 5) ; minute marks every 5 minutes
(clatter-sender-format "[%nick]") ; nick prefix, e.g. [alice] hey
:config
(require 'gnutls)
(clatter-setup)
;; Not wired into clatter-setup - enable explicitly.
(clatter-dcc-setup)
(with-eval-after-load 'org
(require 'clatter-org)
(clatter-org-setup)))
Features
| Feature | Module | Enabled by |
|---|---|---|
| IRC protocol (RFC 1459/2812), multi-network | clatter-protocol |
always |
| IRCv3 CAP LS 302, message tags, batch, labels | clatter-cap |
always |
| SASL PLAIN, SCRAM-SHA-256, EXTERNAL (CertFP) | clatter-cap |
:sasl per network |
| TLS, client certificates, reconnect with backoff | clatter-connection |
:tls per network (default on) |
| STS - auto-upgrade plaintext to TLS | clatter-sts |
clatter-sts-enable (on) |
| SOCKS5 / Tor proxy, remote DNS, .onion | clatter-socks |
:proxy / :tor t per network |
| soju bouncer fan-out, one buffer set per network | clatter-soju |
:bouncer t + clatter-soju-enabled (on) |
| CHATHISTORY backlog; window-wide playback dividers | clatter-chathistory |
clatter-chathistory-enabled (on) |
| Read markers (MARKREAD) synced across clients | clatter-read-marker |
clatter-read-marker-enabled (on) |
| Mode-line activity tracking, unread counts, mentions | clatter-track |
clatter-track-enabled (on) |
| Desktop notifications with per-channel rules | clatter-notify |
clatter-notify-enabled (on) |
| Nick colorization (theme faces) + clickable URLs | clatter-hl-nicks |
clatter-hl-nicks-enabled (on) |
| Incoming and editable mIRC formatting | clatter-format |
on (C-c C-f while editing) |
Completion for nicks, /commands, #channels |
clatter-completion |
always (TAB, standard CAPF) |
| Message action menu at point | clatter-actions |
always (C-c C-a) |
| Smart noise filtering by signal-to-noise ratio | clatter-smart |
clatter-smart-enabled (on) |
| Non-destructive message suppression | clatter-ui |
clatter-suppress-messages, /suppress |
| Pals, fools and ignore lists (glob patterns) | clatter-pals |
clatter-pals, clatter-fools, /ignore |
| Reply threads and emoji reactions (draft/react) | clatter-ui |
always (/reply, /react) |
| Channel list browser | clatter-list |
/list |
| Nick list sidebar | clatter-nicklist |
clatter-nicklist-toggle |
| All-channels feed; hide visible or listed | clatter-feed |
clatter-feed-enabled (off) |
| Inline / divider timestamp sides, mark interval | clatter-ui |
clatter-timestamp-side, clatter-timestamp-interval |
| Channel logging to file, daily rotation | clatter-log |
clatter-log-enable (off) |
| Full-text search across logs | clatter-search |
/search (requires logging) |
| URL title preview | clatter-url-preview |
clatter-url-preview-enable (off) |
| Inline image preview (GUI frames) | clatter-image |
clatter-image-enable (off) |
| Raw protocol inspector | clatter-rawlog |
clatter-rawlog-enabled (off) |
| DCC file transfer (XDCC receive, resume) | clatter-dcc |
(clatter-dcc-setup) |
| Org links, capture templates, log export | clatter-org |
(clatter-org-setup) |
Keybindings
clatter binds no global keys. Inside a chat buffer RET sends, TAB
completes, M-p / M-n walk the input history, C-c C-f applies IRC
formatting and C-c C-a opens the action menu. The full default keymaps, plus
Evil and vanilla binding examples, are in GUIDE.org.
Companion Packages
Contributors
Thanks to the people who have contributed to clatter.el:
- fmqa (F. Magsarian) - non-destructive message suppression, smart noise filtering, input history, WHOIS numerics, buffer cleanup hooks, CTCP ACTION/NOTICE consolidation with server-time, stricter mention matching, error numeric display, AWAY status broadcast, channel list robustness, keymap consolidation
- trevarj (Trevor Arjeski) - SOCKS5 / Tor proxy support, auth-source server password lookup, left-side timestamps, message filling, fool visibility toggling, theme-aware faces
License
MIT