iMessage (imsg)
Status: external CLI integration. Gateway spawns imsg rpc (JSON-RPC over stdio).
Quick setup (beginner)
- Ensure Messages is signed in on this Mac.
- Install imsg:
- brew install steipete/tap/imsg
- Configure OpenClaw with channels.imessage.cliPath and channels.imessage.dbPath.
- Start the gateway and approve any macOS prompts (Automation + Full Disk Access).
Minimal config:
{
channels: {
imessage: {
enabled: true,
cliPath: "/usr/local/bin/imsg",
dbPath: "/Users/<you>/Library/Messages/chat.db"
}
}
}
What it is
- iMessage channel backed by imsg on macOS.
- Deterministic routing: replies always go back to iMessage.
- DMs share the agent's main session; groups are isolated (agent:<agentId>:imessage:group:<chat_id>).
- If a multi-participant thread arrives with is_group=false, you can still isolate it by chat_id using channels.imessage.groups (see βGroup-ish threadsβ below).
Config writes
By default, iMessage is allowed to write config updates triggered by /config set|unset (requires commands.config: true).
Disable with:
{
channels: { imessage: { configWrites: false } }
}
Requirements
- macOS with Messages signed in.
- Full Disk Access for OpenClaw + imsg (Messages DB access).
- Automation permission when sending.
- channels.imessage.cliPath can point to any command that proxies stdin/stdout (for example, a wrapper script that SSHes to another Mac and runs imsg rpc).
Setup (fast path)
- Ensure Messages is signed in on this Mac.
- Configure iMessage and start the gateway.
Dedicated bot macOS user (for isolated identity)
If you want the bot to send from a separate iMessage identity (and keep your personal Messages clean), use a dedicated Apple ID + a dedicated macOS user.
- Create a dedicated Apple ID (example: [email protected]).
- Apple may require a phone number for verification / 2FA.
- Create a macOS user (example: openclawhome) and sign into it.
- Open Messages in that macOS user and sign into iMessage using the bot Apple ID.
- Enable Remote Login (System Settings β General β Sharing β Remote Login).
- Install imsg:
- brew install steipete/tap/imsg
- Set up SSH so ssh <bot-macos-user>@localhost true works without a password.
- Point channels.imessage.accounts.bot.cliPath at an SSH wrapper that runs imsg as the bot user.
First-run note: sending/receiving may require GUI approvals (Automation + Full Disk Access) in the bot macOS user. If imsg rpc looks stuck or exits, log into that user (Screen Sharing helps), run a one-time imsg chats --limit 1 / imsg send ..., approve prompts, then retry.
Example wrapper (chmod +x). Replace <bot-macos-user> with your actual macOS username:
#!/usr/bin/env bash
set -euo pipefail
# Run an interactive SSH once first to accept host keys:
# ssh <bot-macos-user>@localhost true
exec /usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=5 -T <bot-macos-user>@localhost \
"/usr/local/bin/imsg" "$@"
Example config:
{
channels: {
imessage: {
enabled: true,
accounts: {
bot: {
name: "Bot",
enabled: true,
cliPath: "/path/to/imsg-bot",
dbPath: "/Users/<bot-macos-user>/Library/Messages/chat.db"
}
}
}
}
}
For single-account setups, use flat options (channels.imessage.cliPath, channels.imessage.dbPath) instead of the accounts map.
Remote/SSH variant (optional)
If you want iMessage on another Mac, set channels.imessage.cliPath to a wrapper that runs imsg on the remote macOS host over SSH. OpenClaw only needs stdio.
Example wrapper:
#!/usr/bin/env bash
exec ssh -T gateway-host imsg "$@"
Remote attachments: When cliPath points to a remote host via SSH, attachment paths in the Messages database reference files on the remote machine. OpenClaw can automatically fetch these over SCP by setting channels.imessage.remoteHost:
{
channels: {
imessage: {
cliPath: "~/imsg-ssh", // SSH wrapper to remote Mac
remoteHost: "user@gateway-host", // for SCP file transfer
includeAttachments: true
}
}
}
If remoteHost is not set, OpenClaw attempts to auto-detect it by parsing the SSH command in your wrapper script. Explicit configuration is recommended for reliability.
Remote Mac via Tailscale (example)
If the Gateway runs on a Linux host/VM but iMessage must run on a Mac, Tailscale is the simplest bridge: the Gateway talks to the Mac over the tailnet, runs imsg via SSH, and SCPs attachments back.
Architecture:
ββββββββββββββββββββββββββββββββ SSH (imsg rpc) ββββββββββββββββββββββββββββ
β Gateway host (Linux/VM) ββββββββββββββββββββββββββββββββββββΆβ Mac with Messages + imsg β
β - openclaw gateway β SCP (attachments) β - Messages signed in β
β - channels.imessage.cliPath βββββββββββββββββββββββββββββββββββββ - Remote Login enabled β
ββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β²
β Tailscale tailnet (hostname or 100.x.y.z)
βΌ
user@gateway-host
Concrete config example (Tailscale hostname):
{
channels: {
imessage: {
enabled: true,
cliPath: "~/.openclaw/scripts/imsg-ssh",
remoteHost: "[email protected]",
includeAttachments: true,
dbPath: "/Users/bot/Library/Messages/chat.db"
}
}
}
Example wrapper (~/.openclaw/scripts/imsg-ssh):
#!/usr/bin/env bash
exec ssh -T [email protected] imsg "$@"
Notes:
- Ensure the Mac is signed in to Messages, and Remote Login is enabled.
- Use SSH keys so ssh [email protected] works without prompts.
- remoteHost should match the SSH target so SCP can fetch attachments.
Multi-account support: use channels.imessage.accounts with per-account config and optional name. See gateway/configuration for the shared pattern. Don't commit ~/.openclaw/openclaw.json (it often contains tokens).
Access control (DMs + groups)
DMs:
- Default: channels.imessage.dmPolicy = "pairing".
- Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour).
- Approve via:
- openclaw pairing list imessage
- openclaw pairing approve imessage <CODE>
- Pairing is the default token exchange for iMessage DMs. Details: Pairing
Groups:
- channels.imessage.groupPolicy = open | allowlist | disabled.
- channels.imessage.groupAllowFrom controls who can trigger in groups when allowlist is set.
- Mention gating uses agents.list[].groupChat.mentionPatterns (or messages.groupChat.mentionPatterns) because iMessage has no native mention metadata.
- Multi-agent override: set per-agent patterns on agents.list[].groupChat.mentionPatterns.
How it works (behavior)
- imsg streams message events; the gateway normalizes them into the shared channel envelope.
- Replies always route back to the same chat id or handle.
Group-ish threads (is_group=false)
Some iMessage threads can have multiple participants but still arrive with is_group=false depending on how Messages stores the chat identifier.
If you explicitly configure a chat_id under channels.imessage.groups, OpenClaw treats that thread as a βgroupβ for:
- session isolation (separate agent:<agentId>:imessage:group:<chat_id> session key)
- group allowlisting / mention gating behavior
Example:
{
channels: {
imessage: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
"42": { "requireMention": false }
}
}
}
}
This is useful when you want an isolated personality/model for a specific thread (see Multi-agent routing). For filesystem isolation, see Sandboxing.
Media + limits
- Optional attachment ingestion via channels.imessage.includeAttachments.
- Media cap via channels.imessage.mediaMaxMb.
Limits
- Outbound text is chunked to channels.imessage.textChunkLimit (default 4000).
- Optional newline chunking: set channels.imessage.chunkMode="newline" to split on blank lines (paragraph boundaries) before length chunking.
- Media uploads are capped by channels.imessage.mediaMaxMb (default 16).
Addressing / delivery targets
Prefer chat_id for stable routing:
- chat_id:123 (preferred)
- chat_guid:...
- chat_identifier:...
- direct handles: imessage:+1555 / sms:+1555 / [email protected]
List chats:
imsg chats --limit 20
Configuration reference (iMessage)
Full configuration: Configuration
Provider options:
- channels.imessage.enabled: enable/disable channel startup.
- channels.imessage.cliPath: path to imsg.
- channels.imessage.dbPath: Messages DB path.
- channels.imessage.remoteHost: SSH host for SCP attachment transfer when cliPath points to a remote Mac (e.g., user@gateway-host). Auto-detected from SSH wrapper if not set.
- channels.imessage.service: imessage | sms | auto.
- channels.imessage.region: SMS region.
- channels.imessage.dmPolicy: pairing | allowlist | open | disabled (default: pairing).
- channels.imessage.allowFrom: DM allowlist (handles, emails, E.164 numbers, or chat_id:*). open requires "*". iMessage has no usernames; use handles or chat targets.
- channels.imessage.groupPolicy: open | allowlist | disabled (default: allowlist).
- channels.imessage.groupAllowFrom: group sender allowlist.
- channels.imessage.historyLimit / channels.imessage.accounts.*.historyLimit: max group messages to include as context (0 disables).
- channels.imessage.dmHistoryLimit: DM history limit in user turns. Per-user overrides: channels.imessage.dms["<handle>"].historyLimit.
- channels.imessage.groups: per-group defaults + allowlist (use "*" for global defaults).
- channels.imessage.includeAttachments: ingest attachments into context.
- channels.imessage.mediaMaxMb: inbound/outbound media cap (MB).
- channels.imessage.textChunkLimit: outbound chunk size (chars).
- channels.imessage.chunkMode: length (default) or newline to split on blank lines (paragraph boundaries) before length chunking.
Related global options:
- agents.list[].groupChat.mentionPatterns (or messages.groupChat.mentionPatterns).
- messages.responsePrefix.