Skip to content
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ce9dc00
Add iMessage adapter package scaffold
underthestars-zhy Feb 26, 2026
17418b6
Add remote config support to iMessage adapter
underthestars-zhy Feb 26, 2026
077ac9b
Remove userName config from iMessage adapter
underthestars-zhy Feb 26, 2026
0f4347c
Store chat instance in iMessage adapter
underthestars-zhy Feb 26, 2026
62a85c3
Add iMessage adapter tests and types
underthestars-zhy Feb 27, 2026
31d7133
Implement postMessage for iMessage adapter
underthestars-zhy Feb 27, 2026
28cf6f1
Add remote mode connection and ready wait in iMessage adapter
underthestars-zhy Feb 28, 2026
2e4484b
Implement editMessage for iMessage remote adapter
underthestars-zhy Feb 28, 2026
3b13c2f
Add `parseMessage` implementation and tests for iMessage adapter
underthestars-zhy Feb 28, 2026
f9ae490
Implement `fetchThread` for iMessage remote mode
underthestars-zhy Feb 28, 2026
19e25cb
Implement addReaction/removeReaction for iMessage adapter
underthestars-zhy Feb 28, 2026
a4a9129
Implement startTyping for iMessage remote mode
underthestars-zhy Feb 28, 2026
605df2b
Add iMessage format converter and shared adapter dependency
underthestars-zhy Feb 28, 2026
b691e46
add meta
underthestars-zhy Feb 28, 2026
504e74d
Add iMessage adapter docs and README
underthestars-zhy Feb 28, 2026
f664c6f
Implement fetchMessages for iMessage adapter
underthestars-zhy Feb 28, 2026
f113029
Update imessage.mdx
underthestars-zhy Feb 28, 2026
37691f9
support file
underthestars-zhy Feb 28, 2026
5bca3ca
Update README to include iMessage adapter
underthestars-zhy Feb 28, 2026
4c55f14
Update index.mdx
underthestars-zhy Feb 28, 2026
dd8a456
Merge upstream/main into feat/imessage
underthestars-zhy Feb 28, 2026
e5a86ed
Fix Teams file upload support status in adapter docs
underthestars-zhy Feb 28, 2026
f4693bb
Add validation to iMessage `decodeThreadId` for wrong adapter
underthestars-zhy Feb 28, 2026
fee6bd0
Fix handleGatewayMessage to use processMessage and pass options
underthestars-zhy Feb 28, 2026
9ce26fb
Update README.md
underthestars-zhy Feb 28, 2026
da14fab
Update apps/docs/content/docs/adapters/index.mdx
underthestars-zhy Feb 28, 2026
9fb33da
Update apps/docs/content/docs/adapters/index.mdx
underthestars-zhy Feb 28, 2026
a367666
Fix gateway listener closing shared SDK in remote mode
underthestars-zhy Feb 28, 2026
3bcc3aa
Update imessage.mdx
underthestars-zhy Feb 28, 2026
a448148
Merge branch 'feat/imessage' of https://github.com/photon-hq/vercel-c…
underthestars-zhy Feb 28, 2026
8696487
Remove webhook forwarding from iMessage adapter
underthestars-zhy Feb 28, 2026
b08ad8d
Separate webhook token from remote API key in iMessage adapter
underthestars-zhy Feb 28, 2026
585c8c1
Remove webhook mode from iMessage adapter
underthestars-zhy Feb 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ See the [Getting Started guide](https://chat-sdk.dev/docs/getting-started) for a
| Discord | `@chat-adapter/discord` | Yes | Yes | Yes | No | Post+Edit | Yes |
| GitHub | `@chat-adapter/github` | Yes | Yes | No | No | No | No |
| Linear | `@chat-adapter/linear` | Yes | Yes | No | No | No | No |
| iMessage | `@chat-adapter/imessage` | Yes | Yes | No | No | No | Yes |

## Features

Expand Down Expand Up @@ -82,6 +83,7 @@ See the [Getting Started guide](https://chat-sdk.dev/docs/getting-started) for a
| `@chat-adapter/linear` | [Linear adapter](https://chat-sdk.dev/docs/adapters/linear) |
| `@chat-adapter/state-redis` | [Redis state adapter](https://chat-sdk.dev/docs/state/redis) (production) |
| `@chat-adapter/state-ioredis` | [ioredis state adapter](https://chat-sdk.dev/docs/state/ioredis) (alternative) |
| `@chat-adapter/imessage` | [iMessage adapter](https://chat-sdk.dev/docs/adapters/imessage) |
| `@chat-adapter/state-memory` | [In-memory state adapter](https://chat-sdk.dev/docs/state/memory) (development) |

## AI coding agent support
Expand Down
184 changes: 184 additions & 0 deletions apps/docs/content/docs/adapters/imessage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: iMessage
description: Configure the iMessage adapter with local (on-device) or remote (server-based) integration.
type: integration
prerequisites:
- /docs/getting-started
---

## Installation

```sh title="Terminal"
pnpm add @chat-adapter/imessage
```

## Usage

The adapter supports two modes: **local** (running directly on a Mac with iMessage) and **remote** (connecting to a [Photon](https://photon.codes) iMessage server). The mode is auto-detected from the `IMESSAGE_LOCAL` environment variable.

### Remote mode

Recommended for production. Connects to [Photon](https://photon.codes)'s managed iMessage service over HTTP and Socket.IO, so your bot can run on any platform.

```typescript title="lib/bot.ts" lineNumbers
import { Chat } from "chat";
import { createiMessageAdapter } from "@chat-adapter/imessage";

const bot = new Chat({
userName: "mybot",
adapters: {
imessage: createiMessageAdapter({
local: false,
}),
},
});

bot.onNewMention(async (thread, message) => {
await thread.post("Hello from iMessage!");
});
```

### Local mode

For development or self-hosted deployments using [imessage-kit](https://github.com/photon-hq/imessage-kit). Reads from the local iMessage database and sends via AppleScript. Must run on macOS with **Full Disk Access** granted.

```typescript title="lib/bot.ts" lineNumbers
import { Chat } from "chat";
import { createiMessageAdapter } from "@chat-adapter/imessage";

const bot = new Chat({
userName: "mybot",
adapters: {
imessage: createiMessageAdapter({
local: true,
}),
},
});

bot.onNewMention(async (thread, message) => {
await thread.post("Hello from iMessage!");
});
```

## Setup

### Remote mode

Remote mode connects to a [Photon](https://photon.codes) iMessage server, which handles the macOS-side integration on your behalf. You'll need an active Photon subscription to get your server credentials.

1. [Request access](https://photon.codes) from Photon to get your server credentials
2. Copy your **server URL** and **API key** from the Photon dashboard
3. Set `IMESSAGE_SERVER_URL` and `IMESSAGE_API_KEY` environment variables
4. Set `IMESSAGE_LOCAL=false`

### Local mode

Local mode requires the adapter to run directly on a macOS machine with iMessage. It uses `@photon-ai/imessage-kit` to read from the local `chat.db` database and send messages via AppleScript.

1. Grant **Full Disk Access** to your terminal or application in **System Settings → Privacy & Security → Full Disk Access**
2. Ensure iMessage is signed in and working on the Mac
3. No additional environment variables are required — local mode is the default

## Receiving messages

The adapter supports multiple ways to receive incoming messages:

### Gateway listener (recommended)

Call `startGatewayListener()` to listen for new messages in real-time. In remote mode, this uses Socket.IO push events. In local mode, it polls the iMessage database.

You can optionally provide a `webhookUrl` to forward events to your webhook endpoint:

```typescript title="lib/bot.ts"
const adapter = bot.getAdapter("imessage");
await adapter.startGatewayListener({
handleMessage: async (message) => {
// Process message directly (no webhook needed)
},
});
```

### Webhook

The adapter handles two webhook formats:

- **Forwarded gateway events**: Messages forwarded from `startGatewayListener()` with a `GATEWAY_` type prefix, authenticated via the `x-imessage-gateway-token` header
- **iMessage Kit webhooks** (local mode only): Messages posted directly by `imessage-kit` when configured with a `webhook` URL

Both formats are automatically detected and handled by `handleWebhook()`.

## Configuration

| Option | Required | Description |
|--------|----------|-------------|
| `local` | No | `true` for local mode, `false` for remote. Auto-detected from `IMESSAGE_LOCAL` (default: `true`) |
| `serverUrl` | Remote only | URL of the remote iMessage server. Auto-detected from `IMESSAGE_SERVER_URL` |
| `apiKey` | Remote only | API key for authentication. Auto-detected from `IMESSAGE_API_KEY` |
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |

## Environment variables

```bash title=".env.local"
IMESSAGE_LOCAL=false # Set to "false" for remote mode (default: true)
IMESSAGE_SERVER_URL=http://... # Required for remote mode
IMESSAGE_API_KEY=... # Required for remote mode
```

## Features

| Feature | Supported |
|---------|-----------|
| Mentions | DMs only |
| Reactions (add/remove) | Remote only |
| Cards | No |
| Modals | No |
| Streaming | No |
| DMs | Yes |
| Ephemeral messages | No |
| File uploads | Yes |
| Typing indicator | Remote only |
| Message history | Yes |
| Message editing | Remote only |

## Tapback reactions

iMessage uses tapbacks instead of emoji reactions. The adapter maps standard emoji names to iMessage tapbacks:

| Emoji | Tapback |
|-------|---------|
| `love` / `heart` | ❤️ Love |
| `like` / `thumbs_up` | 👍 Like |
| `dislike` / `thumbs_down` | 👎 Dislike |
| `laugh` | 😂 Laugh |
| `emphasize` / `exclamation` | ‼️ Emphasize |
| `question` | ❓ Question |

## Limitations

- **Local mode**: Only supports sending/receiving messages, message history, and file uploads. Reactions, typing indicators, message editing, and thread fetching require remote mode.
- **Formatting**: iMessage is plain-text only. Markdown formatting (bold, italic, etc.) is stripped when sending messages, preserving only the text content.
- **Platform**: Local mode requires macOS. Remote mode can run on any platform — [Photon](https://photon.codes) manages the iMessage infrastructure for you.
- **Cards and modals**: iMessage has no support for structured card layouts or interactive modals.

## Troubleshooting

### "serverUrl is required" error

- Set `IMESSAGE_SERVER_URL` or pass `serverUrl` in config when using remote mode
- This error occurs when `IMESSAGE_LOCAL=false` but no server URL is provided

### "apiKey is required" error

- Set `IMESSAGE_API_KEY` or pass `apiKey` in config when using remote mode

### Local mode not receiving messages

- Verify **Full Disk Access** is granted to your terminal or application
- Check that iMessage is signed in and working
- Messages are polled from the local database — there may be a short delay

### Remote mode connection issues

- Verify the server URL is correct and accessible
- Check that the API key matches your Photon iMessage service credentials
- Confirm your Photon subscription is active
69 changes: 35 additions & 34 deletions apps/docs/content/docs/adapters/index.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Overview
description: Platform-specific adapters for Slack, Teams, Google Chat, Discord, GitHub, and Linear.
description: Platform-specific adapters for Slack, Teams, Google Chat, iMessage, Discord, GitHub, and Linear.
type: overview
prerequisites:
- /docs/getting-started
Expand All @@ -12,48 +12,48 @@ Adapters handle webhook verification, message parsing, and API calls for each pl

### Messaging

| Feature | [Slack](/docs/adapters/slack) | [Teams](/docs/adapters/teams) | [Google Chat](/docs/adapters/gchat) | [Discord](/docs/adapters/discord) | [GitHub](/docs/adapters/github) | [Linear](/docs/adapters/linear) |
|---------|-------|-------|-------------|---------|--------|--------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| File uploads | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ❌ |
| Feature | [Slack](/docs/adapters/slack) | [Teams](/docs/adapters/teams) | [Google Chat](/docs/adapters/gchat) | [iMessage](/docs/adapters/imessage) | [Discord](/docs/adapters/discord) | [GitHub](/docs/adapters/github) | [Linear](/docs/adapters/linear) |
|---------|-------|-------|-------------|----------|---------|--------|--------|
| Post message | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Edit message | ✅ | ✅ | ✅ | ⚠️ Remote only | ✅ | ✅ | ✅ |
| Delete message | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| File uploads | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ |
| Streaming | ✅ Native | ⚠️ Post+Edit | ⚠️ Post+Edit | ❌ | ⚠️ Post+Edit | ❌ | ❌ |

### Rich content

| Feature | Slack | Teams | Google Chat | Discord | GitHub | Linear |
|---------|-------|-------|-------------|---------|--------|--------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Embeds | GFM Markdown | Markdown |
| Buttons | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Link buttons | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ |
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Images in cards | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | iMessage | Discord | GitHub | Linear |
|---------|-------|-------|-------------|----------|---------|--------|--------|
| Card format | Block Kit | Adaptive Cards | Google Chat Cards | Plain text | Embeds | GFM Markdown | Markdown |
| Buttons | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Link buttons | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
| Fields | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| Images in cards | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |

### Conversations

| Feature | Slack | Teams | Google Chat | Discord | GitHub | Linear |
|---------|-------|-------|-------------|---------|--------|--------|
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ⚠️ | ⚠️ |
| Typing indicator | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ |
| DMs | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | iMessage | Discord | GitHub | Linear |
|---------|-------|-------|-------------|----------|---------|--------|--------|
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add reactions | ✅ | ❌ | ✅ | ⚠️ Remote only | ✅ | ✅ | ✅ |
| Remove reactions | ✅ | ❌ | ✅ | ⚠️ Remote only | ✅ | ⚠️ | ⚠️ |
| Typing indicator | ❌ | ✅ | ❌ | ⚠️ Remote only | ✅ | ❌ | ❌ |
| DMs | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Ephemeral messages | ✅ Native | ❌ | ✅ Native | ❌ | ❌ | ❌ | ❌ |

### Message history

| Feature | Slack | Teams | Google Chat | Discord | GitHub | Linear |
|---------|-------|-------|-------------|---------|--------|--------|
| Fetch messages | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Fetch thread info | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fetch channel messages | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| List threads | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Fetch channel info | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Post channel message | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| Feature | Slack | Teams | Google Chat | iMessage | Discord | GitHub | Linear |
|---------|-------|-------|-------------|----------|---------|--------|--------|
| Fetch messages | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
| Fetch single message | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Fetch thread info | ✅ | ✅ | ✅ | ⚠️ Remote only | ✅ | ✅ | ✅ |
| Fetch channel messages | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| List threads | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Fetch channel info | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| Post channel message | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ |

<Callout type="info">
⚠️ indicates partial support — the feature works with limitations. See individual adapter pages for details.
Expand All @@ -66,6 +66,7 @@ Adapters handle webhook verification, message parsing, and API calls for each pl
| [Slack](/docs/adapters/slack) | `@chat-adapter/slack` |
| [Microsoft Teams](/docs/adapters/teams) | `@chat-adapter/teams` |
| [Google Chat](/docs/adapters/gchat) | `@chat-adapter/gchat` |
| [iMessage](/docs/adapters/imessage) | `@chat-adapter/imessage` |
| [Discord](/docs/adapters/discord) | `@chat-adapter/discord` |
| [GitHub](/docs/adapters/github) | `@chat-adapter/github` |
| [Linear](/docs/adapters/linear) | `@chat-adapter/linear` |
Expand Down
1 change: 1 addition & 0 deletions apps/docs/content/docs/adapters/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"slack",
"teams",
"gchat",
"imessage",
"discord",
"github",
"linear"
Expand Down
41 changes: 41 additions & 0 deletions packages/adapter-imessage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# @chat-adapter/imessage

[![npm version](https://img.shields.io/npm/v/@chat-adapter/imessage)](https://www.npmjs.com/package/@chat-adapter/imessage)
[![npm downloads](https://img.shields.io/npm/dm/@chat-adapter/imessage)](https://www.npmjs.com/package/@chat-adapter/imessage)

iMessage adapter for [Chat SDK](https://chat-sdk.dev/docs). Supports both local (on-device) and remote ([photon](https://photon.codes)-based) iMessage integration.

## Installation

```bash
npm install chat @chat-adapter/imessage
```

## Usage

```typescript
import { Chat } from "chat";
import { createiMessageAdapter } from "@chat-adapter/imessage";

const bot = new Chat({
userName: "mybot",
adapters: {
imessage: createiMessageAdapter({
serverUrl: process.env.IMESSAGE_SERVER_URL!,
apiKey: process.env.IMESSAGE_API_KEY!,
}),
},
});

bot.onNewMention(async (thread, message) => {
await thread.post("Hello from iMessage!");
});
```

## Documentation

Full setup instructions, configuration reference, and features at [chat-sdk.dev/docs/adapters/imessage](https://chat-sdk.dev/docs/adapters/imessage).

## License

MIT
Loading
Loading