← Back to PRs

#19581: feat: add XMTP channel plugin for wallet-to-agent messaging

by coffeexcoin open 2026-02-18 00:13 View on GitHub →
size: XL
AI assisted PR; codex + openclaw. Prompts largely targeted usage of XMTP sdk (LLM friendly docs) and mirroring the existing flow of the telegram channel. Tested with my own openclaw instance and functional. ## Summary - **Problem:** OpenClaw has no way to communicate via XMTP, an E2E-encrypted, wallet-native messaging protocol used by applications such as, Converse, World, and xmtp.chat - leaving onchain/web3 agents unreachable from these surfaces. - **Why it matters:** XMTP is the de facto messaging layer for wallet-to-wallet agent communication. Supporting it makes OpenClaw agents discoverable and reachable from any XMTP-compatible app using just an Ethereum address. - **What changed:** Added a new `@openclaw/xmtp` channel plugin (`extensions/xmtp/`) implementing DM support, pairing/allowlist access control, reply threading (inbound + outbound), policy-aware auto-consent, `walletKeyFile`/`dbEncryptionKeyFile` support for file-based secret loading, and comprehensive test coverage (58+ tests across 4 test files). Config schema aligns with the existing OpenClaw channel config conventions. - **What did NOT change (scope boundary):** No group chat support (DMs only). No media/attachment support. No changes to core OpenClaw — this is a self-contained plugin using the standard `ChannelPlugin` interface. No changes to existing channels or gateway logic. ## Change Type (select all) - [ ] Bug fix - [x] Feature - [ ] Refactor - [ ] Docs - [ ] Security hardening - [ ] Chore/infra ## Scope (select all touched areas) - [ ] Gateway / orchestration - [ ] Skills / tool execution - [ ] Auth / tokens - [ ] Memory / storage - [x] Integrations - [ ] API / contracts - [ ] UI / DX - [ ] CI/CD / infra ## Linked Issue/PR https://github.com/openclaw/openclaw/discussions/2050 ## User-visible / Behavior Changes - **New channel: `xmtp`** — agents can now receive and respond to XMTP DMs from any XMTP-compatible app (Base, Converse, World, xmtp.chat) - **New config section: `channels.xmtp`** with the following keys: - `walletKey` (required unless `walletKeyFile` set) — EOA private key for the agent's XMTP identity - `walletKeyFile` — path to a file containing the wallet key (alternative to inline config) - `dbEncryptionKey` (required unless `dbEncryptionKeyFile` set) — 64 hex char encryption key for local SQLite DB - `dbEncryptionKeyFile` — path to a file containing the DB encryption key - `env` — `local` | `dev` | `production` (default: `production`) - `dbPath` — custom DB directory (default: `~/.openclaw/channels/xmtp/<env>/`) - `dmPolicy` — `pairing` | `allowlist` | `open` | `disabled` (default: `pairing`) - `allowFrom` — array of Ethereum addresses - **New plugin entry: `plugins.entries.xmtp`** — standard enable/disable toggle - **Reply threading** — inbound replies include referenced message context (`ReplyToId`, `ReplyToBody`); outbound replies are sent as threaded XMTP replies when `replyToId` is present - **Policy-aware auto-consent** — new DM conversations are auto-consented based on `dmPolicy`: always for `open`/`pairing`, only for allowlisted senders in `allowlist` mode, never for `disabled` - **Pairing flow** — follows the standard OpenClaw pairing pattern; users send a message, receive a pairing code, admin approves via `openclaw pairing approve --channel xmtp <CODE>` - **Credential source tracking** — `describeAccount` reports `credentialSource` and `secretSource` (`config`, `file`, or `none`) for diagnostics ## Security Impact (required) - New permissions/capabilities? **Yes** — new channel plugin that connects to the XMTP network - Secrets/tokens handling changed? **Yes** — `walletKey` and `dbEncryptionKey` stored in config or loaded from file via `walletKeyFile`/`dbEncryptionKeyFile` - New/changed network calls? **Yes** — connects to XMTP network nodes (gRPC) for message streaming - Command/tool execution surface changed? **No** - Data access scope changed? **No** **Risk + mitigation:** - `walletKey` is an EOA private key — if compromised, attacker can impersonate the agent on XMTP. Mitigation: config values are redacted in logs/status; `walletKeyFile` supported for file-based secret loading (e.g. mounted secrets, keychain export); recommend env vars or keychain for production. - XMTP SQLite DB files contain identity + encryption keys. Mitigation: DB directory is created with `0o700` permissions; `dbEncryptionKey` encrypts the DB via SQLCipher. - Plugin runs in-process with the Gateway (same as all OpenClaw plugins). Mitigation: standard plugin trust model; plugin uses only the official `@xmtp/agent-sdk`. ## Repro + Verification ### Environment - OS: macOS 15.3.1 (arm64) - Runtime/container: Node.js v25.6.0 - Model/provider: N/A (channel plugin, not model-dependent) - Integration/channel: XMTP (production network) - Relevant config: ```json5 { "channels": { "xmtp": { "enabled": true, "walletKey": "<REDACTED>", "dbEncryptionKey": "<REDACTED>", "env": "production", "dmPolicy": "pairing", "allowFrom": ["0x..."] } }, "plugins": { "entries": { "xmtp": { "enabled": true } } } } ``` ### Steps 1. Configure `channels.xmtp` with a valid wallet key and DB encryption key 2. Enable the plugin in `plugins.entries.xmtp` 3. Restart the gateway 4. From any XMTP client (xmtp.chat, Base app, Converse), send a DM to the agent's Ethereum address 5. If `dmPolicy` is `pairing`, approve the pairing request via `openclaw pairing approve --channel xmtp <CODE>` 6. Send messages — agent should respond; reply to a message to test threading ### Expected - Agent connects to XMTP network and shows `XMTP: ON / OK / configured` in `openclaw status` - Inbound DMs are routed to the correct agent session - Outbound replies are delivered back via XMTP - Reply threading preserves message context (referenced message ID and text) - Auto-consent respects dmPolicy (e.g. `disabled` never consents, `allowlist` only consents for allowed senders) ### Actual - Verified working on production XMTP network with real DMs from xmtp.chat ## Evidence - [x] Failing test/log before + passing after - 58+ tests passing across 4 test files (`vitest run extensions/xmtp/`) - Test files: `channel.test.ts` (plugin structure, capabilities, reply support), `channel.behavior.test.ts` (inbound routing, pairing, outbound delivery, reply threading, threaded dispatcher replies), `types.test.ts` (account resolution, config parsing, credential source tracking), `xmtp-bus.test.ts` (SDK wrapper, send/receive, reply context extraction, auto-consent callback) - [x] Trace/log snippets - Gateway logs show: `[default] XMTP agent connected (env: production)`, `[default] XMTP provider started (address: 0x...)` - Inbound: `xmtp inbound: sender=0x... sid=... len=... preview="..."` - Outbound: `xmtp outbound: to=... len=... preview="..."` ## Human Verification (required) - **Verified scenarios:** DM send/receive on production XMTP network via xmtp.chat; pairing flow (request → approve → message delivery); reply threading (inbound reply context visible to agent, outbound threaded replies); `openclaw status` shows correct channel state; `openclaw pairing list --channel xmtp` lists pending requests; auto-consent behavior across all dmPolicy modes - **Edge cases checked:** Unauthorized senders blocked per dmPolicy; empty messages filtered; policy-aware auto-consent (`disabled` never consents, `allowlist` only for allowed senders, `open`/`pairing` always consent); hot-reload of account config on each message; allowFrom store scoped by accountId; graceful fallback if sendReply not available on conversation object; `readAllowFromStore` failures logged as warnings instead of silently swallowed - **What was NOT verified:** Group chat (not implemented); media/attachments (not implemented); multi-account XMTP; behavior under XMTP network outages; XMTP mainnet fee model (not yet live); `walletKeyFile`/`dbEncryptionKeyFile` loading (file-based paths, not tested end-to-end) ## Compatibility / Migration - Backward compatible? **Yes** — purely additive; no changes to existing code - Config/env changes? **Yes** — new `channels.xmtp` config section (only needed if enabling XMTP) - Migration needed? **No** ## Failure Recovery (if this breaks) - **How to disable/revert:** Set `plugins.entries.xmtp.enabled: false` or remove `channels.xmtp` from config, then restart gateway - **Files/config to restore:** Only `openclaw.json` (remove xmtp entries) - **Known bad symptoms:** If XMTP SDK fails to connect, gateway logs will show `XMTP error (...)` but other channels are unaffected (plugin is isolated). If DB files are corrupted/lost, agent creates a new XMTP installation (max 10 per inbox — monitor with `openclaw status`) ## Risks and Mitigations - **Risk:** XMTP SDK is an external dependency that could introduce breaking changes on update. **Mitigation:** `@xmtp/agent-sdk` version is pinned in `package.json`; plugin is isolated in `extensions/xmtp/` and can be disabled independently. - **Risk:** SQLite DB file loss creates new installations (hard limit of 10 per inbox, no revocation yet). **Mitigation:** DB files stored in persistent `~/.openclaw/channels/xmtp/` directory with restricted permissions; documented in code comments and plugin README. - **Risk:** `walletKey` in config could be accidentally exposed in logs or status output. **Mitigation:** OpenClaw's config system redacts sensitive fields; plugin reports `credentialSource`/`secretSource` in diagnostics rather than the actual values; `walletKeyFile`/`dbEncryptionKeyFile` options allow keeping secrets out of config entirely. <!-- greptile_comment --> <h3>Greptile Summary</h3> Added self-contained XMTP channel plugin (`extensions/xmtp/`) that i...

Most Similar PRs