{"id":45481622,"url":"https://github.com/qntx/xmtp","last_synced_at":"2026-04-18T05:01:33.050Z","repository":{"id":339927112,"uuid":"1159677632","full_name":"qntx/xmtp","owner":"qntx","description":"Safe, ergonomic Rust client SDK for the XMTP messaging protocol.","archived":false,"fork":false,"pushed_at":"2026-04-07T10:25:31.000Z","size":12458,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-07T12:27:15.281Z","etag":null,"topics":["e2e-encryption","ffi","messaging","mls","xmtp"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qntx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"gitctrlx","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"qntx","thanks_dev":null,"custom":null}},"created_at":"2026-02-17T02:49:35.000Z","updated_at":"2026-04-07T10:24:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/qntx/xmtp","commit_stats":null,"previous_names":["qntx/xmtp"],"tags_count":50,"template":false,"template_full_name":null,"purl":"pkg:github/qntx/xmtp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qntx%2Fxmtp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qntx%2Fxmtp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qntx%2Fxmtp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qntx%2Fxmtp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qntx","download_url":"https://codeload.github.com/qntx/xmtp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qntx%2Fxmtp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31957158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["e2e-encryption","ffi","messaging","mls","xmtp"],"created_at":"2026-02-22T16:28:21.916Z","updated_at":"2026-04-18T05:01:32.982Z","avatar_url":"https://github.com/qntx.png","language":"Rust","funding_links":["https://github.com/sponsors/gitctrlx","https://buymeacoffee.com/qntx"],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD033 MD041 MD036 --\u003e\n\n# XMTP\n\n[![CI][ci-badge]][ci-url]\n[![License][license-badge]][license-url]\n[![Rust][rust-badge]][rust-url]\n\n[ci-badge]: https://github.com/qntx/xmtp/actions/workflows/rust.yml/badge.svg\n[ci-url]: https://github.com/qntx/xmtp/actions/workflows/rust.yml\n[license-badge]: https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg\n[license-url]: LICENSE-MIT\n[rust-badge]: https://img.shields.io/badge/rust-edition%202024-orange.svg\n[rust-url]: https://doc.rust-lang.org/edition-guide/\n\n**Safe, ergonomic Rust SDK for the [XMTP](https://xmtp.org) messaging protocol — E2E encrypted messaging via MLS (RFC 9750), with a batteries-included TUI chat client.**\n\nxmtp wraps the official [`libxmtp`](https://github.com/xmtp/libxmtp) FFI layer with idiomatic Rust types, providing a high-level `Client` → `Conversation` → `Message` 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.\n\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"demo.gif\" alt=\"TUI Demo\"/\u003e\n\u003c/div\u003e\n\n## Crates\n\n| Crate | | Description |\n| --- | --- | --- |\n| **[`xmtp`](xmtp/)** | [![crates.io][xmtp-crate]][xmtp-crate-url] [![docs.rs][xmtp-doc]][xmtp-doc-url] | SDK — Client, Conversation, Message, content codecs, ENS, Ledger |\n| **[`xmtp-sys`](xmtp-sys/)** | [![crates.io][sys-crate]][sys-crate-url] [![docs.rs][sys-doc]][sys-doc-url] | Raw FFI bindings to `libxmtp_ffi` static library |\n| **[`xmtp-cli`](xmtp-cli/)** | [![crates.io][cli-crate]][cli-crate-url] | TUI chat client + profile management CLI |\n\n[xmtp-crate]: https://img.shields.io/crates/v/xmtp.svg\n[xmtp-crate-url]: https://crates.io/crates/xmtp\n[sys-crate]: https://img.shields.io/crates/v/xmtp-sys.svg\n[sys-crate-url]: https://crates.io/crates/xmtp-sys\n[cli-crate]: https://img.shields.io/crates/v/xmtp-cli.svg\n[cli-crate-url]: https://crates.io/crates/xmtp-cli\n[xmtp-doc]: https://img.shields.io/docsrs/xmtp.svg\n[xmtp-doc-url]: https://docs.rs/xmtp\n[sys-doc]: https://img.shields.io/docsrs/xmtp-sys.svg\n[sys-doc-url]: https://docs.rs/xmtp-sys\n\n## Quick Start\n\n### Install the CLI\n\n**Shell** (macOS / Linux):\n\n```sh\ncurl -fsSL https://sh.qntx.fun/xmtp | sh\n```\n\n**PowerShell** (Windows):\n\n```powershell\nirm https://sh.qntx.fun/xmtp/ps | iex\n```\n\n### CLI\n\n```bash\n\n# Create a profile (generates a new key, registers with XMTP)\nxmtp new alice\n\n# Create a profile with a Ledger hardware wallet\n# (connect via USB and open the Ethereum app on the device first)\nxmtp new bob --ledger\n\n# Create a profile with an imported private key\nxmtp new carol --import 0xdeadbeef...\n\n# Launch the TUI chat interface\nxmtp              # uses default profile\nxmtp alice        # uses profile \"alice\"\n\n# Profile management\nxmtp list          # list all profiles (* = default)\nxmtp info alice    # show profile details + installations\nxmtp default alice # set default profile\nxmtp remove alice  # delete a profile\nxmtp clear         # delete ALL profiles\n\n# Revoke all other installations (requires wallet signature)\nxmtp revoke alice\n```\n\n### Linking\n\nThe `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](https://docs.rs/xmtp#linking) for the one-time workaround (`build.rs` or `.cargo/config.toml`).\n\n### Library\n\n```rust\nuse xmtp::{Client, Env, AlloySigner};\n\n// Create a client and register identity.\nlet signer = AlloySigner::random()?;\nlet client = Client::builder()\n    .env(Env::Dev)\n    .db_path(\"./alice.db3\")\n    .build(\u0026signer)?;\n\n// Send a DM.\nlet conv = client.dm(\u0026\"0xBob...\".into())?;\nconv.send_text(\"hello from Rust\")?;\n\n// List conversations.\nlet convs = client.list_conversations(\u0026Default::default())?;\nfor c in \u0026convs {\n    println!(\"{}: {}\", c.id()?, c.name().unwrap_or_default());\n}\n```\n\n## Architecture\n\n- **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.\n- **xmtp-sys** — Auto-generated bindings from `xmtp_ffi.h`. Downloads pre-built static libraries at build time. No `libclang` required for end users.\n- **xmtp-cli** — Profile-based TUI chat client. Profiles persist configuration (environment, signer type, wallet address) in platform data directories. Signer is only required for identity-changing operations (`new`, `revoke`); TUI and `info` operate without it.\n\n## Feature Flags\n\n### `xmtp` crate\n\n| Feature | Description |\n| --- | --- |\n| `content` | Content type codecs (text, reactions, replies, attachments, read receipts) — enabled by default |\n| `alloy` | Local private key signer via `alloy-signer-local` |\n| `ledger` | Ledger hardware wallet signer via `alloy-signer-ledger` |\n| `ens` | ENS name resolution via `alloy-ens` + `alloy-provider` |\n\n\u003e **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](https://primary.ens.domains/). Without it, the app displays your truncated address instead.\n\n### `xmtp-sys` crate\n\n| Feature | Description |\n| --- | --- |\n| `regenerate` | Re-generate bindings from `xmtp_ffi.h` at build time (requires `libclang`) |\n\n## XMTP Protocol Overview\n\n### Identity Model\n\nXMTP V3 uses [MLS (RFC 9750)](https://www.rfc-editor.org/rfc/rfc9750.html) 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).\n\n```text\nInbox ID\n ├── Identity (EOA / Smart Contract Wallet / Passkey)\n │    └── Installation 1  ← unique key pair, stored in local DB\n │    └── Installation 2  ← independent key pair, separate DB\n │    └── ...  (up to 10 per identity)\n └── Identity 2\n      └── ...\n```\n\n### Two-Tier Key Architecture\n\nXMTP separates **identity-level operations** (rare, high-privilege) from **messaging operations** (frequent, automated) using two distinct key tiers:\n\n**Wallet key** (EOA private key / hardware wallet / smart contract wallet) — used exclusively for identity mutations that alter the on-chain association graph:\n\n| Operation | When | Signers Required |\n| --- | --- | --- |\n| Create inbox (register) | First launch | Wallet |\n| Add identity to inbox | Linking a new wallet | Existing wallet + new wallet |\n| Remove identity from inbox | Unlinking a wallet | Wallet |\n| Revoke installations | Device lost/compromised | Wallet |\n| Change recovery identifier | Security rotation | Wallet |\n\n**Installation key** (ed25519 key pair, auto-generated, stored in the local encrypted database) — handles everything else with zero user interaction:\n\n- Sending and receiving messages\n- Creating / joining conversations\n- Syncing conversations, messages, and preferences\n- Streaming real-time updates\n- Managing consent state\n- Group admin operations (add/remove members, update metadata)\n\n\u003e 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.\n\n### Compromise \u0026 Recovery Model\n\nEach installation holds **independent MLS epoch keys**. This architecture provides strong security guarantees through MLS forward secrecy and post-compromise security:\n\n| Scenario | Messages before compromise | Messages during compromise | Messages after revoke + new installation |\n| --- | --- | --- | --- |\n| Single installation compromised | Safe (on other devices) | Exposed (on that device only) | Safe (new keys, new epoch) |\n| Wallet key compromised | Safe (cannot decrypt) | N/A (wallet key ≠ message key) | Rotate wallet, revoke installations |\n| All installations lost | Unrecoverable* | N/A | Fresh start, no history |\n\n\\* Unless another installation was online to complete [History Transfer](#history-transfer) beforehand.\n\n**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.\n\n### Message Synchronization\n\nEvery installation maintains independent MLS state. Understanding what syncs automatically and what requires explicit action is critical:\n\n| Scenario | Automatic? | Mechanism |\n| --- | --- | --- |\n| New messages across existing installations | Yes | MLS group — all member installations decrypt in real time |\n| New conversations (invites/welcomes) | Yes | `conversations.sync()` or `syncAll()` fetches new welcomes |\n| Consent \u0026 preference state | Yes | Preference sync via a hidden sync group between your devices |\n| **Historical messages on a new installation** | **No** | **History Transfer — requires an existing installation online** |\n\nEach 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.\n\n### History Transfer\n\nA new installation cannot decrypt messages sent before it joined the MLS group. To access historical messages, XMTP provides [History Transfer](https://docs.xmtp.org/chat-apps/list-stream-sync/history-sync) (defined in [XIP-64](https://github.com/xmtp/XIPs/blob/main/XIPs/xip-64-history-transfer.md)):\n\n1. **New device** requests history via the sync group (`initiateHistoryRequest`)\n2. **Existing device** (must be online) prepares and uploads an encrypted archive to the history server\n3. **New device** downloads and imports the archive into its local database\n\nKey details:\n\n- History transfer is **enabled by default** — the SDK sets `historySyncUrl` to an XMTP Labs-hosted server based on your `env` setting\n- The encrypted payload is stored on the history server for **24 hours** only\n- The archive includes conversations, messages, consent state, and HMAC keys\n- **If all installations are lost**, message history is unrecoverable (no server-side plaintext storage)\n- You can self-host the history server or disable it by setting `historySyncUrl` to an empty string\n\n## Supported Platforms\n\n| Target | Status |\n| --- | --- |\n| `x86_64-unknown-linux-gnu` | ✅ |\n| `aarch64-unknown-linux-gnu` | ✅ |\n| `aarch64-apple-darwin` | ✅ |\n| `x86_64-pc-windows-msvc` | ✅ |\n| `aarch64-pc-windows-msvc` | ✅ |\n\n## Security\n\nThis library has **not** been independently audited. See [SECURITY.md](SECURITY.md) for full disclaimer, supported versions, and vulnerability reporting instructions.\n\n- All FFI calls are bounds-checked and null-pointer guarded\n- Private keys remain in memory only as long as needed; Ledger keys never leave the device\n- No key material is logged or persisted by the SDK (key files are managed by the CLI layer)\n- E2E encryption handled by libxmtp's MLS implementation (RFC 9750)\n\n## License\n\nLicensed under either of:\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or \u003chttps://www.apache.org/licenses/LICENSE-2.0\u003e)\n- MIT License ([LICENSE-MIT](LICENSE-MIT) or \u003chttps://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\nUnless 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.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\nA **[QNTX](https://qntx.fun)** open-source project.\n\n\u003ca href=\"https://qntx.fun\"\u003e\u003cimg alt=\"QNTX\" width=\"369\" src=\"https://raw.githubusercontent.com/qntx/.github/main/profile/qntx-banner.svg\" /\u003e\u003c/a\u003e\n\n\u003c!--prettier-ignore--\u003e\nCode is law. We write both.\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqntx%2Fxmtp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqntx%2Fxmtp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqntx%2Fxmtp/lists"}