260 lines
11 KiB
Markdown
260 lines
11 KiB
Markdown
---
|
|
summary: "iMessage support via imsg (JSON-RPC over stdio), setup, and chat_id routing"
|
|
read_when:
|
|
- Setting up iMessage support
|
|
- Debugging iMessage send/receive
|
|
---
|
|
# iMessage (imsg)
|
|
|
|
|
|
Status: external CLI integration. Gateway spawns `imsg rpc` (JSON-RPC over stdio).
|
|
|
|
## Quick setup (beginner)
|
|
1) Ensure Messages is signed in on this Mac.
|
|
2) Install `imsg`:
|
|
- `brew install steipete/tap/imsg`
|
|
3) Configure Clawdbot with `channels.imessage.cliPath` and `channels.imessage.dbPath`.
|
|
4) Start the gateway and approve any macOS prompts (Automation + Full Disk Access).
|
|
|
|
Minimal config:
|
|
```json5
|
|
{
|
|
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:
|
|
```json5
|
|
{
|
|
channels: { imessage: { configWrites: false } }
|
|
}
|
|
```
|
|
|
|
## Requirements
|
|
- macOS with Messages signed in.
|
|
- Full Disk Access for Clawdbot + `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)
|
|
1) Ensure Messages is signed in on this Mac.
|
|
2) 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.
|
|
|
|
1) Create a dedicated Apple ID (example: `my-cool-bot@icloud.com`).
|
|
- Apple may require a phone number for verification / 2FA.
|
|
2) Create a macOS user (example: `clawdshome`) and sign into it.
|
|
3) Open Messages in that macOS user and sign into iMessage using the bot Apple ID.
|
|
4) Enable Remote Login (System Settings → General → Sharing → Remote Login).
|
|
5) Install `imsg`:
|
|
- `brew install steipete/tap/imsg`
|
|
6) Set up SSH so `ssh <bot-macos-user>@localhost true` works without a password.
|
|
7) 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:
|
|
```bash
|
|
#!/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:
|
|
```json5
|
|
{
|
|
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. Clawdbot only needs stdio.
|
|
|
|
Example wrapper:
|
|
```bash
|
|
#!/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. Clawdbot can automatically fetch these over SCP by setting `channels.imessage.remoteHost`:
|
|
|
|
```json5
|
|
{
|
|
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, Clawdbot 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 │
|
|
│ - clawdbot 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):
|
|
```json5
|
|
{
|
|
channels: {
|
|
imessage: {
|
|
enabled: true,
|
|
cliPath: "~/.clawdbot/scripts/imsg-ssh",
|
|
remoteHost: "bot@mac-mini.tailnet-1234.ts.net",
|
|
includeAttachments: true,
|
|
dbPath: "/Users/bot/Library/Messages/chat.db"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Example wrapper (`~/.clawdbot/scripts/imsg-ssh`):
|
|
```bash
|
|
#!/usr/bin/env bash
|
|
exec ssh -T bot@mac-mini.tailnet-1234.ts.net imsg "$@"
|
|
```
|
|
|
|
Notes:
|
|
- Ensure the Mac is signed in to Messages, and Remote Login is enabled.
|
|
- Use SSH keys so `ssh bot@mac-mini.tailnet-1234.ts.net` 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`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. Don't commit `~/.clawdbot/clawdbot.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:
|
|
- `clawdbot pairing list imessage`
|
|
- `clawdbot pairing approve imessage <CODE>`
|
|
- Pairing is the default token exchange for iMessage DMs. Details: [Pairing](/start/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`, Clawdbot treats that thread as a “group” for:
|
|
- session isolation (separate `agent:<agentId>:imessage:group:<chat_id>` session key)
|
|
- group allowlisting / mention gating behavior
|
|
|
|
Example:
|
|
```json5
|
|
{
|
|
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](/concepts/multi-agent)). For filesystem isolation, see [Sandboxing](/gateway/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).
|
|
- 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` / `user@example.com`
|
|
|
|
List chats:
|
|
```
|
|
imsg chats --limit 20
|
|
```
|
|
|
|
## Configuration reference (iMessage)
|
|
Full configuration: [Configuration](/gateway/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).
|
|
|
|
Related global options:
|
|
- `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`).
|
|
- `messages.responsePrefix`.
|