kith

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: MIT

README

kith

A keyboard-driven Matrix client for the terminal — with a daemon that keeps working when the terminal is closed.

CI Go

kith is a full daily-driver Matrix client: end-to-end encryption, spaces, threads, reactions, media and voice notes, in a three-pane terminal UI (spaces rail · room list · timeline). What sets it apart is what happens around the chat window — an always-on daemon, an offline index of everything you have received, and a local rules engine that decides what deserves your attention.

Status: early, usable. kith is used every day, but it is pre-1.0: expect rough edges and configuration changes between releases. Linux is the primary platform; macOS builds are produced but less exercised.

Highlights

It keeps working when the terminal is closed

kithd owns the Matrix session, the sync loop, the local cache and the crypto store. The TUI is a thin client that attaches over a unix socket. Close it and notifications still arrive, failed sends are retried, scheduled messages go out on time, and (if you opt in) verification codes are copied to your clipboard — with nothing open. Architecture →

Search everything, offline, instantly

Every message — encrypted ones included, once decrypted — lands in a local SQLite cache with a full-text index. Search the room, the group you are in or the whole account, filter with from:alice since:7d until:2026-08-31, and jump straight into the conversation at the hit. The same index gives you a list of every message that mentions you (@) and every message with a file (gf) — including ones you have already read — plus your starred messages and a watch list of tracked words highlighted wherever anyone says them. Search →

Notifications that you decide, not the server

Notification rules live on your machine: per room, space, sender or thread, with daily quiet hours, timed and scoped do-not-disturb, per-sound overrides, and per-room rate limiting that folds a burst into one "12 new messages" summary. The narrowest rule wins, so "the on-call room gets through at night" is just a rule. When something is quiet, W shows the whole rule chain and marks the one that decided. Notifications →

Spam is a place, not a mute

A conversation you mark — or one your content filters catch — leaves the group it was in: out of the rail, out of every unread count, out of notifications, yet still readable, searchable and answerable. Promotion rules are individually switchable, only you demote, /caught previews what a filter would catch over your history before you trust it, and /why names the rule and filter behind a verdict. Filter verdicts are stored in your account data, so they survive a cache rebuild and reach your other machines. Spam →

Help writing, in the languages you actually use

Spell-checking as you type with every installed dictionary at once — mixed-language messages just work, with rare-word detection for languages whose dictionaries accept almost anything. Word and phrase completion is ranked by what has really been said in that room and shown as inline ghost text, optionally finished by a small local model that the daemon runs on demand and never sends anywhere. Point [assist] at any OpenAI-compatible endpoint for /summary of what you missed, :todo extraction and thread naming — it sees only the rooms you allow, never an encrypted one unless you say so, and alt+m shows exactly what a request would send before it goes. Composer → · Assist →

Your AI assistant can read your chats — under your rules

kith-mcp is a Model Context Protocol server over the same daemon. Any MCP-capable assistant can list and search rooms, find people and the rooms they share, read around a message and summarise what is unread — with encrypted rooms decrypted locally and message reads scoped by an [agent.read] allow/deny list. It can also write, within a separate [agent.write] scope that never exceeds what it may read, but the assistant does not get to choose how: rooms you list are sent to, everything else gets a draft in its composer marked with who wrote it, a per-room cooldown stops loops, and every action is recorded in a ledger (kith --agent-log). MCP →

The scope is only as strict as the facts it is decided from. Some of those facts are other people's: a space's admins decide which rooms are in it, and a DM carries its peer's chosen name. The scope also cannot stop an assistant's provider from seeing what you let the assistant read. If you need a boundary no one else can move, run your own homeserver, name rooms by ID, and use a local model.

Your scripts are slash commands

Drop an executable into ~/.config/kith/commands/ and it is a slash command — a /standup that drafts your standup, a /call that posts a meeting link. Scripts get the room, the message under the cursor or recent history as input, and their output goes where you say: the composer for review, straight to the room, a pager, the clipboard. Bind one to a key if you like. No shell in the chain, and a timeout. Commands →

Pure Go, single binaries, real encryption

Full end-to-end encryption via mautrix-go's pure-Go crypto and a pure-Go SQLite driver: CGO_ENABLED=0, no libolm, clean cross-compiles. Interactive SAS verification, server-side key backup that the daemon keeps filled, and key export/import in the standard format, interoperable with other clients. Releases are signed and ship with build attestations and an SBOM. Encryption →

And everything else you expect

  • A spaces rail with synthetic All / DMs / Unread / Drafts groups, plus Invites, Pinned, Spam and Archived when they apply; a room-list sort you define as a chain
  • Threads, replies, reactions (frequency-ranked), edits, deletions, stickers, stars, and an edit/deletion history view
  • Images drawn in text, a voice-note player bar (mpv or VLC) with speed remembered per person, video hand-off, attachments with captions
  • Drafts that stay with their room across restarts; a send queue; scheduled messages
  • Markdown on send and on receive; right-to-left and bidirectional text done properly
  • Read receipts and typing notices you control, per space, room or person
  • A ctrl+k switcher, per-room key sequences (B), ctrl+o/ctrl+i history, and gl to follow a Matrix link without leaving the client
  • Fully configurable keybindings with generated help (a bad keymap never stops the client from starting), themes, multiple accounts
  • Starts and serves cached history even when the homeserver is down
  • matrix: / matrix.to link handling from the desktop

Quick start

Install a package, or build from source:

System Install
Arch Linux yay -S kith-bin
Debian, Ubuntu, Fedora, Alpine the .deb, .rpm or .apk from Releases
macOS brew install --cask eugeneshtoka/tap/kith
Nix nix profile install github:EugeneShtoka/kith
From source (Go 1.26.3+) git clone https://github.com/EugeneShtoka/kith && cd kith && make install
kith login     # prompts for the password; only the access token is kept, in the OS keyring
make deploy      # from a clone: enable and start the daemon under systemd
                 # (a package: systemctl --user enable --now kithd)
kith           # attach and go

If no daemon is running, kith starts one itself and tells you. Press ? inside the client for every keybinding, and , for settings.

Full walkthrough, per platform, with profiles and encryption setup: Getting started.

Documentation

Using kith Getting started · Using the client · Keybindings · Search
Features Notifications · Spam · Composer · Assist (LLM) · Commands · MCP server · Encryption
Reference Configuration · Command line · Troubleshooting
Project Architecture · Database · Roadmap · Contributing · Security

The complete, annotated configuration reference is built in: kith --print-config.

How it is built

  • Elm architecture on Bubble Tea v2.
  • Enforced layer boundaries — the UI depends only on an api.Backend interface, never on the Matrix SDK; depguard fails the build if a boundary is crossed.
  • One owner for the crypto state — the daemon takes an exclusive lock before opening any store, because two processes sharing one device's olm/megolm state corrupt it. There is deliberately no in-process fallback.
  • Tested and gated — race-tested, coverage floors, lint, vulnerability and secret scanning, and architecture checks on every push. make check runs them locally.

See ARCHITECTURE.md and CONTRIBUTING.md.

Contributing

Issues and pull requests are welcome — please read CONTRIBUTING.md first. Security issues: see SECURITY.md. This project follows a Code of Conduct.

License

MIT © 2026 Eugene Shtoka

Directories

Path Synopsis
cmd
emoji-probe command
Command emoji-probe checks that every emoji kith offers occupies as many columns on screen as the client (uniseg) thinks: a one-column disagreement wraps a pane row and shifts everything below, and only the terminal itself can answer.
Command emoji-probe checks that every emoji kith offers occupies as many columns on screen as the client (uniseg) thinks: a one-column disagreement wraps a pane row and shifts everything below, and only the terminal itself can answer.
kith command
Command kith is a terminal UI Matrix client.
Command kith is a terminal UI Matrix client.
kith-mcp command
Command kith-mcp exposes this account's Matrix history to an AI assistant over the Model Context Protocol, as a third client of the kithd daemon: no Matrix code of its own, decrypted rooms from the daemon's cache, never a key.
Command kith-mcp exposes this account's Matrix history to an AI assistant over the Model Context Protocol, as a third client of the kithd daemon: no Matrix code of its own, decrypted rooms from the daemon's cache, never a key.
kithd command
Command kithd is kith's daemon: it owns the Matrix session, the /sync loop, the cache and the E2EE crypto store, and serves them to clients over a unix socket.
Command kithd is kith's daemon: it owns the Matrix session, the /sync loop, the cache and the E2EE crypto store, and serves them to clients over a unix socket.
internal
agent
Package agent keeps the append-only JSON-lines ledger of messages an assistant (kith-mcp) sent as this account.
Package agent keeps the append-only JSON-lines ledger of messages an assistant (kith-mcp) sent as this account.
api
Package api defines the Backend interface the TUI talks to.
Package api defines the Backend interface the TUI talks to.
api/backend/v1/protoconv
Package protoconv maps domain types to and from the backend v1 wire types, shared by the daemon's handlers and the Remote client.
Package protoconv maps domain types to and from the backend v1 wire types, shared by the daemon's handlers and the Remote client.
apitest
Package apitest provides a do-nothing api.Backend for tests to embed and override selectively.
Package apitest provides a do-nothing api.Backend for tests to embed and override selectively.
audio
Package audio plays one attachment at a time with pause, seek and speed control.
Package audio plays one attachment at a time with pause, seek and speed control.
buildinfo
Package buildinfo exposes version metadata, injected by -ldflags -X in release builds and otherwise read from the module build info ("dev" when absent).
Package buildinfo exposes version metadata, injected by -ldflags -X in release builds and otherwise read from the module build info ("dev" when absent).
config
Package config loads kith's XDG-compliant TOML configuration.
Package config loads kith's XDG-compliant TOML configuration.
daemon
Package daemon holds both sides of the kithd wire: Serve hosts an api.Backend over a unix socket via Connect, and Remote is the api.Backend the TUI runs against.
Package daemon holds both sides of the kithd wire: Serve hosts an api.Backend over a unix socket via Connect, and Remote is the api.Backend the TUI runs against.
db
Package db is kith's local SQLite client cache (pure-Go modernc.org/sqlite), returning domain types.
Package db is kith's local SQLite client cache (pure-Go modernc.org/sqlite), returning domain types.
domain
Package domain holds kith's pure Matrix vocabulary: value types and the logic over them (display-name resolution, sorting) with no I/O, no Matrix SDK, and no TUI framework.
Package domain holds kith's pure Matrix vocabulary: value types and the logic over them (display-name resolution, sorting) with no I/O, no Matrix SDK, and no TUI framework.
filedialog
Package filedialog asks the XDG desktop portal to choose a path.
Package filedialog asks the XDG desktop portal to choose a path.
focus
Package focus brings the browser forward after a link was handed to it.
Package focus brings the browser forward after a link was handed to it.
launch
Package launch opens a terminal to handle a desktop-clicked link when no kith is running: a new tab in a running terminal first, a new window if that exits non-zero.
Package launch opens a terminal to handle a desktop-clicked link when no kith is running: a new tab in a running terminal first, a new window if that exits non-zero.
llamacpp
Package llamacpp reads a local language model as a next-token distribution.
Package llamacpp reads a local language model as a next-token distribution.
llamacpp/models
Package models is the catalog of completion models kith can install: what each is, where it comes from and whether it is on disk.
Package models is the catalog of completion models kith can install: what each is, where it comes from and whether it is on disk.
llm
Package llm talks to one OpenAI-compatible chat endpoint.
Package llm talks to one OpenAI-compatible chat endpoint.
logging
Package logging builds the one log format all three binaries share: log/slog's text handler, with a level from flag, env or config, no timestamps under journald (it stamps every line itself), and secrets scrubbed from every value on the way out.
Package logging builds the one log format all three binaries share: log/slog's text handler, with a level from flag, env or config, no timestamps under journald (it stamps every line itself), and secrets scrubbed from every value on the way out.
matrix
Package matrix adapts mautrix-go to api.Backend.
Package matrix adapts mautrix-go to api.Backend.
media
Package media is the client's own cache of timeline images: the originals as files an external viewer can open, and the decoded, downsampled renderings so reopening a room doesn't re-decode.
Package media is the client's own cache of timeline images: the originals as files an external viewer can open, and the decoded, downsampled renderings so reopening a room doesn't re-decode.
modelsetup
Package modelsetup derives the daemon's model layer from the config: the prompts the remote model runs and the local completion server's settings.
Package modelsetup derives the daemon's model layer from the config: the prompts the remote model runs and the local completion server's settings.
notify
Package notify delivers desktop notifications to the user.
Package notify delivers desktop notifications to the user.
richtext
Package richtext is the single table of Matrix HTML formatting this client understands.
Package richtext is the single table of Matrix HTML formatting this client understands.
schedule
Package schedule is the on-disk queue of messages to send later.
Package schedule is the on-disk queue of messages to send later.
session
Package session persists login credentials in the OS secret store (via go-keyring, no cgo).
Package session persists login credentials in the OS secret store (via go-keyring, no cgo).
setup
Package setup turns a configuration into the structures a running program reads: notification rules, notifier sinks, the code detector's shape and scope.
Package setup turns a configuration into the structures a running program reads: notification rules, notifier sinks, the code detector's shape and scope.
spell
Package spell checks what you are writing against real dictionaries.
Package spell checks what you are writing against real dictionaries.
theme
Package theme is kith's visual palette and the lipgloss styles built from it.
Package theme is kith's visual palette and the lipgloss styles built from it.
themespec
Package themespec is the theme config as data: the built-in presets and the per-role overrides, validated, as the color strings the config writes ("#00aaff", or an ANSI slot like "12").
Package themespec is the theme config as data: the built-in presets and the per-role overrides, validated, as the color strings the config writes ("#00aaff", or an ANSI slot like "12").
tui
Package tui is kith's presentation layer: a Bubble Tea program that talks to the world only through api.Backend.
Package tui is kith's presentation layer: a Bubble Tea program that talks to the world only through api.Backend.
vocab
Package vocab ranks word completions from what was said recently, counted in memory.
Package vocab ranks word completions from what was said recently, counted in memory.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL