# Ekx Xmtp

> Wallet-to-wallet messaging with XMTP, evaluated but not shipped — client creation from a signer, conversations and streams, consent, and what it is and is not suited for. Use when building in-app chat between wallet addresses, wallet-addressed notifications, or evaluating XMTP against a normal database-backed chat.

- Skill: `ekinoxis-evm/ekx-xmtp` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ekinoxis-evm/ekx-xmtp`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ekinoxis-evm/ekx-xmtp/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Ekinoxis-evm (https://skillmd.com/u/ekinoxis-evm)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/ekinoxis-evm/ekx-xmtp

---


# XMTP

Wallet-to-wallet messaging, via the **`xmtp-docs` MCP server**.

Status: **evaluated, not shipped.** No XMTP package appears in any `package.json`.
This file exists so the next person does not re-derive the evaluation.

Docs: https://docs.xmtp.org

---

## What it is

End-to-end encrypted messaging addressed by wallet address rather than by account.
Messages are portable across any XMTP client, and the identity is the wallet — no
signup, no server holding the thread.

---

## Where it fits us

**Good fit:** notifying a bidder that they were outbid, or a player that a challenge
resolved — addressed to a wallet, delivered to whatever client they use, no email or
phone number collected.

**Bad fit:** the in-app chat itself. A `conversations.list()` on load, encrypted local
state, and a signature prompt to initialise are all worse UX than a Supabase table
with realtime for users who are already authenticated with Privy.

**The decision:** Supabase realtime for in-app chat; XMTP remains
the right answer for *outbound wallet-addressed notification* if that becomes a
requirement.

---

## Sketch

```ts
import { Client } from "@xmtp/browser-sdk";

const client = await Client.create(signer, { env: "production" });

const dm = await client.conversations.newDm(recipientAddress);
await dm.send("Tu puja fue superada.");

for await (const message of await client.conversations.streamAllMessages()) {
  if (message.senderInboxId === client.inboxId) continue;   // skip your own
  render(message);
}
```

---

## Things that shape the design

1. **The recipient must have an XMTP identity.** Check `Client.canMessage([address])` first; a wallet that has never used XMTP cannot receive. This alone rules it out as a sole notification channel.
2. **Creating a client requires a signature.** That is a wallet popup on first use — plan where in the flow it happens.
3. **Consent.** XMTP has allowed/blocked/unknown states; messages from unknown senders land in a request bucket. Respect it, or your notifications sit unread.
4. **Local encrypted database.** State lives in the browser. Clearing site data loses local history.
5. **`dev` and `production` are separate networks.** Identities do not carry across.
6. **Not for large payloads.** Send a link, not the content.

---

## Verdict

Keep the MCP server for reference. Revisit if we ship a product where wallet-addressed
outbound messaging is the point rather than a nice-to-have.

