Poke is the user's personal AI assistant on their phone (SMS/iMessage). OpenClaw agents connect to Poke for two-way communication and event routing.
text
User ←→ Poke (phone) ←→ Tunnel (relay) ←→ MCP Server ←→ OpenClaw (agent)
↑
External services (GitHub, Vercel, etc.) → webhooks → Poke → OpenClaw
Poke owns: triggers, schedules, condition monitoring, timing, user-facing UI OpenClaw owns: execution — acting on events, running code, deploying, responding
Do NOT create OpenClaw cron jobs for things Poke can handle. Poke fires, you execute.
Follow these steps in order. Each step depends on the previous one.
bash
npm install -g openclaw-poke
bash
npx openclaw-poke setup
This auto-discovers your OpenClaw config and:
openclaw.jsonpoke login if needed)openclaw.jsonIf not already logged in, setup will trigger poke login:
Q8CUQBXE)https://poke.com/device?code=YOUR_CODEImportant: The login URL is https://poke.com/device — NOT device.poke.com.
The tunnel connects your local MCP server to Poke through an authenticated relay. No ports exposed, no public URLs, zero attack surface.
bash
poke tunnel http://localhost:3210/mcp --name "OpenClaw"
The tunnel auto-registers with Poke — tools sync automatically.
Make it persistent with systemd:
bash
cat > ~/.config/systemd/user/openclaw-poke-tunnel.service << 'EOF'
[Unit]
Description=OpenClaw Poke Tunnel
After=openclaw-poke-mcp.service
Requires=openclaw-poke-mcp.service
[Service]
Type=simple
ExecStart=/usr/local/bin/poke tunnel http://localhost:3210/mcp --name "OpenClaw"
Restart=always
RestartSec=10
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now openclaw-poke-tunnel
Adjust the ExecStart path to wherever poke is installed ( which poke).
bash
# Check MCP server health
curl -s http://localhost:3210/health
# Check tunnel status
systemctl --user status openclaw-poke-tunnel
# Send a test message
npx openclaw-poke test
poke tunnel may fail with "Server did not return a valid connection ID or tunnel URL." This is a Poke SDK bug — the API returns serverUrl: null for tunnel connections, but the SDK checks for it.
Fix: Patch the CLI binary:
bash
# Find the error string and fix the check
POKE_BIN=$(which poke)
sed -i 's/this\.tunnelUrl=r\.serverUrl,!this\.connectionId||!this\.tunnelUrl/this.tunnelUrl=r.serverUrl||("https:\/\/tunnel.poke.com\/"+r.id),!this.connectionId/' "$POKE_BIN"
Also patch the library (variable name may differ — r vs s):
bash
# Patch node_modules too (for programmatic usage)
SDK_DIR=$(node -e "console.log(require.resolve('poke').replace('/dist/index.mjs',''))")
sed -i 's/this\.tunnelUrl=s\.serverUrl,!this\.connectionId||!this\.tunnelUrl/this.tunnelUrl=s.serverUrl||("https:\/\/tunnel.poke.com\/"+s.id),!this.connectionId/' "$SDK_DIR/dist/index.mjs"
sed -i 's/this\.tunnelUrl=s\.serverUrl,!this\.connectionId||!this\.tunnelUrl/this.tunnelUrl=s.serverUrl||("https:\/\/tunnel.poke.com\/"+s.id),!this.connectionId/' "$SDK_DIR/dist/index.cjs"
Only use this if you already have a publicly reachable URL (VPS, Tailscale Funnel, ngrok). Less secure — anyone with the URL can reach the endpoint.
bash
# 1. Expose the MCP server port publicly
tailscale funnel localhost:3210 /poke
# 2. Register with Poke
poke mcp add https://myhost.example.com/poke/mcp --name "OpenClaw"
ComponentValueSourceMCP endpointhttp://localhost:3210/mcpMCP serverHooks URLhttp://localhost:{port}/hooks/agentAuto-detected from gateway configHooks tokenBearer tokenAuto-detected from openclaw.jsonPoke API keyJWTUser provides or OAuthGateway port18789 (default)Auto-detected
Use the poke_send tool. It sends SMS/iMessage through Poke to the user's phone.
ScenarioUseNormal conversationTelegram/WhatsApp (default channel)User explicitly says "text me"PokeCritical alert (deploy failure, outage)Poke (SMS gets through)Proactive daily briefingChat channel (less intrusive)Responding to a Poke-sourced requestPoke (respond where request came from)
ALL messages from Poke arrive prefixed with [Poke→OpenClaw]. This is how you identify the source.
When you see [Poke→OpenClaw] in a hook/system message:
poke_send, NOT in the current chat sessionWhen sending instructions to Poke, always tell Poke to use session targeting:
list_sessions to discover active sessions and their keyssend_to_agent with session_key set to your main session ( kind: "direct", ends with :main)list_sessions — don't hardcode itsession_key, messages land in a throwaway hook session with NO contexttext
System: [timestamp] Hook Hook: [Poke→OpenClaw] <message content>
After the handshake is established, wire up external services to route through Poke.
bash
# Via tool
poke_webhook(condition="when a Vercel deploy fails")
# Via CLI
npx openclaw-poke webhook "when a Vercel deploy fails"
Or text Poke directly: "Create a trigger: when GitHub Actions fails, send details to my OpenClaw agent"
workflow_run eventspayment_intent.payment_failedToolPurposepoke_sendSend SMS/iMessage to userpoke_sessionsList active OpenClaw sessionspoke_session_sendSend message to specific sessionpoke_webhookCreate Poke trigger/webhook
ToolPurposesend_to_agentSend message to OpenClaw (with session targeting)list_sessionsList active OpenClaw sessions and their keyscheck_agent_statusHealth checkcreate_reminderSet a reminder via OpenClawsend_mediaSend media to agentget_logsGet recent agent logsread_fileRead a file from agent workspacecreate_triggerCreate a trigger on OpenClaw side
ProblemFix"Missing Poke API key"Run npx openclaw-poke setup or set POKE_API_KEY"Server did not return a valid connection ID"Poke SDK bug — apply the sed patch aboveTunnel won't startCheck poke whoami — may need poke loginLogin URL not foundURL is https://poke.com/device?code=CODE (not device.poke.com)Message not deliveredCheck Poke app, verify phone numberAgent responds in wrong channelCheck for [Poke→OpenClaw] prefix; respond via poke_sendPoke responses land in wrong sessionPoke isn't using session targeting; remind it to call list_sessionsTools show 0 after registrationNormal; tools sync on first use"clearhistory"If Poke calls wrong MCP after renaming, text "clearhistory" to PokeTunnel disconnectssystemd auto-restarts; check journalctl --user -u openclaw-poke-tunnel