Files
dms-chat/README.md
SalastilandClaude Sonnet 5 7f3a1d36cd Restructure QML into views/settings/forms, add popout IPC command
- Move the ~17 top-level QML files into views/, settings/, and forms/
  subdirectories, grouped so cross-directory type references stay minimal
  (only 3 files need an added `import` line). Root now only holds the
  four surfaces plugin.json points at directly.
- Add a `dms ipc call dankChat popout` IPC target to open the floating
  window directly, alongside the existing `toggle`, and document both in
  the README along with the new directory layout.
- Add one line of breathing room between the last message and the
  composer bar via the message ListView's bottomMargin (measured with
  FontMetrics rather than a guessed pixel value).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-09 23:41:07 -04:00

5.1 KiB

dms-irc (Dank Chat)

A Dank Material Shell plugin that brings a unified chat frontend to the shell: IRC, Discord, and Sneedchat (SockChat, the Tor-only XenForo chat feature) today, with XMPP/Matrix/Slack support landing protocol by protocol without frontend changes. The architecture is deliberately service-agnostic - the QML side only ever sees a unified account/buffer/message model, never a protocol-specific concept.

Why two parts

Quickshell's QML runtime only exposes Unix-domain sockets, not raw TCP/TLS, so the actual protocol work can't live in QML. Instead:

  • chatd (chatd-rs/, Rust) speaks each protocol directly and translates it into a small unified JSON model (accounts, buffers, messages) over a Unix socket. It never exposes protocol-specific concepts to the plugin; it speaks the unified model, and each backend module happens to be how that model gets populated for a given service.
  • The QML plugin (top-level *.qml, plugin.json) spawns/supervises chatd and renders whatever it reports: a DankBar status pill, a slideout for quick access, and a floating window for a full chat session.
chatd-rs/               chatd - the Rust daemon, one crate per concern:
  chatd/src/backend/      one module per protocol (irc, discord, sockchat, ...)
  chatd/src/rpc/          the Unix-socket JSON-RPC server
  chatd/src/store.rs      SQLite-backed scrollback persistence
  chatd/src/runtime.rs    protocol-agnostic connection/buffer/message state
*.qml                    the DMS plugin surfaces plugin.json points at directly:
                           daemon supervisor, bar widget, startup check, settings entry
views/                   main chat UI: slideout/popout window, accounts, buffers, messages
settings/                per-protocol settings panels loaded by views/ChatSettings.qml
forms/                   per-protocol account-connect forms loaded by views/AccountsPanel.qml
plugin.json              DMS plugin manifest

Building chatd

cd chatd-rs
cargo build --release

Enable the plugin in DMS (Settings → Plugins, or dms ipc call plugins enable dankChat). StartupCheck.qml verifies the built binary exists at chatd-rs/target/release/chatd before allowing activation.

Opening the chat UI

Besides the DankBar pill (ChatBarWidget.qml), ChatDaemon.qml registers an IpcHandler under the dankChat target for scripting/keybinds:

dms ipc call dankChat toggle   # open/close the slideout (or the floating window, if that's what's open)
dms ipc call dankChat popout   # open (or bring forward) the floating window directly

Protocol backends

  • IRC - TLS with SASL PLAIN, NickServ auto-identify, autojoin.
  • Discord - official cross-device QR login (the same one discord.com/app offers), a real-time gateway client, message edit/delete/reactions/replies sync.
  • Sneedchat (SockChat) - the Tor-only chat built into Kiwi Farms. Runs over an embedded Tor client (or an external SOCKS5 proxy), solves the site's own proof-of-work anti-bot gate, and connects to every configured room simultaneously (one persistent websocket per room, sharing a single login). Supports message edit/delete and avatars (fetched through the same Tor session and cached locally, since the frontend has no route to a .onion host on its own).
  • XMPP/Matrix/Slack - not implemented yet; see the project plan for the milestone list.

Wire protocol

Newline-delimited JSON over a Unix socket at $XDG_RUNTIME_DIR/dms-chat/chatd.sock:

request:  {"id": 1, "method": "sendMessage", "params": {...}}
response: {"id": 1, "result": {...}}  or  {"id": 1, "error": "..."}
push:     {"event": "message", "data": {...}}

Core methods: listAccounts, listBuffers, listProtocols, addAccount, removeAccount, setAccountConnected, joinBuffer, partBuffer, sendMessage, editMessage, deleteMessage, subscribe/unsubscribe, getBacklog (SQLite-backed, persists across chatd restarts). Each protocol also has its own account-creation method (addAccount for IRC, addDiscordAccount, addSockChatAccount, ...).

Push events: message, messageUpdated, messageDeleted, reactionsChanged, presenceChange, bufferListChange, connectionState, notification, plus per-protocol login-flow events (discordLoginQr/discordLoginScanned/ discordLoginResult, sockChatLoginStatus/sockChatLoginResult). message and presenceChange are only delivered to clients that called subscribe for that buffer.

Status

Core loop is verified end to end through the actual DMS-spawned plugin: connect to real IRC networks over TLS with SASL PLAIN auth, log into Discord via QR and Sneedchat via username/password (+ optional TOTP 2FA), list/add accounts, join channels, send/ receive messages through a slideout or floating window, mentions flagged as highlights and pushed as notification events, and scrollback that survives a chatd restart. Not yet built: tab-complete, multi-account grouping in the buffer list, and XMPP/ Matrix/Slack backends. See the project plan for the full milestone list.