Skip to content

XMTP

CILicenseRust

Safe, ergonomic Rust SDK for the XMTP messaging protocol — E2E encrypted messaging via MLS (RFC 9750), with a batteries-included TUI chat client.

xmtp wraps the official libxmtp FFI layer with idiomatic Rust types, providing a high-level ClientConversationMessage API for DMs, groups, content types, identity management, ENS resolution, and real-time streaming. The CLI crate ships a full-featured terminal chat interface with profile-based persistent configuration.

TUI Demo

Crates

CrateDescription
xmtpcrates.iodocs.rsSDK — Client, Conversation, Message, content codecs, ENS, Ledger
xmtp-syscrates.iodocs.rsRaw FFI bindings to libxmtp_ffi static library
xmtp-clicrates.ioTUI chat client + profile management CLI

Quick Start

Install the CLI

Shell (macOS / Linux):

curl -fsSL https://sh.qntx.org/xmtp | sh

PowerShell (Windows):

irm https://sh.qntx.org/xmtp/ps | iex

CLI

# Create a profile (generates a new key, encrypted local DB, registers with XMTP)
xmtp new alice
# Create a profile with a Ledger hardware wallet# (connect via USB and open the Ethereum app on the device first)
xmtp new bob --ledger
# Create a profile with an imported private key
xmtp new carol --import 0xdeadbeef...
# Launch the TUI chat interface
xmtp # uses default profile
xmtp alice # uses profile "alice"# Profile management
xmtp list # list all profiles (* = default)
xmtp info alice # show profile details + installations
xmtp default alice # set default profile
xmtp remove alice # delete a profile
xmtp clear # delete ALL profiles# Revoke all other installations (requires wallet signature)
xmtp revoke alice
# Request history from another installation (URL from env; override with --history-url)
xmtp sync
xmtp sync --history-url https://message-history.dev.ephemera.network
# Local device-sync archives (encrypted with db.key unless --key is given)
xmtp archive create ./alice.xmtp
xmtp archive import ./alice.xmtp
xmtp archive metadata ./alice.xmtp
xmtp archive list
xmtp archive process
xmtp archive send PIN
# FFI tracing: RUST_LOG=debug xmtp …# xmtp --version includes the libxmtp version

Linking

The xmtp-sys crate links a pre-built Rust staticlib that bundles its own copy of std, which causes duplicate symbol errors when building a Rust binary. See the xmtp crate docs for the one-time workaround (build.rs or .cargo/config.toml).

Library

use xmtp::{Client,Env,AlloySigner};// Create a client and register identity.let signer = AlloySigner::random()?;let client = Client::builder().env(Env::Dev).db_path("./alice.db3").build(&signer)?;// Send a DM.let conv = client.dm(&"0xBob...".into())?;
conv.send_text("hello from Rust")?;// List conversations.let convs = client.list_conversations(&Default::default())?;for c in&convs {println!("{}: {}", c.id()?, c.name().unwrap_or_default());}

Architecture

  • xmtp — High-level SDK. Owns all unsafe FFI calls behind safe types. Client is built via ClientBuilder with optional signer, ENS resolver, and environment selection. Conversation provides send/receive/sync/metadata/consent operations. Content codecs handle text, markdown, reactions, replies, attachments, and read receipts.
  • xmtp-sys — Auto-generated bindings from xmtp_ffi.h. Downloads pre-built static libraries at build time. No libclang required for end users.
  • xmtp-cli — Profile-based TUI chat client. Profiles persist configuration (environment, signer type, wallet address) in platform data directories. New profiles always encrypt the local DB (db.key mode 0600, profile dir 0700). Unencrypted profiles are refused. Signer is only required for identity-changing operations (new, revoke); TUI and info operate without it.

Feature Flags

xmtp crate

FeatureDescription
contentContent type codecs (text, reactions, replies, attachments, read receipts) — enabled by default
alloyLocal private key signer via alloy-signer-local
ledgerLedger hardware wallet signer via alloy-signer-ledger
ensENS name resolution via alloy-ens + alloy-provider

ENS display names — To show your .eth name in the TUI header and conversation list, you must set a Primary Name (reverse record) for your wallet address at primary.ens.domains. Without it, the app displays your truncated address instead.

xmtp-sys crate

FeatureDescription
regenerateRe-generate bindings from xmtp_ffi.h at build time (requires libclang)

XMTP Protocol Overview

Identity Model

XMTP V3 uses MLS (RFC 9750) for E2E encryption. Each user is identified by an Inbox ID, which can own multiple blockchain identities, each with up to 10 installations (devices/apps).

Inbox ID
├── Identity (EOA / Smart Contract Wallet / Passkey)
│ └── Installation 1 ← unique key pair, stored in local DB
│ └── Installation 2 ← independent key pair, separate DB
│ └── ... (up to 10 per identity)
└── Identity 2
└── ...

Two-Tier Key Architecture

XMTP separates identity-level operations (rare, high-privilege) from messaging operations (frequent, automated) using two distinct key tiers:

Wallet key (EOA private key / hardware wallet / smart contract wallet) — used exclusively for identity mutations that alter the on-chain association graph:

OperationWhenSigners Required
Create inbox (register)First launchWallet
Add identity to inboxLinking a new walletExisting wallet + new wallet
Remove identity from inboxUnlinking a walletWallet
Revoke installationsDevice lost/compromisedWallet
Change recovery identifierSecurity rotationWallet

Installation key (ed25519 key pair, auto-generated, stored in the local encrypted database) — handles everything else with zero user interaction:

  • Sending and receiving messages
  • Creating / joining conversations
  • Syncing conversations, messages, and preferences
  • Streaming real-time updates
  • Managing consent state
  • Group admin operations (add/remove members, update metadata)

After initial registration, the wallet key is never needed for day-to-day messaging. For CLI users with Ledger hardware wallets, this means the device only needs to be connected for xmtp new and xmtp revoke. Make sure the Ledger is connected via USB with the Ethereum app open before running those commands.

Compromise & Recovery Model

Each installation holds independent MLS epoch keys. This architecture provides strong security guarantees through MLS forward secrecy and post-compromise security:

ScenarioMessages before compromiseMessages during compromiseMessages after revoke + new installation
Single installation compromisedSafe (on other devices)Exposed (on that device only)Safe (new keys, new epoch)
Wallet key compromisedSafe (cannot decrypt)N/A (wallet key ≠ message key)Rotate wallet, revoke installations
All installations lostUnrecoverable*N/AFresh start, no history

* Unless another installation was online to complete History Transfer beforehand.

Key insight: compromising an installation key exposes only messages decrypted by that specific installation during the compromise window. The attacker cannot decrypt messages on other devices, nor future messages after the compromised installation is revoked — because MLS generates fresh epoch keys that exclude the revoked installation.

Message Synchronization

Every installation maintains independent MLS state. Understanding what syncs automatically and what requires explicit action is critical:

ScenarioAutomatic?Mechanism
New messages across existing installationsYesMLS group — all member installations decrypt in real time
New conversations (invites/welcomes)Yesconversations.sync() or syncAll() fetches new welcomes
Consent & preference stateYesPreference sync via a hidden sync group between your devices
Historical messages on a new installationNoHistory Transfer — requires an existing installation online

Each installation tracks a cursor (bookmark) per conversation. sync() only fetches messages after the cursor, making incremental sync efficient. Streaming (stream()) delivers messages in real time but does not advance the cursor — only sync() does.

History Transfer

A new installation cannot decrypt messages sent before it joined the MLS group. To access historical messages, XMTP provides History Transfer (defined in XIP-64):

  1. New device calls Client::send_sync_request (URL from Env::history_sync_url() or ClientBuilder::history_sync_url)
  2. Existing device (must be online) prepares and uploads an encrypted archive to the history server
  3. New device downloads and imports the archive (process_sync_archive / import_archive)

Key details:

  • ClientBuilder::build() does not send a history-sync request. Call send_sync_request (or send_sync_request_to) explicitly.
  • Default server URL is Env::history_sync_url() (XMTP Labs hosts per env). Override with ClientBuilder::history_sync_url or send_sync_request_to.
  • Disable the device-sync worker with ClientBuilder::disable_device_sync(). Empty-string URL is not a disable switch.
  • The encrypted payload is stored on the history server for 24 hours only
  • The archive includes conversations, messages, consent state, and HMAC keys
  • If all installations are lost, message history is unrecoverable (no server-side plaintext storage)

Supported Platforms

TargetStatus
x86_64-unknown-linux-gnu
aarch64-unknown-linux-gnu
aarch64-apple-darwin
x86_64-pc-windows-msvc
aarch64-pc-windows-msvc

Intel macOS (x86_64-apple-darwin) is unsupported.

Security

This library has not been independently audited. See SECURITY.md for full disclaimer, supported versions, and vulnerability reporting instructions.

  • All FFI calls are bounds-checked and null-pointer guarded
  • Private keys remain in memory only as long as needed; Ledger keys never leave the device
  • No key material is logged or persisted by the SDK (key files are managed by the CLI layer)
  • E2E encryption handled by libxmtp's MLS implementation (RFC 9750)

License

Licensed under either of:

at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project shall be dual-licensed as above, without any additional terms or conditions.


A QuantX open-source project.

QuantX

Code is law. We write both.

About

Safe, ergonomic Rust client SDK for the XMTP messaging protocol.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

38 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Contributors

Languages