termisations

A terminal XMPP client for engineers who run the server, not just chat on it.

attributes

role
author
repo
https://github.com/tzx1z/termisations

Solution

A raw XMPP stream panel sits next to the message feed, the interception happens at the socket level, and every message carries badges for the extensions involved. Secrets are redacted by default: SASL, OMEMO keys and payloads, PEP bundles, signatures in upload links.

All the work is done through slash commands, and the command registry is data from which help, completion and the palette are built automatically. The client connects to a real server and can also run on an emulated stream: the interface is identical in both modes.

  • RAW XML panel: a 2000-stanza ring buffer, batched rendering, syntax highlighting, filtering by stanza type, address and namespace, a 500 stanzas per second budget
  • Protocol: XEP-0198 with stream resumption, 0280 Carbons, 0313 MAM with paging, 0359, 0384 OMEMO, 0045 MUC, 0363 upload, 0424, 0444, 0461
  • Security: redaction in the log, 0700 directories and 0600 files, a separate profile per account, the password kept out of the config - keyring or an external command
  • Batch mode for cron and pipelines: sends a message or a file with no interface, using the same encryption as the conversation

Stack

Python 3.12+, Textual, slixmpp, SQLite in WAL mode, asyncio, uv. AGPL-3.0-only, chosen because of the OMEMO dependencies.

Outcome

mypy --strict, ruff, 930 tests, a live suite against a real ejabberd, a module contract kept as a separate document.

All projects