* fix(bluebubbles): restore inbound image attachments and accept updated-message events Four interconnected fixes for BlueBubbles inbound media: 1. Strip bundled-undici dispatcher from non-SSRF fetch path so attachment downloads no longer silently fail on Node 22+ (#64105, #61861) 2. Accept updated-message webhook events that carry attachments instead of filtering them as non-reaction events (#65430) 3. Include eventType in the persistent GUID dedup key so updated-message follow-ups are not rejected as duplicates of the original new-message (#52277) 4. Retry attachment fetch from BB API (2s delay) when the initial webhook arrives with an empty attachments array — image-only messages and updated-message events only (#67437) Closes #64105, closes #61861, closes #65430. * fix(bluebubbles): resolve review findings — SSRF policy, reuse extractAttachments, add tests - F1 (BLOCKER): pass undefined instead of {} for SSRF policy when allowPrivateNetwork is false, so localhost BB servers are not blocked. - F2 (IMPORTANT): reuse exported extractAttachments() from monitor-normalize instead of duplicating field extraction logic. - F3 (IMPORTANT): simplify asRecord(asRecord(payload)?.data) to asRecord(payload.data) since payload is already Record<string, unknown>. - F4 (NIT): bind retryMessageId before the guard to eliminate non-null assertion. - F5 (IMPORTANT): add 4 tests for fetchBlueBubblesMessageAttachments covering success, non-ok HTTP, empty data, and guid-less entries. - Add CHANGELOG entry for the user-facing fix. * fix(ci): update raw-fetch allowlist line number after dispatcher strip * fix(bluebubbles): resolve PR review findings (#67510) - monitor-processing: move attachment retry into the !rawBody guard so image-only new-message events that arrive with empty attachments and empty text are recovered via a BB API refetch before being dropped. The existing retry block at the end of processMessageAfterDedupe was unreachable for this case because the !rawBody early-return fired first. (Greptile) - monitor: derive isAttachmentUpdate from the normalized message shape instead of raw payload.data.attachments so updated-message webhooks with attachments under wrapper formats (payload.message, JSON-string payloads) are correctly routed through for processing instead of silently filtered. (Codex) - types: use bundled-undici fetch when init.dispatcher is present so the SSRF guard's DNS-pinning dispatcher is preserved when this function is called as fetchImpl from guarded callers (e.g. the attachment download path via fetchRemoteMedia). Falls back to globalThis.fetch when no dispatcher is present so tests that stub globalThis.fetch keep working. (Codex) - attachments: blueBubblesPolicy returns undefined for the non-private case (matching monitor-processing's helper) so sendBlueBubblesAttachment stops routing localhost BB through the SSRF guard. (Greptile) - scripts/check-no-raw-channel-fetch: bump the types.ts allowlist line to match the restructured non-SSRF branch. * fix(bluebubbles): move attachment retry before rawBody guard, fix stale log Move the attachment retry block (2s BB API refetch for empty attachments) before the !rawBody early-return guard. Previously, image-only messages with text='' and attachments=[] would be dropped by the !rawBody check before the retry could fire, making fix #4 dead code for its primary use-case. Now the retry runs first and recomputes the placeholder from resolved attachments so rawBody becomes non-empty when media is found. Also fix stale log message that still said 'without reaction' after the filter was expanded to pass through attachment updates. * fix(bluebubbles): revert undici import, restore dispatcher-strip approach Revert the @claude bot's undici import in types.ts — it introduced a direct 'undici' dependency that is not declared in the BB extension's package.json and would break isolated plugin installs. Restore the original dispatcher-strip approach which is correct: the SSRF guard already completed validation upstream before calling this function as fetchImpl, so stripping the dispatcher does not weaken security. * fix(bluebubbles): remove dead empty-body recovery block in !rawBody guard The empty-body attachment-recovery block added in the earlier PR revision is now redundant because the main retry block was moved above the rawBody computation in0d7d1c4208. Worse, that leftover block reassigned the (now-const) placeholder variable, throwing `TypeError: Assignment to constant variable` at runtime for image-only messages — breaking the very recovery path it was meant to protect (flagged by Codex on 4bfc2777). Remove the dead block; the up-front retry already handles the image-only case by recovering attachments before the rawBody computation, so once we reach the !rawBody guard with an empty body it is genuinely empty and should drop as before. * fix(ci): update raw-fetch allowlist line after dispatcher-strip revert279dba17d2reverted types.ts back to the dispatcher-strip approach, which put the `fetch(url, ...)` call at line 189 instead of line 198. Bump the allowlist entry to match so `lint:tmp:no-raw-channel-fetch` stops failing check-additional. * test(pdf-tool): update stale opus-4-6 constant to opus-4-7 `628b454eff feat: default Anthropic to Opus 4.7` bumped the bundled anthropic image default to `claude-opus-4-7` but missed updating the `ANTHROPIC_PDF_MODEL` constant in pdf-tool.model-config.test.ts. The tests now fail on any PR that runs the `checks-node-agentic-agents-plugins` shard because the resolver returns 4-7 while the test asserts 4-6. Bump the constant to 4-7 to match the bundled default. --------- Co-authored-by: Lobster <10343873+omarshahine@users.noreply.github.com>
🦞 OpenClaw — Personal AI Assistant
EXFOLIATE! EXFOLIATE!
OpenClaw is a personal AI assistant you run on your own devices. It answers you on the channels you already use. It can speak and listen on macOS/iOS/Android, and can render a live Canvas you control. The Gateway is just the control plane — the product is the assistant.
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
Supported channels include: WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, iMessage, BlueBubbles, IRC, Microsoft Teams, Matrix, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, Zalo Personal, WeChat, QQ, WebChat.
Website · Docs · Vision · DeepWiki · Getting Started · Updating · Showcase · FAQ · Onboarding · Nix · Docker · Discord
New install? Start here: Getting started
Preferred setup: run openclaw onboard in your terminal.
OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on macOS, Linux, and Windows (via WSL2; strongly recommended).
Works with npm, pnpm, or bun.
Sponsors
|
|
|
|
|
|
|
Subscriptions (OAuth):
- OpenAI (ChatGPT/Codex)
Model note: while many providers and models are supported, prefer a current flagship model from the provider you trust and already use. See Onboarding.
Install (recommended)
Runtime: Node 24 (recommended) or Node 22.16+.
npm install -g openclaw@latest
# or: pnpm add -g openclaw@latest
openclaw onboard --install-daemon
OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service) so it stays running.
Quick start (TL;DR)
Runtime: Node 24 (recommended) or Node 22.16+.
Full beginner guide (auth, pairing, channels): Getting started
openclaw onboard --install-daemon
openclaw gateway --port 18789 --verbose
# Send a message
openclaw message send --to +1234567890 --message "Hello from OpenClaw"
# Talk to the assistant (optionally deliver back to any connected channel: WhatsApp/Telegram/Slack/Discord/Google Chat/Signal/iMessage/BlueBubbles/IRC/Microsoft Teams/Matrix/Feishu/LINE/Mattermost/Nextcloud Talk/Nostr/Synology Chat/Tlon/Twitch/Zalo/Zalo Personal/WeChat/QQ/WebChat)
openclaw agent --message "Ship checklist" --thinking high
Upgrading? Updating guide (and run openclaw doctor).
Models config + CLI: Models. Auth profile rotation + fallbacks: Model failover.
Security defaults (DM access)
OpenClaw connects to real messaging surfaces. Treat inbound DMs as untrusted input.
Full security guide: Security
Default behavior on Telegram/WhatsApp/Signal/iMessage/Microsoft Teams/Discord/Google Chat/Slack:
- DM pairing (
dmPolicy="pairing"/channels.discord.dmPolicy="pairing"/channels.slack.dmPolicy="pairing"; legacy:channels.discord.dm.policy,channels.slack.dm.policy): unknown senders receive a short pairing code and the bot does not process their message. - Approve with:
openclaw pairing approve <channel> <code>(then the sender is added to a local allowlist store). - Public inbound DMs require an explicit opt-in: set
dmPolicy="open"and include"*"in the channel allowlist (allowFrom/channels.discord.allowFrom/channels.slack.allowFrom; legacy:channels.discord.dm.allowFrom,channels.slack.dm.allowFrom).
Run openclaw doctor to surface risky/misconfigured DM policies.
Highlights
- Local-first Gateway — single control plane for sessions, channels, tools, and events.
- Multi-channel inbox — WhatsApp, Telegram, Slack, Discord, Google Chat, Signal, BlueBubbles (iMessage), iMessage (legacy), IRC, Microsoft Teams, Matrix, Feishu, LINE, Mattermost, Nextcloud Talk, Nostr, Synology Chat, Tlon, Twitch, Zalo, Zalo Personal, WeChat, QQ, WebChat, macOS, iOS/Android.
- Multi-agent routing — route inbound channels/accounts/peers to isolated agents (workspaces + per-agent sessions).
- Voice Wake + Talk Mode — wake words on macOS/iOS and continuous voice on Android (ElevenLabs + system TTS fallback).
- Live Canvas — agent-driven visual workspace with A2UI.
- First-class tools — browser, canvas, nodes, cron, sessions, and Discord/Slack actions.
- Companion apps — macOS menu bar app + iOS/Android nodes.
- Onboarding + skills — onboarding-driven setup with bundled/managed/workspace skills.
Security model (important)
- Default: tools run on the host for the
mainsession, so the agent has full access when it is just you. - Group/channel safety: set
agents.defaults.sandbox.mode: "non-main"to run non-mainsessions inside per-session Docker sandboxes. - Typical sandbox default: allow
bash,process,read,write,edit,sessions_list,sessions_history,sessions_send,sessions_spawn; denybrowser,canvas,nodes,cron,discord,gateway. - Before exposing anything remotely, read Security, Docker sandboxing, and Configuration.
Operator quick refs
- Chat commands:
/status,/new,/reset,/compact,/think <level>,/verbose on|off,/trace on|off,/usage off|tokens|full,/restart,/activation mention|always - Session tools:
sessions_list,sessions_history,sessions_send - Skills registry: ClawHub
- Architecture overview: Architecture
Docs by goal
- New here: Getting started, Onboarding, Updating
- Channel setup: Channels index, WhatsApp, Telegram, Discord, Slack
- Apps + nodes: macOS, iOS, Android, Nodes
- Config + security: Configuration, Security, Docker sandboxing
- Remote + web: Gateway, Remote access, Tailscale, Web surfaces
- Tools + automation: Tools, Skills, Cron jobs, Webhooks, Gmail Pub/Sub
- Internals: Architecture, Agent, Session model, Gateway protocol
- Troubleshooting: Channel troubleshooting, Logging, Docs home
Apps (optional)
The Gateway alone delivers a great experience. All apps are optional and add extra features.
If you plan to build/run companion apps, follow the platform runbooks below.
macOS (OpenClaw.app) (optional)
- Menu bar control for the Gateway and health.
- Voice Wake + push-to-talk overlay.
- WebChat + debug tools.
- Remote gateway control over SSH.
Note: signed builds required for macOS permissions to stick across rebuilds (see macOS Permissions).
iOS node (optional)
- Pairs as a node over the Gateway WebSocket (device pairing).
- Voice trigger forwarding + Canvas surface.
- Controlled via
openclaw nodes ….
Runbook: iOS connect.
Android node (optional)
- Pairs as a WS node via device pairing (
openclaw devices ...). - Exposes Connect/Chat/Voice tabs plus Canvas, Camera, Screen capture, and Android device command families.
- Runbook: Android connect.
From source (development)
Prefer pnpm for builds from source. Bun is optional for running TypeScript directly.
git clone https://github.com/openclaw/openclaw.git
cd openclaw
pnpm install
pnpm ui:build # auto-installs UI deps on first run
pnpm build
pnpm openclaw onboard --install-daemon
# Dev loop (auto-reload on source/config changes)
pnpm gateway:watch
Note: pnpm openclaw ... runs TypeScript directly (via tsx). pnpm build produces dist/ for running via Node / the packaged openclaw binary.
Development channels
- stable: tagged releases (
vYYYY.M.DorvYYYY.M.D-<patch>), npm dist-taglatest. - beta: prerelease tags (
vYYYY.M.D-beta.N), npm dist-tagbeta(macOS app may be missing). - dev: moving head of
main, npm dist-tagdev(when published).
Switch channels (git + npm): openclaw update --channel stable|beta|dev.
Details: Development channels.
Agent workspace + skills
- Workspace root:
~/.openclaw/workspace(configurable viaagents.defaults.workspace). - Injected prompt files:
AGENTS.md,SOUL.md,TOOLS.md. - Skills:
~/.openclaw/workspace/skills/<skill>/SKILL.md.
Configuration
Minimal ~/.openclaw/openclaw.json (model + defaults):
{
agent: {
model: "<provider>/<model-id>",
},
}
Full configuration reference (all keys + examples).
Star History
Molty
OpenClaw was built for Molty, a space lobster AI assistant. 🦞 by Peter Steinberger and the community.
Community
See CONTRIBUTING.md for guidelines, maintainers, and how to submit PRs. AI/vibe-coded PRs welcome! 🤖
Special thanks to Mario Zechner for his support and for pi-mono. Special thanks to Adam Doppelt for the lobster.bot domain.
Thanks to all clawtributors: