Files
claude-plugins-official/external_plugins/imessage/README.md
Kenneth Lien 1c95fc662b Add imessage channel plugin
iMessage bridge for Claude Code. Reads ~/Library/Messages/chat.db
directly for history and new-message polling; sends via AppleScript
to Messages.app. macOS only.

Built-in access control: inbound messages are gated by an allowlist
(default: self-chat only), outbound sends are scoped to the same
allowlist. The /imessage:access skill manages allowlists and policy.

Requires Full Disk Access and Automation TCC grants — both prompted
by macOS on first use.

Ships full source — server.ts runs locally via bun, started by the
.mcp.json command.
2026-03-18 16:23:29 -07:00

76 lines
3.5 KiB
Markdown

# iMessage
Connect iMessage to your Claude Code assistant. Reads `~/Library/Messages/chat.db` directly for history, search, and new-message detection; sends via AppleScript to Messages.app. No external server, no background process to keep alive.
macOS only.
## Quick setup
> Default: text yourself. Other senders are dropped silently (no auto-reply) until you allowlist them. See [ACCESS.md](./ACCESS.md) for groups and multi-user setups.
**1. Grant Full Disk Access.**
`chat.db` is protected by macOS TCC. The first time the server reads it, macOS pops a prompt asking if your terminal can access Messages — click **Allow**. The prompt names whatever app launched bun (Terminal.app, iTerm, Ghostty, your IDE).
If you click Don't Allow, or the prompt never appears, grant it manually: **System Settings → Privacy & Security → Full Disk Access** → add your terminal. Without this the server exits immediately with `authorization denied`.
**2. Install the plugin.**
These are Claude Code commands — run `claude` to start a session first.
Install the plugin. No env vars needed.
```
/plugin install imessage@claude-plugins-official
```
**3. Relaunch with the channel flag.**
The server won't connect without this — exit your session and start a new one:
```sh
claude --channels plugin:imessage@claude-plugins-official
```
Check that `/imessage:configure` tab-completes.
**4. Text yourself.**
iMessage yourself from any device. It reaches the assistant immediately — self-chat bypasses access control.
> The first outbound reply triggers an **Automation** permission prompt ("Terminal wants to control Messages"). Click OK.
**5. Decide who else gets in.**
Nobody else's texts reach the assistant until you add their handle:
```
/imessage:access allow +15551234567
```
Handles are phone numbers (`+15551234567`) or Apple ID emails (`them@icloud.com`). If you're not sure what you want, ask Claude to review your setup.
## How it works
| | |
| --- | --- |
| **Inbound** | Polls `chat.db` once a second for `ROWID > watermark`. Watermark initializes to `MAX(ROWID)` at boot — old messages aren't replayed on restart. |
| **Outbound** | `osascript` with `tell application "Messages" to send …`. Text and chat GUID pass through argv so there's no escaping footgun. |
| **History & search** | Direct SQLite queries against `chat.db`. Full history — not just messages since the server started. |
| **Attachments** | `chat.db` stores absolute filesystem paths. The first inbound image per message is surfaced to the assistant as a local path it can `Read`. Outbound attachments send as separate messages after the text. |
## Access control
See **[ACCESS.md](./ACCESS.md)** for DM policies, groups, self-chat, delivery config, skill commands, and the `access.json` schema.
Quick reference: IDs are **handle addresses** (`+15551234567` or `someone@icloud.com`). Default policy is `allowlist` — this reads your personal `chat.db`. Self-chat always bypasses the gate.
## Tools exposed to the assistant
| Tool | Purpose |
| --- | --- |
| `reply` | Send to a chat. `chat_id` + `text`, optional `files` (absolute paths). Auto-chunks text; files send as separate messages. |
| `chat_messages` | Fetch recent history from a chat (oldest-first). Reads `chat.db` directly — full native history. Scoped to allowlisted chats. |
## What you don't get
AppleScript can send messages but not tapback, edit, or thread — those require Apple's private API. If you need them, look at [BlueBubbles](https://bluebubbles.app) (requires disabling SIP).