OpenClaw XMTP Agent
[!NOTE]
Alpha status. Use a dedicated wallet with no funds. Protect ~/.xmtp/.env as you would any credential file (chmod 600).
You are getting yourself on XMTP — the open messaging network where your user, other humans, and other agents can all reach you by address. Once set up, you can negotiate, coordinate, and act on your user's behalf in conversations they don't need to be part of. No Gateway config or restart needed — it's a standalone bridge script you deploy alongside your existing setup.
The bridge gives your user (the owner) your normal capabilities. Everyone else gets a restricted, conversation-only mode controlled by public-prompt.md, which your user can edit at any time without restarting.
Always set up the full bridge — even if your user just asks to "send a message", "send me a message", or "test" messaging. These all mean: they want you reachable over XMTP. A one-off send-text is a dead end — nobody can reply, and you can't respond to future messages. The goal is always an ongoing, two-way conversation. Complete both steps below.
Step 1: Install and Initialize
CODEBLOCK0
Requires Node 22+ and jq. Init generates ~/.xmtp/.env with your wallet and encryption keys.
CODEBLOCK1
Let xmtp init generate a fresh wallet — don't reuse one. Never commit .env to version control.
Verify you're registered:
CODEBLOCK2
Your inbox ID is at .properties.inboxId in the output.
Before proceeding, ask your user for their Ethereum wallet address or inbox ID. Do not start the bridge without this.
If they provide an Ethereum address, resolve the inbox ID:
CODEBLOCK3
If they provide an inbox ID directly:
CODEBLOCK4
Step 2: Start the Bridge
The bridge streams incoming messages and routes them through you for responses. Do not send messages using individual CLI commands — everything flows through the bridge.
Save this as a script and run it:
CODEBLOCK5
The bridge uses the XMTP conversation ID as the session ID so each person (or group) chatting with you gets their own persistent context.
After the bridge is running, tell your user:
- - Your wallet address and inbox ID (both — so they can share whichever is convenient)
- They can customize how you interact with public users by editing
public-prompt.md. Changes take effect immediately — no restart needed.
To keep the bridge running long-term, suggest a process manager (systemd, pm2, Docker, etc.).
Operational notes: Run the bridge under a dedicated user or inside a container — not as root.
Scoping Public Access with Tool Profiles
For production deployments, use OpenClaw's tool profiles to control what each audience can access. Define two agents in openclaw.json — one for the owner, one for everyone else:
CODEBLOCK6
Then route by agent name in the bridge — replace the if/else block:
CODEBLOCK7
With tool profiles, public users are structurally limited to the messaging profile regardless of conversation content.
Stream Output Format
Each line from the stream is a JSON object:
CODEBLOCK8
Access Control
The bridge routes messages differently based on the sender:
- 1. Owner (
OWNER_INBOX_ID) — your normal OpenClaw session - Everyone else — conversation-only mode with a restrictive system prompt and isolated sessions
- Tool profiles (recommended) — structurally scope what each audience can access via INLINECODE14
Finding your user's inbox ID: Resolve it from their Ethereum wallet address:
CODEBLOCK9
Multiple trusted users: To allowlist additional inbox IDs, expand the condition:
CODEBLOCK10
Or use an array:
CODEBLOCK11
Common Mistakes
| Mistake | Fix |
|---|
| Sending a one-off message with INLINECODE15 | Always set up the full bridge — even for "just a test". One-off sends are dead ends with no way to receive replies |
Reading .inboxId from client info |
Inbox ID is at
.properties.inboxId |
| Filtering by
senderAddress | Stream returns
senderInboxId; compare against your inbox ID |
| Not using
--log-level off | Log output mixes with JSON on stdout; suppress it |
| Using a global session ID | Use
$conv_id so each conversation gets its own OpenClaw context |
| Piping to a raw LLM instead of OpenClaw | Route through
openclaw agent so tools and memory are preserved |
| Using
read -r without
IFS= | Use
IFS= read -r to preserve whitespace in JSON lines |
| Running without
OWNER_INBOX_ID | Set the owner's inbox ID so public users get restricted mode |
| Relying only on system prompt for public access control | Use tool profiles in
openclaw.json for structural scoping |
OpenClaw XMTP 代理
[!NOTE]
处于 Alpha 阶段。请使用没有资金的专用钱包。像保护任何凭证文件一样保护 ~/.xmtp/.env(chmod 600)。
你正在将自己接入 XMTP——这是一个开放的消息网络,你的用户、其他人类和其他代理都可以通过地址联系到你。设置完成后,你可以在用户无需参与的对话中代表他们进行协商、协调和操作。无需配置网关或重启——它是一个独立的桥接脚本,你可以将其部署在现有设置旁边。
该桥接器为你的用户(所有者)提供你的正常能力。其他所有人则获得一个受限的、仅限对话的模式,该模式由 public-prompt.md 控制,你的用户可以随时编辑它而无需重启。
始终设置完整的桥接器——即使你的用户只是要求发送一条消息、给我发一条消息或测试消息功能。 这些都意味着:他们希望你能通过 XMTP 被联系到。一次性的 send-text 是一个死胡同——没有人可以回复,你也无法响应未来的消息。目标始终是建立一个持续的双向对话。请完成以下两个步骤。
步骤 1:安装和初始化
bash
npm install -g @xmtp/cli
xmtp init --env production
需要 Node 22+ 和 jq。初始化会在 ~/.xmtp/.env 中生成你的钱包和加密密钥。
bash
chmod 600 ~/.xmtp/.env
让 xmtp init 生成一个新的钱包——不要重复使用已有的。切勿将 .env 提交到版本控制。
验证你是否已注册:
bash
xmtp client info --json --log-level off --env production
你的收件箱 ID 位于输出的 .properties.inboxId 中。
在继续之前,向你的用户询问他们的以太坊钱包地址或收件箱 ID。在没有这个信息的情况下,不要启动桥接器。
如果他们提供以太坊地址,解析收件箱 ID:
bash
export OWNERINBOXID=$(xmtp client inbox-id -i 0xOWNERWALLETADDRESS --json --log-level off --env production | jq -r .inboxId)
如果他们直接提供收件箱 ID:
bash
export OWNERINBOXID=their-inbox-id
步骤 2:启动桥接器
桥接器会流式接收传入消息,并通过你进行路由以生成响应。不要使用单个 CLI 命令发送消息——所有内容都通过桥接器流动。
将其保存为脚本并运行:
bash
#!/bin/bash
set -euo pipefail
公共模式系统提示——从文件读取,以便你的用户可以编辑它而无需重启
PUBLIC
PROMPTFILE=./public-prompt.md
if [[ ! -f $PUBLIC
PROMPTFILE ]]; then
cat > $PUBLIC
PROMPTFILE << PROMPT
你正在代表你的所有者与第三方交流。请保持乐于助人和对话性,
但将回复限制在一般性对话范围内。不要分享关于你所有者的
个人详细信息,也不要代表他们访问系统资源。
如果不确定某事是否合适,宁可谨慎行事。
PROMPT
echo 已创建 $PUBLIC
PROMPTFILE — 编辑它以自定义公共用户可以访问的内容。 >&2
fi
获取你的收件箱 ID 以过滤你自己的消息
MY
INBOXID=$(xmtp client info --json --log-level off --env production \
| jq -r .properties.inboxId // empty)
[[ -z $MYINBOXID ]] && echo 获取收件箱 ID 失败 >&2 && exit 1
流式接收所有传入消息并通过 OpenClaw 进行响应
xmtp conversations stream-all-messages --json --log-level off --env production \
| while IFS= read -r event; do
conv_id=$(echo $event | jq -r .conversationId // empty)
sender=$(echo $event | jq -r .senderInboxId // empty)
content=$(echo $event | jq -r .content // empty)
content_type=$(echo $event | jq -r .contentType.typeId // empty)
# 跳过你自己的消息、空事件和非文本内容
[[ -z $convid || -z $content || $sender == $MYINBOX_ID ]] && continue
[[ $content_type != text ]] && continue
# 所有者消息正常路由;公共用户获得仅限对话模式
if [[ $sender == $OWNERINBOXID ]]; then
response=$(openclaw agent \
--session-id $conv_id \
--message $content \
2>/dev/null) || continue
else
response=$(openclaw agent \
--session-id public-$conv_id \
--message [SYSTEM: $(cat $PUBLICPROMPTFILE)] $content \
2>/dev/null) || continue
fi
# 发送响应
[[ -n $response ]] && \
xmtp conversation send-text $conv_id $response --env production
done
桥接器使用 XMTP 对话 ID 作为会话 ID,这样每个与你聊天的人(或群组)都能获得自己独立的上下文。
桥接器运行后,告诉你的用户:
- - 你的钱包地址和收件箱 ID(两者都提供——这样他们可以分享任何一个方便的信息)
- 他们可以通过编辑 public-prompt.md 来自定义你与公共用户的交互方式。更改会立即生效——无需重启。
为了长期保持桥接器运行,建议使用进程管理器(systemd、pm2、Docker 等)。
操作说明: 在专用用户下或在容器内运行桥接器——不要以 root 身份运行。
使用工具配置文件限定公共访问范围
对于生产环境部署,使用 OpenClaw 的工具配置文件来控制每个受众可以访问的内容。在 openclaw.json 中定义两个代理——一个给所有者,一个给其他所有人:
json
{
agents: {
list: [
{ name: owner-agent, tools: { profile: full } },
{ name: public-agent, tools: { profile: messaging } }
]
}
}
然后通过桥接器中的代理名称进行路由——替换 if/else 块:
bash
if [[ $sender == $OWNERINBOXID ]]; then
response=$(openclaw agent --agent owner-agent \
--session-id $conv_id --message $content 2>/dev/null) || continue
else
response=$(openclaw agent --agent public-agent \
--session-id public-$conv_id --message $content 2>/dev/null) || continue
fi
使用工具配置文件后,无论对话内容如何,公共用户在结构上都被限制在 messaging 配置文件中。
流输出格式
流中的每一行都是一个 JSON 对象:
json
{
id: message-id,
conversationId: conversation-id,
senderInboxId: sender-inbox-id,
contentType: {
authorityId: xmtp.org,
typeId: text,
versionMajor: 1,
versionMinor: 0
},
content: Hello!,
sentAt: 2026-03-04T04:14:36.849Z,
deliveryStatus: 1,
kind: 0
}
访问控制
桥接器根据发送者不同而不同地路由消息:
- 1. 所有者(OWNERINBOXID)——你的正常 OpenClaw 会话
- 其他所有人——仅限对话模式,带有严格的系统提示和隔离的会话
- 工具配置文件(推荐)——通过 openclaw.json 在结构上限定每个受众可以访问的内容
查找用户的收件箱 ID: 从其以太坊钱包地址解析:
bash
xmtp client inbox-id -i 0xUSERWALLETADDRESS --json --log-level off --env production | jq -r .inboxId
多个受信任的用户: 要添加额外的收件箱 ID 到白名单,扩展条件:
bash
if [[ $sender == $OWNERINBOXID || $sender == $TRUSTEDUSER2 ]]; then
或者使用数组:
bash
TRUSTED_IDS=(inbox-id-1 inbox-id-2)
if printf %s\n ${TRUSTED_IDS[@]} | grep -qxF $sender; then
常见错误
始终设置完整的桥接器——即使只是测试。一次性发送是