Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
For OpenClaw iMessage deployments, use
imsg on a signed-in macOS Messages host. If your Gateway runs on Linux or Windows, point channels.imessage.cliPath at an SSH wrapper that runs imsg on the Mac.Gateway-downtime catchup is opt-in. When enabled (channels.imessage.catchup.enabled: true), the gateway replays inbound messages that landed in chat.db while it was offline (crash, restart, Mac sleep) on next startup. Disabled by default — see Catching up after gateway downtime. Closes openclaw#78649.imsg rpc and communicates over JSON-RPC on stdio (no separate daemon/port). Advanced actions require imsg launch and a successful private API probe.
Private API actions
Replies, tapbacks, effects, attachments, and group management.
Pairing
iMessage DMs default to pairing mode.
Remote Mac
Use an SSH wrapper when the Gateway is not running on the Messages Mac.
Configuration reference
Full iMessage field reference.
Quick setup
- Local Mac (fast path)
- Remote Mac over SSH
Requirements and permissions (macOS)
- Messages must be signed in on the Mac running
imsg. - Full Disk Access is required for the process context running OpenClaw/
imsg(Messages DB access). - Automation permission is required to send messages through Messages.app.
- For advanced actions (react / edit / unsend / threaded reply / effects / group ops), System Integrity Protection must be disabled — see Enabling the imsg private API below. Basic text and media send/receive work without it.
Enabling the imsg private API
imsg ships in two operational modes:
- Basic mode (default, no SIP changes needed): outbound text and media via
send, inbound watch/history, chat list. This is what you get out of the box from a freshbrew install steipete/tap/imsgplus the standard macOS permissions above. - Private API mode:
imsginjects a helper dylib intoMessages.appto call internalIMCorefunctions. This is what unlocksreact,edit,unsend,reply(threaded),sendWithEffect,renameGroup,setGroupIcon,addParticipant,removeParticipant,leaveGroup, plus typing indicators and read receipts.
imsg README is explicit about the requirement:
Advanced features such asThe helper-injection technique usesread,typing,launch, bridge-backed rich send, message mutation, and chat management are opt-in. They require SIP to be disabled and a helper dylib to be injected intoMessages.app.imsg launchrefuses to inject when SIP is enabled.
imsg’s own dylib to reach Messages private APIs. There is no third-party server or BlueBubbles runtime in the OpenClaw iMessage path.
Setup
-
Install (or upgrade)
imsgon the Mac that runs Messages.app:Theimsg status --jsonoutput reportsbridge_version,rpc_methods, and per-methodselectorsso you can see what the current build supports before you start. -
Disable System Integrity Protection. This is macOS-version-specific because the underlying Apple requirement depends on the OS and hardware:
- macOS 10.13–10.15 (Sierra–Catalina): disable Library Validation via Terminal, reboot to Recovery Mode, run
csrutil disable, restart. - macOS 11+ (Big Sur and later), Intel: Recovery Mode (or Internet Recovery),
csrutil disable, restart. - macOS 11+, Apple Silicon: power-button startup sequence to enter Recovery; on recent macOS versions hold the Left Shift key when you click Continue, then
csrutil disable. Virtual-machine setups follow a separate flow — take a VM snapshot first. - macOS 26 / Tahoe: library-validation policies and
imagentprivate-entitlement checks have tightened further;imsgmay need an updated build to keep up. Ifimsg launchinjection or specificselectorsstart returning false after a macOS major upgrade, checkimsg’s release notes before assuming the SIP step succeeded.
imsg launch. - macOS 10.13–10.15 (Sierra–Catalina): disable Library Validation via Terminal, reboot to Recovery Mode, run
-
Inject the helper. With SIP disabled and Messages.app signed in:
imsg launchrefuses to inject when SIP is still enabled, so this also doubles as a confirmation that step 2 took. -
Verify the bridge from OpenClaw:
The iMessage entry should report
works, andimsg status --json | jq '.selectors'should showretractMessagePart: trueplus whichever edit / typing / read selectors your macOS build exposes. The OpenClaw plugin per-method gating inactions.tsonly advertises actions whose underlying selector istrue, so the action surface you see in the agent’s tool list reflects what the bridge can actually do on this host.
openclaw channels status --probe reports the channel as works but specific actions throw “iMessage <action> requires the imsg private API bridge” at dispatch time, run imsg launch again — the helper can fall out (Messages.app restart, OS update, etc.) and the cached available: true status will keep advertising actions until the next probe refreshes.
When you can’t disable SIP
If SIP-disabled isn’t acceptable for your threat model:imsgfalls back to basic mode — text + media + receive only.- The OpenClaw plugin still advertises text/media send and inbound monitoring; it just hides
react,edit,unsend,reply,sendWithEffect, and group ops from the action surface (per the per-method capability gate). - You can run a separate non-Apple-Silicon Mac (or a dedicated bot Mac) with SIP off for the iMessage workload, while keeping SIP enabled on your primary devices. See Dedicated bot macOS user (separate iMessage identity) below.
Access control and routing
- DM policy
- Group policy + mentions
- Sessions and deterministic replies
channels.imessage.dmPolicy controls direct messages:pairing(default)allowlistopen(requiresallowFromto include"*")disabled
channels.imessage.allowFrom.Allowlist entries can be handles, static sender access groups (accessGroup:<name>), or chat targets (chat_id:*, chat_guid:*, chat_identifier:*).ACP conversation bindings
Legacy iMessage chats can also be bound to ACP sessions. Fast operator flow:- Run
/acp spawn codex --bind hereinside the DM or allowed group chat. - Future messages in that same iMessage conversation route to the spawned ACP session.
/newand/resetreset the same bound ACP session in place./acp closecloses the ACP session and removes the binding.
bindings[] entries with type: "acp" and match.channel: "imessage".
match.peer.id can use:
- normalized DM handle such as
+15555550123oruser@example.com chat_id:<id>(recommended for stable group bindings)chat_guid:<guid>chat_identifier:<identifier>
Deployment patterns
Dedicated bot macOS user (separate iMessage identity)
Dedicated bot macOS user (separate iMessage identity)
Use a dedicated Apple ID and macOS user so bot traffic is isolated from your personal Messages profile.Typical flow:
- Create/sign in a dedicated macOS user.
- Sign into Messages with the bot Apple ID in that user.
- Install
imsgin that user. - Create SSH wrapper so OpenClaw can run
imsgin that user context. - Point
channels.imessage.accounts.<id>.cliPathand.dbPathto that user profile.
Remote Mac over Tailscale (example)
Remote Mac over Tailscale (example)
Common topology:Use SSH keys so both SSH and SCP are non-interactive.
Ensure the host key is trusted first (for example
- gateway runs on Linux/VM
- iMessage +
imsgruns on a Mac in your tailnet cliPathwrapper uses SSH to runimsgremoteHostenables SCP attachment fetches
ssh bot@mac-mini.tailnet-1234.ts.net) so known_hosts is populated.Multi-account pattern
Multi-account pattern
iMessage supports per-account config under
channels.imessage.accounts.Each account can override fields such as cliPath, dbPath, allowFrom, groupPolicy, mediaMaxMb, history settings, and attachment root allowlists.Media, chunking, and delivery targets
Attachments and media
Attachments and media
- inbound attachment ingestion is off by default — set
channels.imessage.includeAttachments: trueto forward photos, voice memos, video, and other attachments to the agent. With it disabled, attachment-only iMessages are dropped before reaching the agent and may produce noInbound messagelog line at all. - remote attachment paths can be fetched via SCP when
remoteHostis set - attachment paths must match allowed roots:
channels.imessage.attachmentRoots(local)channels.imessage.remoteAttachmentRoots(remote SCP mode)- default root pattern:
/Users/*/Library/Messages/Attachments
- SCP uses strict host-key checking (
StrictHostKeyChecking=yes) - outbound media size uses
channels.imessage.mediaMaxMb(default 16 MB)
Outbound chunking
Outbound chunking
- text chunk limit:
channels.imessage.textChunkLimit(default 4000) - chunk mode:
channels.imessage.chunkModelength(default)newline(paragraph-first splitting)
Addressing formats
Addressing formats
Preferred explicit targets:
chat_id:123(recommended for stable routing)chat_guid:...chat_identifier:...
imessage:+1555...sms:+1555...user@example.com
Private API actions
Whenimsg launch is running and openclaw channels status --probe reports privateApi.available: true, the message tool can use iMessage-native actions in addition to normal text sends.
Available actions
Available actions
- react: Add/remove iMessage tapbacks (
messageId,emoji,remove). Supported tapbacks map to love, like, dislike, laugh, emphasize, and question. - reply: Send a threaded reply to an existing message (
messageId,textormessage, pluschatGuid,chatId,chatIdentifier, orto). - sendWithEffect: Send text with an iMessage effect (
textormessage,effectoreffectId). - edit: Edit a sent message on supported macOS/private API versions (
messageId,textornewText). - unsend: Retract a sent message on supported macOS/private API versions (
messageId). - upload-file: Send media/files (
bufferas base64 or a hydratedmedia/path/filePath,filename, optionalasVoice). Legacy alias:sendAttachment. - renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup: Manage group chats when the current target is a group conversation.
Message IDs
Message IDs
Inbound iMessage context includes both short
MessageSid values and full message GUIDs when available. Short IDs are scoped to the recent in-memory reply cache and are checked against the current chat before use. If a short ID has expired or belongs to another chat, retry with the full MessageSidFull.Capability detection
Capability detection
OpenClaw hides private API actions only when the cached probe status says the bridge is unavailable. If the status is unknown, actions remain visible and dispatch probes lazily so the first action can succeed after
imsg launch without a separate manual status refresh.Read receipts and typing
Read receipts and typing
When the private API bridge is up, accepted inbound chats are marked read before dispatch and a typing bubble is shown to the sender while the agent generates. Disable read-marking with:Older
imsg builds that pre-date the per-method capability list will gate off typing/read silently; OpenClaw logs a one-time warning per restart so the missing receipt is attributable.Config writes
iMessage allows channel-initiated config writes by default (for/config set|unset when commands.config: true).
Disable:
Coalescing split-send DMs (command + URL in one composition)
When a user types a command and a URL together — e.g.Dump https://example.com/article — Apple’s Messages app splits the send into two separate chat.db rows:
- A text message (
"Dump"). - A URL-preview balloon (
"https://...") with OG-preview images as attachments.
imsg introduces.
channels.imessage.coalesceSameSenderDms opts a DM into merging consecutive same-sender rows into a single agent turn. Group chats continue to dispatch per-message so multi-user turn structure is preserved.
- When to enable
- Enabling
- Trade-offs
Enable when:
- You ship skills that expect
command + payloadin 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).
- You need minimum command latency for single-word DM triggers.
- All your flows are one-shot commands without payload follow-ups.
Scenarios and what the agent sees
| User composes | chat.db produces | Flag off (default) | Flag on + 2500 ms window |
|---|---|---|---|
Dump https://example.com (one send) | 2 rows ~1 s apart | Two agent turns: “Dump” alone, then URL | One turn: merged text Dump https://example.com |
Save this 📎image.jpg caption (attachment + text) | 2 rows | Two turns (attachment dropped on merge) | One turn: text + image preserved |
/status (standalone command) | 1 row | Instant dispatch | Wait up to window, then dispatch |
| URL pasted alone | 1 row | Instant dispatch | Instant dispatch (only one entry in bucket) |
| Text + URL sent as two deliberate separate messages, minutes apart | 2 rows outside window | Two turns | Two turns (window expires between them) |
| Rapid flood (>10 small DMs inside window) | N rows | N turns | One turn, bounded output (first + latest, text/attachment caps applied) |
| Two people typing in a group chat | N rows from M senders | M+ turns (one per sender bucket) | M+ turns — group chats are not coalesced |
Catching up after gateway downtime
When the gateway is offline (crash, restart, Mac sleep, machine off),imsg watch resumes from the current chat.db state once the gateway comes back up — anything that arrived during the gap is, by default, never seen. Catchup replays those messages on the next startup so the agent does not silently miss inbound traffic.
Catchup is disabled by default. Enable it per channel:
How it runs
One pass permonitorIMessageProvider startup, sequenced as imsg launch ready → watch.subscribe → performIMessageCatchup → live dispatch loop. Catchup itself uses chats.list + per-chat messages.history against the same JSON-RPC client used by imsg watch. Anything that arrives during the catchup pass flows through live dispatch normally; the existing inbound-dedupe cache absorbs any overlap with replayed rows.
Each replayed row is fed through the live dispatch path (evaluateIMessageInbound + dispatchInboundMessage), so allowlists, group policy, debouncer, echo cache, and read receipts behave identically on replayed and live messages.
Cursor and retry semantics
Catchup keeps a per-account cursor at<openclawStateDir>/imessage/catchup/<account>__<hash>.json (the OpenClaw state dir defaults to ~/.openclaw, overridable with OPENCLAW_STATE_DIR):
- The cursor advances on each successful dispatch and is held when a row’s dispatch throws — the next startup retries the same row from the held cursor.
- After
maxFailureRetriesconsecutive throws against the sameguid, catchup logs awarnand force-advances the cursor past the wedged message so subsequent startups can make progress. - Already-given-up guids are skipped on sight (no dispatch attempt) on later runs and counted under
skippedGivenUpin the run summary.
Operator-visible signals
WARN ... capped to perRunLimit line means a single startup did not drain the full backlog. Raise perRunLimit (max 500) if your gaps regularly exceed the default 50-row pass.
When to leave it off
- Gateway runs continuously with watchdog auto-restart and gaps are always < a few seconds — the default of off is fine.
- DM volume is low and missed messages would not change agent behavior — the
firstRunLookbackMinutesinitial window can dispatch surprising old context on first enable.
firstRunLookbackMinutes (30 min default), not the full maxAgeMinutes window — this avoids replaying a long history of pre-enable messages.
Troubleshooting
imsg not found or RPC unsupported
imsg not found or RPC unsupported
Validate the binary and RPC support:If probe reports RPC unsupported, update
imsg. If private API actions are unavailable, run imsg launch in the logged-in macOS user session and probe again. If the Gateway is not running on macOS, use the Remote Mac over SSH setup above instead of the default local imsg path.Gateway is not running on macOS
Gateway is not running on macOS
The default Then run:
cliPath: "imsg" must run on the Mac signed into Messages. On Linux or Windows, set channels.imessage.cliPath to a wrapper script that SSHes to that Mac and runs imsg "$@".DMs are ignored
DMs are ignored
Check:
channels.imessage.dmPolicychannels.imessage.allowFrom- pairing approvals (
openclaw pairing list imessage)
Group messages are ignored
Group messages are ignored
Check:
channels.imessage.groupPolicychannels.imessage.groupAllowFromchannels.imessage.groupsallowlist behavior- mention pattern configuration (
agents.list[].groupChat.mentionPatterns)
Remote attachments fail
Remote attachments fail
Check:
channels.imessage.remoteHostchannels.imessage.remoteAttachmentRoots- SSH/SCP key auth from the gateway host
- host key exists in
~/.ssh/known_hostson the gateway host - remote path readability on the Mac running Messages
macOS permission prompts were missed
macOS permission prompts were missed
Re-run in an interactive GUI terminal in the same user/session context and approve prompts:Confirm Full Disk Access + Automation are granted for the process context that runs OpenClaw/
imsg.Configuration reference pointers
Related
- Channels Overview — all supported channels
- Coming from BlueBubbles — config translation table and step-by-step cutover
- Pairing — DM authentication and pairing flow
- Groups — group chat behavior and mention gating
- Channel Routing — session routing for messages
- Security — access model and hardening