Install
openclaw skills install @jkobject/unbridledSend and read messages on Facebook Messenger, WhatsApp, Instagram, LinkedIn, Twitter/X, Signal, Telegram, Discord and other networks through a Beeper account, using the cloud Matrix bridges (hungryserv). Installs bbctl, sets up E2EE with matrix-nio, bootstraps cross-signing from the user's Beeper recovery key, runs a long-running sync daemon for incoming decryption, and exposes a single Python wrapper to list/search/send/read chats across all bridged networks.
openclaw skills install @jkobject/unbridledUnified messaging for agents via a personal Beeper account.
https://matrix.beeper.com/_hungryserv/<user>).matrix-nio[e2e].Under the hood it is a thin, dependency-minimal layer:
agent / clawd
│
│ CLI / Python import
▼
scripts/
├── nio_client.py ← async send / list / history (E2EE)
├── client.py ← sync HTTP wrapper (no e2ee; list + bridge state)
├── bootstrap_crosssign.py ← one-shot: recovery key → cross-sign device
├── import_key_backup.py ← one-shot: recovery key → import Megolm key backup
├── sync_daemon.py ← long-running sync (systemd) → new Megolm sessions
└── verify_interactive.py ← fallback: SAS verification via Beeper Desktop
▼
bbctl + access token (~/.config/bbctl/config.json)
▼
https://matrix.beeper.com/_hungryserv/<user> (Matrix CS API)
▼
Beeper bridges (cloud) → Messenger / WhatsApp / IG / LinkedIn / Twitter / …
Use beeper-matrix when the user asks to:
Do not use it to blast messages to many contacts or to automate replies without explicit consent per-thread.
The user must have:
EsUC HBcy scrf uiTy DTU2 rvEB Jmgj 9Cpa D6V2 z7Vk ZrU9 9RMh.In Beeper Desktop:
The code is shown as 12 groups of 4 base58 characters.
⚠️ It's a full account recovery secret — treat it like a password. If it's ever exposed, regenerate it from the same menu.
python3 with venvuv (or plain pip) to create the venvlibolm-dev (package for Olm/Megolm crypto)ffmpeg (optional, for media attachments later)Follow these steps once on the agent host.
bbctl and deps# bbctl binary (Beeper Bridge Manager)
mkdir -p ~/bin
curl -sL -o ~/bin/bbctl https://github.com/beeper/bridge-manager/releases/latest/download/bbctl-linux-amd64
chmod +x ~/bin/bbctl
# System deps
sudo apt install -y libolm-dev ffmpeg python3-venv
# Agent Python venv (dedicated, not global)
uv venv ~/.venvs/beeper --python 3.12
VIRTUAL_ENV=~/.venvs/beeper uv pip install 'matrix-nio[e2e]' aiohttp pycryptodome cryptography pynacl unpaddedbase64 canonicaljson
bbctlbbctl login
The user enters their Beeper credentials. This stores an access token at ~/.config/bbctl/config.json. That token is all the nio client needs.
Verify:
bbctl whoami
# Should show: User ID: @<user>:beeper.com, all bridges RUNNING
mkdir -p ~/.secrets && chmod 700 ~/.secrets
cat > ~/.secrets/beeper-recovery-key.txt <<EOF
EsUC HBcy scrf uiTy DTU2 rvEB Jmgj 9Cpa D6V2 z7Vk ZrU9 9RMh
EOF
chmod 600 ~/.secrets/beeper-recovery-key.txt
Replace the sample with the actual recovery key. Never commit to git.
The 4 scripts live at scripts/beeper/ in the workspace (they come with the skill — see scripts/ subfolder). Ensure:
ls ~/.openclaw/workspace/scripts/beeper/
# client.py nio_client.py bootstrap_crosssign.py verify_interactive.py
# First run initializes the Olm store (~/.local/share/clawd-matrix/)
~/.venvs/beeper/bin/python ~/.openclaw/workspace/scripts/beeper/nio_client.py whoami
# Should print: e2ee: enabled=True
# Sign the device using the recovery key
~/.venvs/beeper/bin/python ~/.openclaw/workspace/scripts/beeper/bootstrap_crosssign.py
# Expected output ends with:
# 🎉 SUCCESS — device is now cross-signed. Bridge should accept our messages.
After this step, Beeper's bridges trust the agent's device and will relay messages to the external networks.
Cross-signing only handles outgoing messages. To decrypt incoming history, import the server-side Megolm key backup into the local Olm store. Stop the sync daemon first to avoid a write conflict on the sqlite store.
systemctl --user stop clawd-beeper-sync 2>/dev/null || true
~/.venvs/beeper/bin/python ~/.openclaw/workspace/scripts/beeper/import_key_backup.py
systemctl --user start clawd-beeper-sync
# Expected: "✓ Imported N sessions into ~/.local/share/clawd-matrix/"
You only need to run this once per device (sessions accumulate in the store).
Re-run it after any bbctl login that issued a new device id.
All commands run inside the venv. $SKILL_DIR is wherever this skill is
installed (e.g. ~/.openclaw/workspace/skills/unbridled when installed via
ClawHub, or the repo root if cloned from GitHub).
NIO=~/.venvs/beeper/bin/python
SCRIPT="$SKILL_DIR/scripts/nio_client.py"
# Identity check
$NIO $SCRIPT whoami
# List chats for a specific network (shows room name, which is often missing for DMs)
$NIO $SCRIPT list-chats --network messenger --limit 25
$NIO $SCRIPT list-chats --network whatsapp --limit 50
$NIO $SCRIPT list-chats --network linkedin
# Aliases accepted: messenger/facebook/fb, whatsapp/wa, instagram/ig,
# linkedin, twitter/x, signal, telegram, discord
# ⚠️ IMPORTANT: DMs on Beeper usually have NO room name (listed as !xxx:beeper.local).
# The contact name lives in a member's display_name. To find a chat by contact, use:
$NIO $SCRIPT search-chats baptiste # scans all ~450 rooms + members
$NIO $SCRIPT search-chats juliette --network messenger # restrict to one bridge
$NIO $SCRIPT search-chats "jean-baptiste" --json # structured output
#
# SEARCH STRATEGY: strict first → automatic fuzzy fallback if 0 results
# Fuzzy handles double-letter variants: 'zummer' ↔ 'zumer', 'baptiste' ↔ 'batiste', etc.
# Output shows "[fuzzy fallback]" when fallback was used.
#
# Flags:
$NIO $SCRIPT search-chats "zummer" # auto: strict → fuzzy if needed
$NIO $SCRIPT search-chats "zummer" --fuzzy # force fuzzy (skip strict pass)
$NIO $SCRIPT search-chats "zummer" --strict # strict only, no fuzzy fallback
# Send a message (E2EE handled automatically)
$NIO $SCRIPT send --room '!xxx:beeper.local' --text "Hello from clawd"
# Read recent history in a room (requires megolm session in the store)
$NIO $SCRIPT history --room '!xxx:beeper.local' --limit 20
Python import usage (recommended for cron / scripts):
import os, sys, asyncio
sys.path.insert(0, os.path.expanduser(os.environ["SKILL_DIR"]) + "/scripts")
from nio_client import make_client
async def ping():
c = await make_client()
try:
# ... use c.room_send / c.joined_rooms / etc.
pass
finally:
await c.close()
asyncio.run(ping())
sync(full_state=True). nio's client.rooms will be mostly empty. The wrapper sidesteps this by calling joined_rooms() directly and manually injecting a minimal MatrixRoom before room_send. Don't rely on client.rooms being complete.logging.getLogger("nio").setLevel(ERROR).'events' is a required property): hungryserv returns sync responses with fields nio doesn't fully recognize. Safe to ignore; already silenced.com.beeper.undecryptable_event / your device is not trusted (unverified). bootstrap_crosssign.py fixes this once and for all for this device.Facebook Messenger (Jérémie Kalfon) auto-chat has no external recipient. Test sends on a chat with a real other user.history --limit >= 10) instead of mirroring the raw count, otherwise it can report a false decryption unavailable.This skill gives the agent direct write access to the user's personal chats
on every bridged network. The agent MUST treat every send as a privileged
operation:
memory/YYYY-MM-DD.md) so the user can audit after the fact.bootstrap_crosssign.py and import_key_backup.py
after the next bbctl login.unbridled/
├── SKILL.md (this file)
├── README.md GitHub-facing doc
├── LICENSE MIT
├── install.sh prerequisites installer
├── scripts/
│ ├── client.py sync HTTP wrapper (list + bridge state)
│ ├── nio_client.py async E2EE client (send/list/history)
│ ├── bootstrap_crosssign.py one-shot: recovery key → cross-sign
│ ├── import_key_backup.py one-shot: recovery key → import Megolm backup
│ ├── verify_interactive.py fallback: SAS via Beeper Desktop
│ ├── sync_daemon.py long-running sync (Megolm accumulation)
│ └── collect_beeper_daily.py daily digest generator
├── systemd/
│ ├── clawd-beeper-sync.service user-level systemd unit for the daemon
│ └── install.sh installs the unit into ~/.config/systemd/user/
└── references/
├── setup-checklist.md step-by-step for humans
└── architecture.md diagrams and crypto flow
search-chats refactored: strict-first + automatic fuzzy fallback on 0 results. Fuzzy handles double-letter variants (zummer ↔ zumer, baptiste ↔ batiste). Flags: --fuzzy (force), --strict (disable fallback). Output shows [fuzzy fallback] tag. _fetch_room_info now also returns chan_name for room-name matching. All matching moved to pure _apply_match() helper for reuse.collect_beeper_daily.py (scripts/client.py and scripts/nio_client.py live next to the collector, not under scripts/beeper/). Validated by running the collector directly from the published skill layout.decryption unavailable in collect_beeper_daily.py by over-fetching a small history window instead of using the raw recent-event count as the decrypt limit. Validated on Messenger + WhatsApp groups where the latest raw event was reaction/meta noise.import_key_backup.py was added. Confirmed decrypting >95% of joined rooms on an active Beeper account (357/357 backup sessions imported, 0 errors).Two complementary mechanisms feed Megolm group sessions into the local Olm store so inbound history can be decrypted:
m.megolm_backup.v1.curve25519-aes-sha2): Beeper
keeps a server-side, encrypted-at-rest backup of every Megolm session the
user has ever held. import_key_backup.py downloads those, decrypts them
with the recovery key (same key used for cross-signing), and injects each
one into the nio sqlite store. One-shot, imports the entire history.sync_daemon.py, systemd-supervised): runs
sync_forever against hungryserv. Beeper's bridges push new sessions via
to_device events as they're created, which the daemon stores. Keeps
everything up-to-date for future messages.After the one-shot backup import and a minute or two of the daemon running,
history and collect_beeper_daily.py decrypt nearly all traffic. Coverage
is typically ≥ 95% of joined rooms (the rest being inactive rooms that had
no session in the backup).
Install:
bash systemd/install.sh
systemctl --user enable --now clawd-beeper-sync.service
systemctl --user status clawd-beeper-sync
journalctl --user -u clawd-beeper-sync -f
Resource footprint: ~35 MB RAM idle, negligible CPU.
unread --network X helper (summarize unread chats)reply --to <event_id> with proper Matrix reply threadingmark-read on inbound messages