Open-source project
ulyssa/iamb avatar
ulyssa/iamb

iamb: a Matrix client that behaves like Vim

A Matrix client for Vim addicts

1,311 stars123 forksRustApache-2.0

At a glance

What is it?
iamb is a terminal Matrix client with Vim keybindings, end-to-end encryption, threads, spaces and read receipts, and it renders images as sixels, Kitty or iTerm2 graphics where the terminal allows it and as pixelated blocks where it does not. It installs from crates.io, from source, or from about ten distributions.
Who is it for?
iamb fits a Matrix user who works inside a terminal all day, who wants a client that responds to the keys they already know, and who does not need rich media beyond images.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A chat client with no mouse in sight

iamb is a Matrix client for the terminal that uses Vim keybindings, written in Rust, and the homepage is `iamb.chat`.

The premise is narrow and it is a good one. Instead of a desktop application with a sidebar, a room list and a message pane, you get a modal interface where navigation is done with keys, in the way a Vim user already navigates, and the project describes itself as a Matrix client for Vim addicts.

The implementation choices follow from that. The interface is built on ratatui, the Rust terminal user interface library, and the dependency list in the manifest also includes `linkify` for turning URLs in messages into links, `emojis` for the emoji that Matrix messages carry, `html5ever` and `markup5ever_rcdom` for parsing the HTML that the Matrix specification allows a message to contain, and `clap` with the derive feature for the command line, along with `clap_complete` for the shell completions. The Matrix protocol itself is handled by a client library, and the manifest is careful to include its bundled SQLite feature.

The project is Apache-2.0 licensed, the default branch is `main`, and the last push was on 2026-10-13. The recent releases are v0.0.12 from 2026-09-20, v0.0.11 from 2026-01-20 and v0.0.10 from 2024-08-21, while the manifest carries the version 0.0.13-alpha.1. The version line being at zero is a signal about the project's stage, and it is worth keeping in mind when deciding how much to depend on it.

There is a community room as well, on Matrix at `#iamb:0x.badd.cafe`, and a Snap package in addition to the distribution packages further down this page.

The feature list is a Matrix client's feature list

The supported set is long enough to describe what the client does, and it is worth going through it in groups rather than in order.

The protocol features come first: threads, spaces, E2EE and read receipts. That is the core of the Matrix client experience, and having threads and spaces in a terminal client is unusual enough to be the reason somebody writes one.

Then the messaging features: send Markdown, HTML or plaintext messages, edit, redact and react to messages, create, join and leave rooms, and send and accept room invitations.

Then the interface features that a terminal client has to earn: image previews in terminals that support sixels, Kitty and iTerm2, or pixelated blocks for the ones that do not, and notifications through the terminal bell or the desktop environment.

And then the two that are about the person rather than the protocol: custom keybindings, and multiple profiles, which is the feature that makes a single client usable for a personal account and a work account on different homeservers.

The combination is what gives the project its shape. A terminal client cannot show a rich embed, cannot show a video, and cannot offer a drag and drop attachment, so the client that survives in that environment is the one that gets the protocol features right, the keybindings right and the image handling right. Everything else is a desktop client problem.

The repository reflects that focus. There is a `themes/` directory, a `config.example.toml` and a `config.full.toml` for the two ends of the configuration spectrum, a `docs/` directory for the documentation that is published to the website, an `iamb.desktop` file, and a `rust-toolchain.toml` plus a `.rustfmt.toml`, which are the marks of a project that pins its toolchain and its formatting.

Profiles, one per homeserver, in a TOML file

The configuration is small, and the shape of it follows from Matrix's own model of an account.

A basic configuration lives in `$CONFIG_DIR/iamb/config.toml` and looks like this:

toml
[profiles."example.com"]
user_id = "@user:example.com"

The profile is keyed by the homeserver domain, and it holds the user id. That is enough for a server that publishes the well-known entry, because the client can then ask the domain where the homeserver actually is.

When it is not enough, the second form adds the URL:

toml
[profiles."example.com"]
url = "https://example.com"
user_id = "@user:example.com"

The condition is stated precisely: if the homeserver is located on a different domain than the server part of the `user_id` and you do not have a `/.well-known` entry, then you can explicitly specify the homeserver URL to use.

That is a small piece of the Matrix specification, the well-known entry, and it is the kind of thing that is invisible until it is not, because a client that assumes the domain is the homeserver works for most people and fails for a minority. The documentation here names the case and the fix in two sentences, which is more than most clients do.

The multiple profiles feature then extends the same idea: one configuration file, one section per homeserver, and the same keybindings and themes across all of them.

Building from source, and the features you can compile out

The source installation is a cargo install, and the README then spends a paragraph on the variations, because this is a client that people build rather than install.

shell
cargo install --locked --path .

If you are willing to wait longer on the build, the `release-lto` profile enables link-time optimisation. If you would prefer a smaller binary, the `release-light` profile does the LTO, optimises code generation for smaller output and strips the binary. The `max_level_error` feature also makes sure that any `tracing` logs below the error level have their strings removed during compile time, so that you only get `error` logs.

shell
cargo install --profile release-light --features max_level_error --path .

And the third variation is about linking: adding `--no-default-features` skips the desktop integration, for example clipboard and notifications support, and links against the system's SQLite instead of using a bundled SQLite.

The crate features list makes the same points in one place. `bundled` uses bundled SQLite instead of the system library and is on by default, `desktop` enables desktop notifications and clipboard support and is on by default, the three `max_level` features cut logging verbosity at compile time, and the two `chafa` features select the dynamic or the static library for halfblock rendering.

Two of those deserve comment. The compile-time removal of log strings is a real technique for a client that ships to end users, because a log line you never compile is a log line that cannot leak a token. And the `bundled` versus system SQLite choice is a distribution decision that has to be made early, because it changes what the build needs and what the binary carries.

The manifest also shows a build script that derives the version from the git metadata, through the `vergen-gitcl` build dependency, which is the same pattern that keeps a binary's version honest about which commit it came from.

Ten package managers, and the shape of the matrix

The installation section of this README is longer than the configuration section, and that is a statement about the project's audience.

From crates.io the instruction is `cargo install --locked iamb`, with Rust 1.83.0 or above. From source it is the path install shown earlier. And then the distribution packages, one section each.

Arch Linux has a package in the AUR, installed with `paru iamb-git`, which is the git variant rather than a release variant. FreeBSD has a package in the official repositories, `pkg install iamb`. Gentoo has an ebuild in the community-managed GURU overlay, enabled with `eselect repository enable guru` and `emerge --sync guru`, and then `emerge --ask iamb`. macOS has a Homebrew formula, `brew install iamb`. NetBSD has a package, `pkgin install iamb`. Nix has a flake, `nix profile install "github:ulyssa/iamb"`. openSUSE Tumbleweed has a package, `zypper install iamb`. There is a Snap for Linux distributions that support the packaging system, `snap install iamb`. And there is a Conda package on conda-forge, installed with `pixi global install iamb`.

So there are nine distribution channels plus crates.io and the source build, and a Snap and a Conda package and a Nix flake and an AUR package on top of the official BSD and Linux repository packages.

That coverage is not incidental. A terminal client is the kind of program that people install from the package manager of their operating system rather than from a language ecosystem, because the ecosystem route means a Rust toolchain on a machine that only needs a binary. The Conda entry is the sharpest example, since it covers Linux, macOS and Windows in one channel.

The `PACKAGING.md` file in the repository is where the details of that arrangement live, and the `flake.nix` and `flake.lock` at the root are the Nix side of it.

Where iamb is the wrong tool

The limits are the ones a terminal client has, and they are worth stating before somebody wonders why their favourite chat client is missing a feature.

The first is the medium. A terminal can do sixels, Kitty graphics and iTerm2 images, which is why the client renders previews three different ways, but a terminal cannot show a video, cannot play an audio message, cannot show a rich embed, and cannot show a reaction picker that is not a list of characters. A Matrix room where the conversation happens in links and images will look poor here, and no amount of theming changes that.

The second is the stage of the software. The version line is 0.0.x, and the releases come irregularly, with a gap of about seventeen months between v0.0.10 and v0.0.11. The project describes itself as a client for Vim addicts, which is a clear statement of the audience, and it is also a statement of the size of the team. A Matrix client is infrastructure for some people, and infrastructure that a single maintainer carries is a risk to weigh.

The third is that a terminal client is a different product, not a smaller one. It needs its own keybindings to be good, and the project has a themes directory and a full configuration reference because the interface is custom. Learning it is a cost that a graphical client does not charge.

The alternative, for somebody who wants Matrix and a terminal, is a bridge or a web client with a terminal-oriented interface, which gives the notifications and the rich rendering of a browser at the cost of another service in the path. The alternative for a team that treats the chat client as critical is one of the graphical clients, with the caveat that it needs the graphical tools that a terminal user has chosen not to use. The difference in approach is that iamb optimises for the keyboard and the keyboard only, and that is a deliberate trade rather than a limitation to be apologised for.

Editorial conclusion

iamb fits a Matrix user who works inside a terminal all day, who wants a client that responds to the keys they already know, and who does not need rich media beyond images. It is the wrong choice for a user who needs calls, threads with rich previews or a polished read-receipt UI, and it is the wrong tool for a team that treats a chat client as a critical dependency, since the version line is still 0.0.x. Before adopting it, read the configuration page and set up a profile per homeserver, including the explicit `url` when your server has no `/.well-known` entry, and decide about the `bundled` SQLite feature early, because it decides whether your build carries its own SQLite or links the system one.

Frequently asked questions

How do I install iamb?

From crates.io with `cargo install --locked iamb`, which needs Rust 1.83.0 or above, or from source with `cargo install --locked --path .`. It is also packaged for Arch in the AUR, FreeBSD, Gentoo through the GURU overlay, macOS through Homebrew, NetBSD, Nix, openSUSE Tumbleweed, Snap and Conda.

How do I configure iamb to connect to my homeserver?

Create a file at $CONFIG_DIR/iamb/config.toml with one profile per homeserver, holding the user_id, for example `[profiles."example.com"]` with `user_id = "@user:example.com"`. If the homeserver is on a different domain than the server part of the user_id and there is no /.well-known entry, add an explicit `url` to the profile.

Does iamb support end-to-end encryption?

Yes. The supported features include threads, spaces, E2EE and read receipts, together with editing, redacting and reacting to messages, creating, joining and leaving rooms, and sending and accepting room invitations.

How does iamb display images?

With previews in terminals that support sixels, Kitty or iTerm2, and with pixelated blocks for the terminals that do not. The crate therefore carries chafa-dyn and chafa-static features for halfblock rendering, and the client offers image previews in the first place.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. ulyssa/iamb on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ulyssa-iamb.svg)](https://hysenlabs.com/projects/ulyssa-iamb)

Was this useful?