Caricamento in corso...
Caricamento in corso...
Last synced: Today, 22:00
Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. Recommended for iMessage integration due to its richer API and easier setup compared to the legacy imsg channel.
GET /api/v1/pingPOST /message/textPOST /chat/:id/*/channels/pairingchannels.bluebubbles.allowFromtext```json5} { channels: { bluebubbles: { enabled: true, serverUrl: "http://192.168.1.100:1234", password: "example-password", webhookPath: "/bluebubbles-webhook", }, }, } ```
channels.bluebubbles.password?password=<password>x-passwordSome macOS VM / always-on setups can end up with Messages.app going "idle" (incoming events stop until the app is opened/foregrounded). A simple workaround is to poke Messages every 5 minutes using an AppleScript + LaunchAgent.
text```applescript} try tell application "Messages" if not running then launch end if -- Touch the scripting interface to keep the process responsive. set _chatCount to (count of chats) end tell on error -- Ignore transient failures (first-run prompts, locked session, etc). end try ```
text```xml} <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.user.poke-messages</string> <key>ProgramArguments</key> <array> <string>/bin/bash</string> <string>-lc</string> <string>/usr/bin/osascript "$HOME/Scripts/poke-messages.scpt"</string> </array> <key>RunAtLoad</key> <true/> <key>StartInterval</key> <integer>300</integer> <key>StandardOutPath</key> <string>/tmp/poke-messages.log</string> <key>StandardErrorPath</key> <string>/tmp/poke-messages.err</string> </dict> </plist> ``` This runs **every 300 seconds** and **on login**. The first run may trigger macOS **Automation** prompts (`osascript` → Messages). Approve them in the same user session that runs the LaunchAgent.
BlueBubbles is available in interactive onboarding:
textopenclaw onboard
The wizard prompts for:
You can also add BlueBubbles via CLI:
textopenclaw channels add bluebubbles --http-url http://192.168.1.100:1234 --password <password>
`
* Pairing is the default token exchange. Details: [Pairing](/channels/pairing)
* `channels.bluebubbles.groupPolicy = open | allowlist | disabled` (default: `allowlist`).
* `channels.bluebubbles.groupAllowFrom` controls who can trigger in groups when `allowlist` is set.
Contact name enrichment (macOS, optional)
BlueBubbles group webhooks often only include raw participant addresses. If you want
textGroupMembers context to show local contact names instead, you can opt in to local Contacts enrichment on macOS:
- text
channels.bluebubbles.enrichGroupParticipantsFromContacts = true enables the lookup. Default: textfalse.
- Lookups run only after group access, command authorization, and mention gating have allowed the message through.
- Only unnamed phone participants are enriched.
- Raw phone numbers remain as the fallback when no local match is found.
json5{
channels: {
bluebubbles: {
enrichGroupParticipantsFromContacts: true,
},
},
}
Mention gating (groups)
BlueBubbles supports mention gating for group chats, matching iMessage/WhatsApp behavior:
- Uses text
agents.list[].groupChat.mentionPatterns (or textmessages.groupChat.mentionPatterns) to detect mentions.
- When text
requireMention is enabled for a group, the agent only responds when mentioned.
- Control commands from authorized senders bypass mention gating.
Per-group configuration:
json5{
channels: {
bluebubbles: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
"*": { requireMention: true }, // default for all groups
"iMessage;-;chat123": { requireMention: false }, // override for specific group
},
},
},
}
Command gating
- Control commands (e.g., text
/config, text/model) require authorization.
- Uses text
allowFrom and textgroupAllowFrom to determine command authorization.
- Authorized senders can run control commands even without mentioning in groups.
Per-group system prompt
Each entry under
textchannels.bluebubbles.groups.* accepts an optional textsystemPrompt string. The value is injected into the agent's system prompt on every turn that handles a message in that group, so you can set per-group persona or behavioral rules without editing agent prompts:
json5{
channels: {
bluebubbles: {
groups: {
"iMessage;-;chat123": {
systemPrompt: "Keep responses under 3 sentences. Mirror the group's casual tone.",
},
},
},
},
}
The key matches whatever BlueBubbles reports as
textchatGuid / textchatIdentifier / numeric textchatId for the group, and a text"*" wildcard entry provides a default for every group without an exact match (same pattern used by textrequireMention and per-group tool policies). Exact matches always win over the wildcard. DMs ignore this field; use agent-level or account-level prompt customization instead.
Worked example: threaded replies and tapback reactions (Private API)
With the BlueBubbles Private API enabled, inbound messages arrive with short message IDs (for example
text[[reply_to:5]]) and the agent can call textaction=reply to thread into a specific message or textaction=react to drop a tapback. A per-group textsystemPrompt is a reliable way to keep the agent choosing the right tool:
json5{
channels: {
bluebubbles: {
groups: {
"iMessage;+;chat-family": {
systemPrompt: [
"When replying in this group, always call action=reply with the",
"[[reply_to:N]] messageId from context so your response threads",
"under the triggering message. Never send a new unlinked message.",
"",
"For short acknowledgements ('ok', 'got it', 'on it'), use",
"action=react with an appropriate tapback emoji (❤️, 👍, 😂, ‼️, ❓)",
"instead of sending a text reply.",
].join(" "),
},
},
},
},
}
Tapback reactions and threaded replies both require the BlueBubbles Private API; see Advanced actions and Message IDs for the underlying mechanics.
ACP conversation bindings
BlueBubbles chats can be turned into durable ACP workspaces without changing the transport layer.
Fast operator flow:
- Run text
/acp spawn codex --bind here inside the DM or allowed group chat.
- Future messages in that same BlueBubbles conversation route to the spawned ACP session.
- text
/new and text/reset reset the same bound ACP session in place.
- text
/acp close closes the ACP session and removes the binding.
Configured persistent bindings are also supported through top-level
textbindings[] entries with texttype: "acp" and textmatch.channel: "bluebubbles".
textmatch.peer.id can use any supported BlueBubbles target form:
- normalized DM handle such as text
+15555550123 or textuser@example.com
- text
chat_id:<id>
- text
chat_guid:<guid>
- text
chat_identifier:<identifier>
For stable group bindings, prefer
textchat_id:* or textchat_identifier:*.
Example:
json5{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: { agent: "codex", backend: "acpx", mode: "persistent" },
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "bluebubbles",
accountId: "default",
peer: { kind: "dm", id: "+15555550123" },
},
acp: { label: "codex-imessage" },
},
],
}
See ACP Agents for shared ACP binding behavior.
Typing + read receipts
- Typing indicators: Sent automatically before and during response generation.
- Read receipts: Controlled by text
channels.bluebubbles.sendReadReceipts (default: texttrue).
- Typing indicators: OpenClaw sends typing start events; BlueBubbles clears typing automatically on send or timeout (manual stop via DELETE is unreliable).
json5{
channels: {
bluebubbles: {
sendReadReceipts: false, // disable read receipts
},
},
}
Advanced actions
BlueBubbles supports advanced message actions when enabled in config:
json5{
channels: {
bluebubbles: {
actions: {
reactions: true, // tapbacks (default: true)
edit: true, // edit sent messages (macOS 13+, broken on macOS 26 Tahoe)
unsend: true, // unsend messages (macOS 13+)
reply: true, // reply threading by message GUID
sendWithEffect: true, // message effects (slam, loud, etc.)
renameGroup: true, // rename group chats
setGroupIcon: true, // set group chat icon/photo (flaky on macOS 26 Tahoe)
addParticipant: true, // add participants to groups
removeParticipant: true, // remove participants from groups
leaveGroup: true, // leave group chats
sendAttachment: true, // send attachments/media
},
},
},
}
Message IDs (short vs full)
OpenClaw may surface short message IDs (e.g.,
text1, text2) to save tokens.
- text
MessageSid / textReplyToId can be short IDs.
- text
MessageSidFull / textReplyToIdFull contain the provider full IDs.
- Short IDs are in-memory; they can expire on restart or cache eviction.
- Actions accept short or full text
messageId, but short IDs will error if no longer available.
Use full IDs for durable automations and storage:
- Templates: text
{{MessageSidFull}}, text{{ReplyToIdFull}}
- Context: text
MessageSidFull / textReplyToIdFull in inbound payloads
See Configuration for template variables.
Coalescing split-send DMs (command + URL in one composition)
When a user types a command and a URL together in iMessage — e.g.
textDump https://example.com/article — Apple splits the send into two separate webhook deliveries:
- A text message (text
"Dump").
- A URL-preview balloon (text
"https://...") with OG-preview images as attachments.
The two webhooks arrive at OpenClaw ~0.8-2.0 s apart on most setups. Without coalescing, the agent receives the command alone on turn 1, replies (often "send me the URL"), and only sees the URL on turn 2 — at which point the command context is already lost.
textchannels.bluebubbles.coalesceSameSenderDms opts a DM into merging consecutive same-sender webhooks into a single agent turn. Group chats continue to key per-message so multi-user turn structure is preserved.
Enable when:
text* You ship skills that expect `command + payload` in one message (dump, paste, save, queue, etc.).
* Your users paste URLs, images, or long content alongside commands.
* You can accept the added DM turn latency (see below).
Leave disabled when:
* You need minimum command latency for single-word DM triggers.
* All your flows are one-shot commands without payload follow-ups.
```json5}
{
channels: {
bluebubbles: {
coalesceSameSenderDms: true, // opt in (default: false)
},
},
}
```
textWith the flag on and no explicit `messages.inbound.byChannel.bluebubbles`, the debounce window widens to **2500 ms** (the default for non-coalescing is 500 ms). The wider window is required — Apple's split-send cadence of 0.8-2.0 s does not fit in the tighter default.
To tune the window yourself:
```json5}
{
messages: {
inbound: {
byChannel: {
// 2500 ms works for most setups; raise to 4000 ms if your Mac is slow
// or under memory pressure (observed gap can stretch past 2 s then).
bluebubbles: 2500,
},
},
},
}
```
* **Added latency for DM control commands.** With the flag on, DM control-command messages (like `Dump`, `Save`, etc.) now wait up to the debounce window before dispatching, in case a payload webhook is coming. Group-chat commands keep instant dispatch.
* **Merged output is bounded** — merged text caps at 4000 chars with an explicit `…[truncated]` marker; attachments cap at 20; source entries cap at 10 (first-plus-latest retained beyond that). Every source `messageId` still reaches inbound-dedupe so a later MessagePoller replay of any individual event is recognized as a duplicate.
* **Opt-in, per-channel.** Other channels (Telegram, WhatsApp, Slack, …) are unaffected.
Scenarios and what the agent sees
User composes Apple delivers Flag off (default) Flag on + 2500 ms window textDump https://example.com (one send) 2 webhooks ~1 s apart Two agent turns: "Dump" alone, then URL One turn: merged text textDump https://example.com textSave this 📎image.jpg caption (attachment + text) 2 webhooks Two turns One turn: text + image text/status (standalone command) 1 webhook Instant dispatch Wait up to window, then dispatch URL pasted alone 1 webhook Instant dispatch Instant dispatch (only one entry in bucket) Text + URL sent as two deliberate separate messages, minutes apart 2 webhooks outside window Two turns Two turns (window expires between them) Rapid flood (>10 small DMs inside window) N webhooks N turns One turn, bounded output (first + latest, text/attachment caps applied)
Split-send coalescing troubleshooting
If the flag is on and split-sends still arrive as two turns, check each layer:
Block streaming
Control whether responses are sent as a single message or streamed in blocks:
json5{
channels: {
bluebubbles: {
blockStreaming: true, // enable block streaming (off by default)
},
},
}
Media + limits
- Inbound attachments are downloaded and stored in the media cache.
- Media cap via text
channels.bluebubbles.mediaMaxMb for inbound and outbound media (default: 8 MB).
- Outbound text is chunked to text
channels.bluebubbles.textChunkLimit (default: 4000 chars).
Configuration reference
Full configuration: Configuration
Related global options:
- text
agents.list[].groupChat.mentionPatterns (or textmessages.groupChat.mentionPatterns).
- text
messages.responsePrefix.
Addressing / delivery targets
Prefer
textchat_guid for stable routing:
- text
chat_guid:iMessage;-;+15555550123 (preferred for groups)
- text
chat_id:123
- text
chat_identifier:...
- Direct handles: text
+15555550123, textuser@example.com
- If a direct handle does not have an existing DM chat, OpenClaw will create one via text
POST /api/v1/chat/new. This requires the BlueBubbles Private API to be enabled.
iMessage vs SMS routing
When the same handle has both an iMessage and an SMS chat on the Mac (for example a phone number that is iMessage-registered but has also received green-bubble fallbacks), OpenClaw prefers the iMessage chat and never silently downgrades to SMS. To force the SMS chat, use an explicit
textsms: target prefix (for example textsms:+15555550123). Handles without a matching iMessage chat still send through whatever chat BlueBubbles reports.
Security
- Webhook requests are authenticated by comparing text
guid/textpassword query params or headers against textchannels.bluebubbles.password.
- Keep the API password and webhook endpoint secret (treat them like credentials).
- There is no localhost bypass for BlueBubbles webhook auth. If you proxy webhook traffic, keep the BlueBubbles password on the request end-to-end. text
gateway.trustedProxies does not replace textchannels.bluebubbles.password here. See Gateway security.
- Enable HTTPS + firewall rules on the BlueBubbles server if exposing it outside your LAN.
Troubleshooting
- If typing/read events stop working, check the BlueBubbles webhook logs and verify the gateway path matches text
channels.bluebubbles.webhookPath.
- Pairing codes expire after one hour; use text
openclaw pairing list bluebubbles and textopenclaw pairing approve bluebubbles <code>.
- Reactions require the BlueBubbles private API (text
POST /api/v1/message/react); ensure the server version exposes it.
- Edit/unsend require macOS 13+ and a compatible BlueBubbles server version. On macOS 26 (Tahoe), edit is currently broken due to private API changes.
- Group icon updates can be flaky on macOS 26 (Tahoe): the API may return success but the new icon does not sync.
- OpenClaw auto-hides known-broken actions based on the BlueBubbles server's macOS version. If edit still appears on macOS 26 (Tahoe), disable it manually with text
channels.bluebubbles.actions.edit=false.
- text
coalesceSameSenderDms enabled but split-sends (e.g. textDump + URL) still arrive as two turns: see the split-send coalescing troubleshooting checklist — common causes are too-tight debounce window, session-log timestamps misread as webhook arrival, or a reply-quote send (which uses textreplyToBody, not a second webhook).
- For status/health info: text
openclaw status --all or textopenclaw status --deep.
For general channel workflow reference, see Channels and the Plugins guide.
Related
- Channel Routing — session routing for messages
- Channels Overview — all supported channels
- Groups — group chat behavior and mention gating
- Pairing — DM authentication and pairing flow
- Security — access model and hardening
© 2024 TaskFlow Mirror
Powered by TaskFlow Sync Engine