Appearance
使用 imsg 是 OpenClaw iMessage 集成的新方案,BlueBubbles 已移除。你可以在本地或通过 SSH 远程运行 imsg RPC,网关通过标准输入输出通信。高级动作(反应/编辑/撤回/效果/群组管理)需关闭 SIP 并运行 imsg launch;无此条件则仅支持文本与媒体收发。启程前先在 macOS 上授予完全磁盘访问和自动化权限。
OpenClaw iMessage(imsg)配置与故障排查指南
INFO
OpenClaw iMessage 部署应在已登录 Messages 的 macOS 主机上使用 imsg。若网关运行在 Linux 或 Windows,请将 channels.imessage.cliPath 指向一个通过 SSH 在 Mac 上运行 imsg 的包装脚本。
网关离线时消息补发为可选项。 启用后(channels.imessage.catchup.enabled: true),网关在下次启动时重播离线期间(崩溃、重启、Mac 睡眠)落入 chat.db 的入站消息。默认禁用 — 参见网关停机后补发消息。关闭 openclaw#78649。
WARNING
BlueBubbles 支持已移除。 将 channels.bluebubbles 配置迁移到 channels.imessage;OpenClaw 仅通过 imsg 支持 iMessage。从 BlueBubbles 移除及 imsg iMessage 路径 开始了解简短公告,或查看 从 BlueBubbles 迁移 获取完整迁移对照表。
状态:原生外部 CLI 集成。网关启动 imsg rpc 并通过标准输入输出上的 JSON-RPC 通信(无独立守护进程/端口)。高级动作要求 imsg launch 并成功探测私密 API。
私密 API 动作
回复、反应、效果、附件和群组管理。
配对
iMessage 私信默认使用配对模式。
远程 Mac
当网关不在 Messages Mac 上运行时使用 SSH 包装。
配置参考
完整 iMessage 字段参考。
快速设置
本地 Mac(快速路径)
安装并验证 imsg
bash
brew install steipete/tap/imsg
imsg rpc --help
imsg launch
openclaw channels status --probe配置 OpenClaw
json5
{
channels: {
imessage: {
enabled: true,
cliPath: "/usr/local/bin/imsg",
dbPath: "/Users/user/Library/Messages/chat.db",
},
},
}启动网关
bash
openclaw gateway批准首次 DM 配对(默认 dmPolicy)
bash
openclaw pairing list imessage
openclaw pairing approve imessage <CODE> 配对请求 1 小时后过期。
远程 Mac over SSH
OpenClaw 仅需要兼容标准输入输出的 `cliPath`,因此可将 `cliPath` 指向一个通过 SSH 连接到远程 Mac 并运行 `imsg` 的包装脚本。
bash
#!/usr/bin/env bash
exec ssh -T gateway-host imsg "$@"启用附件时推荐配置:
json5
{
channels: {
imessage: {
enabled: true,
cliPath: "~/.openclaw/scripts/imsg-ssh",
remoteHost: "user@gateway-host", // 用于 SCP 附件获取
includeAttachments: true,
// 可选:覆盖允许的附件根目录。
// 默认包含 /Users/*/Library/Messages/Attachments
attachmentRoots: ["/Users/*/Library/Messages/Attachments"],
remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],
},
},
}若未设置 `remoteHost`,OpenClaw 会尝试通过解析 SSH 包装脚本自动检测。
`remoteHost` 格式必须是 `host` 或 `user@host`(无空格或 SSH 选项)。
OpenClaw 对 SCP 使用严格的主机密钥检查,因此中继主机密钥必须已存在于 `~/.ssh/known_hosts`。
附件路径会针对允许的根目录(`attachmentRoots` / `remoteAttachmentRoots`)进行验证。
WARNING
任何置于 `imsg` 前方的 `cliPath` 包装或 SSH 代理,**必须**作为长期 JSON-RPC 的透明标准输入输出管道运行。OpenClaw 通过包装的标准输入输出发送小型换行分隔的 JSON-RPC 消息,且在整个通道生命周期中持续进行:
- 每收到一个标准输入块/行时**立即转发**,不要等待 EOF。
- 立即向相反方向转发每个标准输出块/行。
- 保留换行。
- 避免固定大小的阻塞读取(`read(4096)`、`cat | buffer`、默认 shell `read`),否则可能导致小帧饥饿。
- 保持 stderr 与 JSON-RPC 标准输出流分离。
一个在填充大块之前缓冲标准输入的包装会产生类似于 iMessage 中断的症状 — `imsg rpc timeout (chats.list)` 或通道反复重启,即使 `imsg rpc` 本身正常。上方的 `ssh -T host imsg "$@"` 是安全的,因为它将 OpenClaw 的 `cliPath` 参数(如 `rpc` 和 `--db`)递交给远程。像 `ssh host imsg | grep -v '^DEBUG'` 这样的管道并**不安全** — 行缓冲工具仍可能阻塞帧;若必须过滤,请在每个阶段使用 `stdbuf -oL -eL`。
macOS 要求与权限
- 运行
imsg的 Mac 上必须已登录 Messages。 - 运行 OpenClaw/
imsg的进程上下文需要完全磁盘访问权限(访问 Messages 数据库)。 - 需要自动化权限来通过 Messages.app 发送消息。
- 对于高级动作(react/edit/unsend/threaded reply/effects/group ops),必须禁用系统完整性保护(SIP) — 参见下文启用 imsg 私密 API。基本文本和媒体收发无需 SIP 关闭。
TIP
权限按进程上下文授予。如果网关在无头模式(LaunchAgent/SSH)下运行,请在同一上下文中运行一次性交互命令来触发提示:
bash
imsg chats --limit 1
# 或
imsg send <handle> "test"启用 imsg 私密 API
imsg 提供两种操作模式:
- 基本模式(默认,无需 SIP 更改):通过
send发送文本和媒体,入站监听/历史记录,聊天列表。从新的brew install steipete/tap/imsg加上标准 macOS 权限即可使用。 - 私密 API 模式:
imsg向Messages.app注入一个 helper dylib 以调用内部IMCore函数。解锁react、edit、unsend、reply(线程回复)、sendWithEffect、renameGroup、setGroupIcon、addParticipant、removeParticipant、leaveGroup、以及输入指示和已读回执。
要使用本文档中介绍的高级动作面,你需要私密 API 模式。imsg 自述文件明确指出要求:
高级功能如
read、typing、launch、bridge-backed rich send、消息修改和聊天管理是可选的。它们要求禁用 SIP 并将 helper dylib 注入到Messages.app。当 SIP 启用时,imsg launch拒绝注入。
helper 注入技术使用 imsg 自身的 dylib 来调用 Messages 私密 API。OpenClaw iMessage 路径中没有第三方服务器或 BlueBubbles 运行时。
WARNING
禁用 SIP 是一个真实的安全取舍。 SIP 是 macOS 保护运行修改过的系统代码的核心防护之一;全局关闭 SIP 会引入额外的攻击面并产生副作用。值得注意的是,在 Apple Silicon Mac 上禁用 SIP 还会丧失安装和运行 iOS 应用的能力。
请将此视为有意的操作选择,而非默认操作。如果你的威胁模型无法容忍 SIP 关闭,那么内置的 iMessage 将限制为基本模式 — 仅文本和媒体收发,无反应/编辑/撤回/效果/群组操作。
设置步骤
安装(或升级)
imsg在运行 Messages.app 的 Mac 上:bashbrew install steipete/tap/imsg imsg --version imsg status --jsonimsg status --json输出报告bridge_version、rpc_methods和每个方法的selectors,因此你可以在开始前了解当前构建支持什么。禁用系统完整性保护。 这与 macOS 版本相关,因为底层 Apple 要求取决于操作系统和硬件:
- macOS 10.13–10.15 (Sierra–Catalina):通过终端禁用库验证,重启到恢复模式,运行
csrutil disable,重启。 - macOS 11+ (Big Sur 及之后) Intel:恢复模式(或互联网恢复),
csrutil disable,重启。 - macOS 11+ Apple Silicon:开机按钮进入恢复;在较新的 macOS 版本上,在点击继续时按住 左 Shift 键,然后
csrutil disable。虚拟机设置遵循单独流程 — 先拍摄虚拟机快照。 - macOS 26 / Tahoe:库验证策略和
imagent私密权限检查进一步收紧;imsg可能需要更新的构建才能跟上。如果 macOS 大版本升级后imsg launch注入或特定selectors开始返回 false,请在假设 SIP 步骤成功前检查imsg的发布说明。
按照你的 Mac 的 Apple 恢复模式流程禁用 SIP,然后再运行
imsg launch。- macOS 10.13–10.15 (Sierra–Catalina):通过终端禁用库验证,重启到恢复模式,运行
注入 helper。 SIP 已禁用且 Messages.app 已登录:
bashimsg launchimsg launch在 SIP 仍启用时拒绝注入,因此这也同时验证了步骤 2 成功。从 OpenClaw 验证桥接状态:
bashopenclaw channels status --probeiMessage 条目应报告
works,并且imsg status --json | jq '.selectors'应显示retractMessagePart: true以及你的 macOS 构建暴露的其他编辑/输入/已读选择器。OpenClaw 插件在actions.ts中按方法进行门控,仅公布其基础选择器为true的动作,因此你在智能体工具列表中看到的动作面反映了桥接在此主机上实际能做的事情。
如果 openclaw channels status --probe 报告通道为 works,但特定动作在分发时抛出“iMessage <action> 需要 imsg 私密 API 桥接”,请重新运行 imsg launch — helper 可能失效(Messages.app 重启、OS 更新等)且缓存的 available: true 状态会继续公布动作直到下次探测刷新。
当无法禁用 SIP 时
如果 SIP 禁用对你的威胁模型不可接受:
imsg回退到基本模式 — 仅文本 + 媒体 + 接收。- OpenClaw 插件仍公布文本/媒体发送和入站监听;只是从动作面中隐藏了
react、edit、unsend、reply、sendWithEffect和群组操作(根据每个方法的能力门控)。 - 你可以为一台单独的 Intel Mac(或专用的 bot Mac)禁用 SIP 用于 iMessage 工作负载,同时在主要设备上保持 SIP 启用。参见专用 bot macOS 用户(独立 iMessage 身份)。
访问控制与路由
DM 策略
`channels.imessage.dmPolicy` 控制私信:
- `pairing`(默认)
- `allowlist`
- `open`(需要 `allowFrom` 包含 `"*"`)
- `disabled`
白名单字段:`channels.imessage.allowFrom`。
白名单条目必须标识发件人:句柄或静态发件人访问组(`accessGroup:<name>`)。对于聊天目标(如 `chat_id:*`、`chat_guid:*`、`chat_identifier:*`),使用 `channels.imessage.groupAllowFrom`;数字 `chat_id` 注册键使用 `channels.imessage.groups`。
群组策略 + 提及
`channels.imessage.groupPolicy` 控制群组处理:
- `allowlist`(配置时默认)
- `open`
- `disabled`
群组发件人白名单:`channels.imessage.groupAllowFrom`。
`groupAllowFrom` 条目也可引用静态发件人访问组(`accessGroup:<name>`)。
运行时回退:如果未设置 `groupAllowFrom`,iMessage 群组发件人检查使用 `allowFrom`;当 DM 和群组准入应不同时,设置 `groupAllowFrom`。
运行时注意:如果 `channels.imessage` 完全缺失,运行时回退到 `groupPolicy="allowlist"` 并记录警告(即使设置了 `channels.defaults.groupPolicy`)。
WARNING
群组路由依次经过**两个**白名单门控,**两者都必须通过**:
1. **发件人/聊天目标白名单**(`channels.imessage.groupAllowFrom`) — 句柄、`chat_guid`、`chat_identifier`、`chat_id`。
2. **群组注册表**(`channels.imessage.groups`) — 当 `groupPolicy: "allowlist"` 时,此门控要求要么存在 `groups: { "*": { ... } }` 通配符条目(设置 `allowAll = true`),要么在 `groups` 下有每个 `chat_id` 的显式条目。
如果门控 2 为空,每条群组消息都会被丢弃。插件在默认日志级别输出两条 `warn` 级别信号:
- 启动时每个账号一次:`imessage: groupPolicy="allowlist" but channels.imessage.groups is empty for account "<id>"`
- 运行时每个 `chat_id` 一次:`imessage: dropping group message from chat_id=<id> ...`
私信仍然工作,因为走不同的代码路径。
在 `groupPolicy: "allowlist"` 下保持群组流动的最小配置:
```json5
{
channels: {
imessage: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: { "*": { "requireMention": true } },
},
},
}
```
如果网关日志中出现那些 `warn` 行,说明门控 2 在丢消息 — 添加 `groups` 块。
群组提及门控:
- iMessage 没有原生提及元数据
- 提及检测使用正则模式(`agents.list[].groupChat.mentionPatterns`,回退 `messages.groupChat.mentionPatterns`)
- 若未配置模式,则无法执行提及门控
来自授权发件人的控制命令可以绕过群组中的提及门控。
每个群组的 `systemPrompt`:
`channels.imessage.groups.*` 下的每个条目接受可选的 `systemPrompt` 字符串。该值在处理该群组消息的每一轮中被注入智能体的系统提示。解析方式与 `channels.whatsapp.groups` 使用的每个群组提示解析相同:
1. **群组专有系统提示**(`groups["<chat_id>"].systemPrompt`):当群组条目存在于映射中**且**其 `systemPrompt` 键已定义时使用。如果 `systemPrompt` 是空字符串(`""`),通配符被抑制,且不会对该群组应用系统提示。
2. **群组通配符系统提示**(`groups["*"].systemPrompt`):当群组条目完全不在映射中时使用,或者当条目存在但未定义 `systemPrompt` 键时使用。
```json5
{
channels: {
imessage: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
"*": { systemPrompt: "使用英式拼写。" },
"8421": {
requireMention: true,
systemPrompt: "这是值班轮换聊天。回复保持在 3 句以内。",
},
"9907": {
// 显式抑制:通配符“使用英式拼写”不适用于此
systemPrompt: "",
},
},
},
},
}
```
每个群组的提示仅应用于群组消息 — 此通道中的私信不受影响。
会话与确定性回复
- 私信使用直接路由;群组使用群组路由。
- 默认 `session.dmScope=main`,iMessage 私信合并到智能体主会话。
- 群组会话隔离(`agent:<agentId>:imessage:group:<chat_id>`)。
- 回复使用原始通道/目标元数据路由回 iMessage。
类群组线程行为:
某些多方参与的 iMessage 线程到达时 `is_group=false`。
如果该 `chat_id` 在 `channels.imessage.groups` 中显式配置,OpenClaw 将其视为群组流量(群组门控 + 群组会话隔离)。
ACP 会话绑定
旧版 iMessage 聊天也可绑定到 ACP 会话。
快速操作流程:
- 在 DM 或允许的群聊中运行
/acp spawn codex --bind here。 - 该 iMessage 对话中的后续消息路由到已创建的 ACP 会话。
/new和/reset原地重置同一绑定的 ACP 会话。/acp close关闭 ACP 会话并移除绑定。
通过顶层 bindings[] 条目支持配置持久绑定,type: "acp" 和 match.channel: "imessage"。
match.peer.id 可以使用:
- 标准化 DM 句柄,如
+15555550123或user@example.com chat_id:<id>(推荐用于稳定的群组绑定)chat_guid:<guid>chat_identifier:<identifier>
示例:
json5
{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: { agent: "codex", backend: "acpx", mode: "persistent" },
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "imessage",
accountId: "default",
peer: { kind: "group", id: "chat_id:123" },
},
acp: { label: "codex-group" },
},
],
}参见 ACP Agents 了解共享的 ACP 绑定行为。
部署模式
专用 bot macOS 用户(独立 iMessage 身份)
使用专用 Apple ID 和 macOS 用户,使 bot 流量与个人 Messages 档案隔离。
典型流程:
1. 创建/登录一个专用 macOS 用户。
2. 在该用户中使用 bot Apple ID 登录 Messages。
3. 在该用户中安装 `imsg`。
4. 创建 SSH 包装,使 OpenClaw 可以在该用户上下文中运行 `imsg`。
5. 将 `channels.imessage.accounts.<id>.cliPath` 和 `.dbPath` 指向该用户档案。
首次运行可能需要在 bot 用户会话中进行 GUI 授权(自动化 + 完全磁盘访问)。
通过 Tailscale 连接远程 Mac(示例)
常见拓扑:
- 网关运行在 Linux/VM 上
- iMessage + `imsg` 运行在你的 tailnet 中的 Mac 上
- `cliPath` 包装使用 SSH 运行 `imsg`
- `remoteHost` 启用 SCP 附件获取
示例:
```json5
{
channels: {
imessage: {
enabled: true,
cliPath: "~/.openclaw/scripts/imsg-ssh",
remoteHost: "bot@mac-mini.tailnet-1234.ts.net",
includeAttachments: true,
dbPath: "/Users/bot/Library/Messages/chat.db",
},
},
}
```
```bash
#!/usr/bin/env bash
exec ssh -T bot@mac-mini.tailnet-1234.ts.net imsg "$@"
```
使用 SSH 密钥使 SSH 和 SCP 均无需交互。
首先确保主机密钥受信任(例如 `ssh bot@mac-mini.tailnet-1234.ts.net`),以便 `known_hosts` 内容填充。
多账号模式
iMessage 支持在 `channels.imessage.accounts` 下对每个账号进行配置。
每个账号可以覆盖诸如 `cliPath`、`dbPath`、`allowFrom`、`groupPolicy`、`mediaMaxMb`、历史设置和附件根白名单等字段。
媒体、分块与投递目标
附件与媒体
- 入站附件获取**默认关闭** — 设置 `channels.imessage.includeAttachments: true` 以将照片、语音备忘录、视频和其他附件转发给智能体。禁用时,仅含附件的 iMessage 在到达智能体前被丢弃,可能根本不产生任何 `Inbound message` 日志行。
- 设置 `remoteHost` 后,远程附件路径可通过 SCP 获取。
- 附件路径必须匹配允许的根目录:
- `channels.imessage.attachmentRoots`(本地)
- `channels.imessage.remoteAttachmentRoots`(远程 SCP 模式)
- 默认根目录模式:`/Users/*/Library/Messages/Attachments`
- SCP 使用严格的主机密钥检查(`StrictHostKeyChecking=yes`)。
- 出站媒体大小:`channels.imessage.mediaMaxMb`(默认 16 MB)。
出站分块
- 文本块限制:`channels.imessage.textChunkLimit`(默认 4000)。
- 分块模式:`channels.imessage.chunkMode`
- `length`(默认)
- `newline`(段落优先分割)
寻址格式
推荐显式目标:
- `chat_id:123`(推荐用于稳定路由)
- `chat_guid:...`
- `chat_identifier:...`
也支持句柄目标:
- `imessage:+1555...`
- `sms:+1555...`
- `user@example.com`
```bash
imsg chats --limit 20
```
私密 API 动作
当 imsg launch 运行且 openclaw channels status --probe 报告 privateApi.available: true 时,消息工具除了普通文本发送外还可使用 iMessage 原生动作。
json5
{
channels: {
imessage: {
actions: {
reactions: true,
edit: true,
unsend: true,
reply: true,
sendWithEffect: true,
sendAttachment: true,
renameGroup: true,
setGroupIcon: true,
addParticipant: true,
removeParticipant: true,
leaveGroup: true,
},
},
},
}可用动作
- **react**:添加/删除 iMessage tapback(`messageId`, `emoji`, `remove`)。支持的 tapback 映射为 love, like, dislike, laugh, emphasize, question。
- **reply**:向现有消息发送线程回复(`messageId`, `text` 或 `message`,加上 `chatGuid`, `chatId`, `chatIdentifier` 或 `to`)。
- **sendWithEffect**:使用 iMessage 效果发送文本(`text` 或 `message`, `effect` 或 `effectId`)。
- **edit**:在支持的 macOS/私密 API 版本上编辑已发送消息(`messageId`, `text` 或 `newText`)。
- **unsend**:在支持的 macOS/私密 API 版本上撤回已发送消息(`messageId`)。
- **upload-file**:发送媒体/文件(`buffer` 为 base64 或填充的 `media`/`path`/`filePath`, `filename`, 可选的 `asVoice`)。旧别名:`sendAttachment`。
- **renameGroup**, **setGroupIcon**, **addParticipant**, **removeParticipant**, **leaveGroup**:当当前目标为群聊时管理群组。
消息 ID
入站 iMessage 上下文包含短 `MessageSid` 值,以及条件允许时的完整消息 GUID。短 ID 限定于近期内存回复缓存,并在使用前针对当前聊天进行检查。如果短 ID 已过期或属于其他聊天,请使用完整的 `MessageSidFull` 重试。
能力检测
OpenClaw 仅在缓存的探测状态表明桥接不可用时隐藏私密 API 动作。如果状态未知,动作保持可见且分发时惰性探测,因此第一个动作可以在 `imsg launch` 后成功而无需手动刷新状态。
已读回执与输入指示
当私密 API 桥接启动时,接受的入站聊天在分发前被标记为已读,并在智能体生成时向发件人显示输入气泡。禁用已读标记:
```json5
{
channels: {
imessage: {
sendReadReceipts: false,
},
},
}
```
旧版 `imsg` 构建若早于每个方法的能力列表,将静默地门控输入/已读;OpenClaw 每次重启记录一次性警告,使得缺失的回执可追溯。
入站 tapback
OpenClaw 订阅 iMessage tapback,并将接受的反应作为系统事件而非普通消息文本路由,这样用户 tapback 不会触发普通 reply 循环。
通知模式由 `channels.imessage.reactionNotifications` 控制:
- `"own"`(默认):仅当用户对 bot 编写的消息做出反应时通知。
- `"all"`:通知所有来自授权发件人的入站 tapback。
- `"off"`:忽略入站 tapback。
每个账号覆盖使用 `channels.imessage.accounts.<id>.reactionNotifications`。
配置写入
iMessage 默认允许通道发起的配置写入(用于 /config set|unset 当 commands.config: true 时)。
禁用:
json5
{
channels: {
imessage: {
configWrites: false,
},
},
}合并发送私信(命令 + URL 在同一组合中)
当用户同时输入命令和 URL(如 Dump https://example.com/article),Apple 的 Messages 应用将发送拆分为两个单独的 chat.db 行:
- 一条文本消息(
"Dump")。 - 一个 URL 预览气泡(
"https://..."),附带 OG 预览图片附件。
两个行到达 OpenClaw 的时间间隔约为 0.8-2.0 秒(大多数设置下)。若不做合并,智能体在第 1 轮仅收到命令,回复(通常“请发送 URL”),然后到第 2 轮才看到 URL — 此时命令上下文已丢失。这是 Apple 的发送管道行为,不是 OpenClaw 或 imsg 引入的。
channels.imessage.coalesceSameSenderDms 选择将同一发件人的连续行合并为单个智能体轮次。群聊继续按消息分发,以保留多人轮次结构。
何时启用
启用条件:
- 你提供期望 `command + payload` 在一条消息中的技能(dump, paste, save, queue 等)。
- 你的用户会在命令旁边粘贴 URL、图片或长内容。
- 你能接受增加的私信轮次延迟(见下文)。
保持禁用的情况:
- 你需要针对单字 DM 触发的最小命令延迟。
- 所有流程都是一次性命令,无有效载荷后续。
启用方法
```json5
{
channels: {
imessage: {
coalesceSameSenderDms: true, // 选择启用(默认:false)
},
},
}
```
打开此标志且没有显式 `messages.inbound.byChannel.imessage` 时,去抖窗口会加宽到 **2500 ms**(旧默认值为 0 ms — 不去抖)。加宽窗口是必需的,因为 Apple 的拆分发送节奏为 0.8-2.0 秒,无法放入较紧凑的默认值。
若要自行调整窗口:
```json5
{
messages: {
inbound: {
byChannel: {
// 大多数设置下 2500 ms 工作;若 Mac 较慢或内存压力大,可调至 4000 ms
imessage: 2500,
},
},
},
}
```
权衡
- **私信消息增加延迟。** 打开此标志后,每条 DM(包括独立控制命令和单文本后续)在分发前最多等待去抖窗口,以防有有效载荷行到来。群聊消息保持即时分发。
- **合并输出有上限。** 合并文本上限 4000 字符,超出部分附加 `…[truncated]`;附件上限 20 个;来源条目上限 10 个(超出部分仅保留首个和最新)。每条源 GUID 记录在 `coalescedMessageGuids` 中用于下游遥测。
- **仅限 DM。** 群聊走逐消息分发,以使 bot 在多人同时输入时保持响应。
- **按通道选择启用。** 其他通道(Telegram, WhatsApp, Slack…)不受影响。旧版 BlueBubbles 配置若设置了 `channels.bluebubbles.coalesceSameSenderDms`,应迁移该值到 `channels.imessage.coalesceSameSenderDms`。
场景与智能体看到的内容
| 用户组合 | chat.db 产生 | 标志关闭(默认) | 标志打开 + 2500 ms 窗口 |
|---|---|---|---|
Dump https://example.com(一次发送) | 2 行,间隔约 1 秒 | 两个智能体轮次:先“Dump”,后 URL | 一次轮次:合并文本 Dump https://example.com |
Save this 📎image.jpg caption(附件+文本) | 2 行 | 两个轮次(合并中附件被丢弃) | 一次轮次:文本 + 图片保留 |
/status(独立命令) | 1 行 | 即时分发 | 等待窗口,然后分发 |
| 单独粘贴 URL | 1 行 | 即时分发 | 即时分发(桶中仅一项) |
| 文本+URL,有意分开发送,间隔数分钟 | 2 行,超出窗口 | 两个轮次 | 两个轮次(窗口在间隔间过期) |
| 快速洪泛(窗口内多于 10 条小 DM) | N 行 | N 个轮次 | 一次轮次,有界输出(第一个+最新,文本/附件上限应用) |
| 多人在群聊中同时打字 | 来自 M 个发件人的 N 行 | M+ 个轮次(每个发件人桶一个) | M+ 个轮次 — 群聊不合并 |
网关停机后补发消息
当网关离线时(崩溃、重启、Mac 睡眠、机器关闭),imsg watch 在网关重新上线后从当前 chat.db 状态恢复 — 间隙期间到达的任何消息默认丢失。补发在下次启动时重播这些消息,使智能体不会静默错过入站流量。
补发默认关闭。按通道启用:
ts
channels: {
imessage: {
catchup: {
enabled: true, // 主开关(默认:false)
maxAgeMinutes: 120, // 跳过早于 now - 2h 的行(默认:120,限制 1..720)
perRunLimit: 50, // 每次启动最大重排行数(默认:50,限制 1..500)
firstRunLookbackMinutes: 30, // 首次运行无游标时:回退 30 分钟(默认:30)
maxFailureRetries: 10, // 在 10 次分发失败后放弃楔死的 guid(默认:10)
},
},
}执行方式
每次 monitorIMessageProvider 启动时通行一次,顺序为:imsg launch 就绪 → watch.subscribe → performIMessageCatchup → 实时分发循环。补发本身使用 chats.list + 每个聊天 messages.history,通过同一个用于 imsg watch 的 JSON-RPC 客户端进行。补发期间到达的任何消息通过实时分发正常处理;现有入站去重缓存吸收与重排行重叠的部分。
每个重排行通过实时分发路径(evaluateIMessageInbound + dispatchInboundMessage),因此白名单、群组策略、去抖器、回声缓存和已读回执在重排行和实时消息上行为一致。
游标与重试语义
补发在每个账号下维护一个游标,存储于 <openclawStateDir>/imessage/catchup/<account>__<hash>.json(OpenClaw 状态目录默认 ~/.openclaw,可通过 OPENCLAW_STATE_DIR 覆盖):
json
{
"lastSeenMs": 1717900800000,
"lastSeenRowid": 482910,
"updatedAt": 1717900801234,
"failureRetries": { "<guid>": 1 }
}- 游标在每次成功分发时前进,并在行的分发抛出时保持不动 — 下次启动从保持的游标重试同一行。
- 在相同
guid连续抛出maxFailureRetries次后,补发记录一条warn并强制将游标前进越过该楔死消息,以便后续启动能够进展。 - 已放弃的 guid 在后续运行中跳过(不尝试分发)并在运行摘要中计入
skippedGivenUp。
操作员可见信号
imessage catchup: replayed=N skippedFromMe=… skippedGivenUp=… failed=… givenUp=… fetchedCount=…
imessage catchup: giving up on guid=<guid> after <N> failures; advancing cursor past it
imessage catchup: fetched <X> rows across chats, capped to perRunLimit=<Y>WARN ... capped to perRunLimit 行意味着单次启动未耗尽完整积压。如果间隙通常超过默认的 50 行一次通过,请提高 perRunLimit(最大 500)。
何时保持关闭
- 网关连续运行,配合 watchdog 自动重启,间隙始终小于几秒 — 默认关闭即可。
- DM 流量低,遗漏的消息不会改变智能体行为 — 首次启用时
firstRunLookbackMinutes初始窗口可能分发令人惊讶的旧上下文。
当启用补发时,首次启动(无游标)仅回退 firstRunLookbackMinutes(默认 30 分钟),而非完整的 maxAgeMinutes 窗口 — 这避免了重播启用前的大量历史消息。
故障排查
imsg 未找到或不支持 RPC
验证二进制和 RPC 支持:
```bash
imsg rpc --help
imsg status --json
openclaw channels status --probe
```
如果探测报告 RPC 不受支持,请更新 `imsg`。如果私密 API 动作不可用,在已登录的 macOS 用户会话中运行 `imsg launch` 并重新探测。如果网关未在 macOS 上运行,请使用上述“远程 Mac over SSH”设置代替默认的本地 `imsg` 路径。
网关不在 macOS 上运行
默认 `cliPath: "imsg"` 必须在已登录 Messages 的 Mac 上运行。在 Linux 或 Windows 上,将 `channels.imessage.cliPath` 设置为通过 SSH 连接到该 Mac 并运行 `imsg "$@"` 的包装脚本。
bash
#!/usr/bin/env bash
exec ssh -T messages-mac imsg "$@"然后运行:
bash
openclaw channels status --probe --channel imessage私信被忽略
检查:
- `channels.imessage.dmPolicy`
- `channels.imessage.allowFrom`
- 配对审批状态(`openclaw pairing list imessage`)
群组消息被忽略
检查:
- `channels.imessage.groupPolicy`
- `channels.imessage.groupAllowFrom`
- `channels.imessage.groups` 白名单行为
- 提及模式配置(`agents.list[].groupChat.mentionPatterns`)
远程附件失败
检查:
- `channels.imessage.remoteHost`
- `channels.imessage.remoteAttachmentRoots`
- 网关主机上的 SSH/SCP 密钥认证
- 网关主机上 `~/.ssh/known_hosts` 中存在主机密钥
- 运行 Messages 的 Mac 上远程路径的可读性
macOS 权限提示被错过
在相同用户/会话上下文的交互式 GUI 终端中重新运行并批准提示:
```bash
imsg chats --limit 1
imsg send <handle> "test"
```
确认运行 OpenClaw/`imsg` 的进程上下文已授予完全磁盘访问 + 自动化权限。
配置参考指针
相关链接
- 渠道概览 — 所有支持的渠道
- BlueBubbles 移除及 imsg iMessage 路径 — 公告和迁移总结
- 从 BlueBubbles 迁移 — 配置转换表和逐步切换
- 配对 — 私信认证与配对流程
- 群组 — 群组行为与提及门控
- 频道路由 — 消息的会话路由
- 安全 — 访问模型与加固
常见问题
imsg 连接失败时怎么排查?
先确认 imsg rpc --help 正常输出,然后运行 openclaw channels status --probe 查看通道状态。如果探测显示 RPC 不受支持,更新 imsg。若私密 API 不可用,检查 SIP 是否已关闭并运行 imsg launch。如果是远程 Mac,确保 SSH 包装脚本将参数正确传递,并且网关主机上的 ~/.ssh/known_hosts 包含远程主机密钥。
群组消息被丢弃但私信正常,是什么原因?
检查两个门控:① channels.imessage.groupPolicy 是否为 allowlist,以及 groupAllowFrom 是否包含发件人或群组标识;② channels.imessage.groups 是否非空(至少需要 "*": {} 通配符或每个 chat_id 的显式条目)。如果缺少 groups 块,群组消息会被丢弃,网关日志会输出 WARN dropping group message。
远程 Mac 附件下载失败怎么办?
确认 remoteHost 格式正确(user@host),并且网关主机上已通过 ssh user@host 将主机密钥加入 ~/.ssh/known_hosts。检查 remoteAttachmentRoots 是否包含附件实际路径(默认 /Users/*/Library/Messages/Attachments)。此外,确保运行 Messages 的 Mac 上附件目录可读,且 SCP 密钥认证无需交互。