跳转到主要内容
对于 OpenClaw iMessage 部署,请在已登录的 macOS Messages 主机上使用 imsg。如果你的 Gateway 网关运行在 Linux 或 Windows 上,请将 channels.imessage.cliPath 指向一个 SSH 包装器,由它在 Mac 上运行 imsg入站恢复是自动的。 在 bridge 或 Gateway 网关重启后,iMessage 会重放停机期间错过的消息,并抑制 Apple 在 Push 恢复后可能刷出的陈旧“积压消息炸弹”,同时去重,确保不会重复分发任何内容。无需配置启用 — 请参阅bridge 或 Gateway 网关重启后的入站恢复
BlueBubbles 支持已移除。请将 channels.bluebubbles 配置迁移到 channels.imessage;OpenClaw 仅通过 imsg 支持 iMessage。短公告请先阅读 BlueBubbles removal and the imsg iMessage path,完整迁移表请阅读 Coming from BlueBubbles
状态:原生外部 CLI 集成。Gateway 网关会启动 imsg rpc,并通过 stdio 使用 JSON-RPC 通信 — 无需单独的 daemon 或端口。高级操作需要 imsg launch 和成功的私有 API 探测。

Private API actions

回复、tapback、效果、投票、附件和群组管理。

Pairing

iMessage 私信默认使用配对模式。

Remote Mac

当 Gateway 网关未运行在 Messages Mac 上时,请使用 SSH 包装器。

Configuration reference

完整的 iMessage 字段参考。

快速设置

1

Install and verify imsg

brew install steipete/tap/imsg
imsg rpc --help
imsg launch
openclaw channels status --probe
2

Configure OpenClaw

{
  channels: {
    imessage: {
      enabled: true,
      cliPath: "/usr/local/bin/imsg",
      dbPath: "/Users/user/Library/Messages/chat.db",
    },
  },
}
3

Start gateway

openclaw gateway
4

Approve first DM pairing (default dmPolicy)

openclaw pairing list imessage
openclaw pairing approve imessage <CODE>
配对请求会在 1 小时后过期。

要求和权限(macOS)

  • Messages 必须在运行 imsg 的 Mac 上登录。
  • 运行 OpenClaw/imsg 的进程上下文需要 Full Disk Access(用于访问 Messages DB)。
  • 通过 Messages.app 发送消息需要 Automation 权限。
  • 对于高级操作(react / edit / unsend / threaded reply / effects / polls / group ops),必须禁用 System Integrity Protection — 请参阅启用 imsg 私有 API。基础文本和媒体收发不需要禁用它。
权限按进程上下文授予。如果 Gateway 网关以无头方式运行(LaunchAgent/SSH),请在同一上下文中运行一次交互式命令以触发提示:
imsg chats --limit 1
# or
imsg send <handle> "test"
远程 SSH 设置可以读取聊天、通过 channels status --probe,并处理入站消息,但出站发送仍可能因 AppleEvents 授权错误而失败:
Not authorized to send Apple events to Messages. (-1743)
检查已登录 Mac 用户的 TCC 数据库,或 System Settings > Privacy & Security > Automation。如果 Automation 条目记录的是 /usr/libexec/sshd-keygen-wrapper,而不是 imsg 或本地 shell 进程,macOS 可能不会为该 SSH 服务器端客户端显示可用的 Messages 开关:
kTCCServiceAppleEvents | /usr/libexec/sshd-keygen-wrapper | auth_value=0 | com.apple.MobileSMS
在这种状态下,反复执行 tccutil reset AppleEvents 或通过同一个 SSH 包装器重新运行 imsg send 可能仍会失败,因为需要 Messages Automation 的进程上下文是 SSH 包装器,而不是 UI 可以授权的应用。请改用受支持的 imsg 进程上下文之一:
  • 在已登录 Messages 用户的本地会话中运行 Gateway 网关,或至少运行 imsg bridge。
  • 在同一会话中授予 Full Disk Access 和 Automation 后,为该用户使用 LaunchAgent 启动 Gateway 网关。
  • 如果保留双用户 SSH 拓扑,请在启用渠道前验证真正的出站 imsg send 能通过完全相同的包装器成功。如果无法授予 Automation,请改为重新配置为单用户 imsg 设置,而不是依赖 SSH 包装器进行发送。

启用 imsg 私有 API

imsg 提供两种运行模式:
  • 基础模式(默认,无需更改 SIP):通过 send 发送出站文本和媒体,入站 watch/history,聊天列表。这是全新 brew install steipete/tap/imsg 加上上面标准 macOS 权限后即可获得的模式。
  • 私有 API 模式imsg 将辅助 dylib 注入 Messages.app,以调用内部 IMCore 函数。这会解锁 reacteditunsendreply(threaded)、sendWithEffectpollpoll-vote(原生 Messages 投票)、renameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup,以及正在输入指示和已读回执。
本页上的高级操作面需要私有 API 模式。imsg README 明确说明了该要求:
高级功能,例如 readtypinglaunch、bridge 支持的富发送、消息变更和聊天管理,都是选择启用的。它们要求禁用 SIP,并将辅助 dylib 注入 Messages.app。当 SIP 启用时,imsg launch 会拒绝注入。
该辅助注入技术使用 imsg 自身的 dylib 访问 Messages 私有 API。OpenClaw iMessage 路径中没有第三方服务器或 BlueBubbles 运行时。
禁用 SIP 是真实的安全权衡。 SIP 是 macOS 防止运行被修改系统代码的核心保护之一;在系统范围内关闭它会带来额外攻击面和副作用。特别是,在 Apple Silicon Mac 上禁用 SIP 还会禁用在你的 Mac 上安装和运行 iOS 应用的能力请将其视为有意的运维选择,而不是默认选项。如果你的威胁模型无法容忍关闭 SIP,内置 iMessage 将仅限于基础模式 — 只能收发文本和媒体,没有 reaction / edit / unsend / effects / group ops。

设置

  1. 在运行 Messages.app 的 Mac 上安装(或升级)imsg
    brew install steipete/tap/imsg
    imsg --version
    imsg status --json
    
    imsg status --json 输出会报告 bridge_versionrpc_methods 和按方法列出的 selectors,因此你可以在开始前查看当前构建支持什么。
  2. 禁用 System Integrity Protection,并且(在现代 macOS 上)禁用 Library Validation。 将非 Apple 辅助 dylib 注入 Apple 签名的 Messages.app 需要关闭 SIP,并且放宽 library validation。Recovery 模式下的 SIP 步骤因 macOS 版本而异:
    • macOS 10.13-10.15(Sierra-Catalina): 通过 Terminal 禁用 Library Validation,重启到 Recovery Mode,运行 csrutil disable,然后重启。
    • macOS 11+(Big Sur 及更高版本),Intel: 进入 Recovery Mode(或 Internet Recovery),运行 csrutil disable,然后重启。
    • macOS 11+,Apple Silicon: 使用电源按钮启动流程进入 Recovery;在近期 macOS 版本中,点击 Continue 时按住左 Shift 键,然后运行 csrutil disable。虚拟机设置遵循单独流程,因此请先创建 VM 快照。
    在 macOS 11 及更高版本上,仅运行 csrutil disable 通常不够。 Apple 仍会把 Messages.app 作为平台二进制文件强制执行 library validation,因此即使 SIP 关闭,adhoc 签名的辅助程序也会被拒绝(Library Validation failed: ... platform binary, but mapped file is not)。禁用 SIP 后,还要禁用 library validation 并重启:
    sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool true
    
    macOS 26(Tahoe),已在 26.5.1 验证: 关闭 SIP 加上上面的 DisableLibraryValidation 命令,足以在 26.0 到 26.5.x 中注入辅助程序。不需要 boot-args。 该 plist 是决定性因素,也是 Tahoe 上注入失败时最常漏掉的步骤:
    • 有该 plist: imsg launch 会注入,且 imsg status 会报告 advanced_features: true
    • 没有该 plist(即使 SIP 关闭): imsg launch 会失败并显示 Failed to launch: Timeout waiting for Messages.app to initialize。AMFI 在加载时拒绝 adhoc 辅助程序,因此 bridge 永远无法就绪,launch 最终超时。这个超时是大多数人在 Tahoe 上遇到的症状;修复方法是上面的 plist,而不是采取更激进的措施。
    如果 macOS 升级后 imsg launch 注入或特定 selectors 开始返回 false,此门槛通常就是原因。请先检查 SIP 和 library-validation 状态,再假设 SIP 步骤本身失败。如果这些设置正确但 bridge 仍无法注入,请收集 imsg status --jsonimsg launch 输出,并报告给 imsg 项目,而不是削弱更多系统范围的安全控制。
  3. 注入 helper。 在 SIP 已禁用且 Messages.app 已登录的情况下:
    imsg launch
    
    当 SIP 仍处于启用状态时,imsg launch 会拒绝注入,因此这也可以作为第 2 步已生效的确认。
  4. 从 OpenClaw 验证 bridge:
    openclaw channels status --probe
    
    iMessage 条目应报告 works,并且 imsg status --json | jq '{rpc_methods, selectors}' 应显示你的 macOS 构建暴露的能力。创建投票需要 selectors.pollPayloadMessage;投票需要同时具备 selectors.pollVoteMessagepoll.vote RPC 方法。OpenClaw 插件只通告缓存探测支持的操作,而空缓存会保持乐观,并在首次分发时探测。
如果 openclaw channels status --probe 报告该渠道为 works,但特定操作在分发时抛出 “iMessage <action> requires the imsg private API bridge”,请再次运行 imsg launch——helper 可能会脱离(Messages.app 重启、OS 更新等),并且缓存的 available: true 状态会继续通告操作,直到下一次探测刷新。

当 SIP 保持启用时

如果禁用 SIP 不符合你的威胁模型:
  • imsg 会回退到基础模式——仅支持文本 + 媒体 + 接收。
  • OpenClaw 插件仍会通告文本/媒体发送和入站监控;它会从操作表面隐藏 reacteditunsendreplysendWithEffect 和群组操作(按照逐方法能力门控)。
  • 你可以运行一台单独的非 Apple-Silicon Mac(或专用 bot Mac),为 iMessage 工作负载关闭 SIP,同时在你的主设备上保持 SIP 启用。请参阅下方的 Dedicated bot macOS user (separate iMessage identity)

访问控制和路由

channels.imessage.dmPolicy 控制私信:
  • pairing(默认)
  • allowlist(需要至少一个 allowFrom 条目)
  • open(需要 allowFrom 包含 "*"
  • disabled
允许列表字段:channels.imessage.allowFrom允许列表条目必须标识发送者:handle 或静态发送者访问组(accessGroup:<name>)。对 chat_id:*chat_guid:*chat_identifier:* 等聊天目标使用 channels.imessage.groupAllowFrom;对数字 chat_id 注册表键使用 channels.imessage.groups

ACP 对话绑定

iMessage 聊天可以绑定到 ACP 会话。 快速操作员流程:
  • 在私信或允许的群组聊天中运行 /acp spawn codex --bind here
  • 同一 iMessage 对话中的未来消息会路由到已生成的 ACP 会话。
  • /new/reset 会在原处重置同一个已绑定 ACP 会话。
  • /acp close 会关闭 ACP 会话并移除绑定。
已配置的持久绑定使用顶层 bindings[] 条目,并带有 type: "acp"match.channel: "imessage" match.peer.id 可以使用:
  • 规范化的私信 handle,例如 +15555550123user@example.com
  • chat_id:<id>(推荐用于稳定群组绑定)
  • chat_guid:<guid>
  • chat_identifier:<identifier>
示例:
{
  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 绑定行为,请参阅 ACP 智能体

部署模式

使用专用 Apple ID 和 macOS 用户,使 bot 流量与你的个人 Messages 资料隔离。典型流程:
  1. 创建/登录专用 macOS 用户。
  2. 在该用户中使用 bot Apple ID 登录 Messages。
  3. 在该用户中安装 imsg
  4. 创建 SSH wrapper,使 OpenClaw 可以在该用户上下文中运行 imsg
  5. channels.imessage.accounts.<id>.cliPath.dbPath 指向该用户资料。
首次运行可能需要在该 bot 用户会话中进行 GUI 审批(Automation + Full Disk Access)。
常见拓扑:
  • Gateway 网关运行在 Linux/VM 上
  • iMessage + imsg 运行在你的 tailnet 中的一台 Mac 上
  • cliPath wrapper 使用 SSH 运行 imsg
  • remoteHost 启用 SCP 附件获取
示例:
{
  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",
    },
  },
}
#!/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 下的逐账户配置。每个账户都可以覆盖 cliPathdbPathallowFromgroupPolicymediaMaxMb、历史设置和附件根允许列表等字段。
设置 channels.imessage.dmHistoryLimit,用该对话最近解码的 imsg 历史为新的私信会话播种。使用 channels.imessage.dms["<sender>"].historyLimit 进行逐发送者覆盖,包括设为 0 以禁用某个发送者的历史。iMessage 私信历史会按需从 imsg 获取。未设置 dmHistoryLimit 会禁用全局私信历史播种,但正数的逐发送者 channels.imessage.dms["<sender>"].historyLimit 仍会为该发送者启用播种。

媒体、分块和投递目标

  • 入站附件摄取默认关闭 — 设置 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(优先按段落拆分)
  • 出站 markdown 粗体/斜体/下划线/删除线会转换为原生样式文本(macOS 15+ 接收者会渲染样式;较旧的接收者会看到不带标记的纯文本);markdown 表格会按该渠道的 markdown 表格模式转换
  • channels.imessage.sendTransport(默认 autobridgeapplescript)选择 imsg 如何发送消息
首选显式目标:
  • chat_id:123(建议用于稳定路由)
  • chat_guid:...
  • chat_identifier:...
也支持句柄目标:
  • imessage:+1555...
  • sms:+1555...
  • user@example.com
imsg chats --limit 20

私有 API 操作

imsg launch 正在运行,并且 openclaw channels status --probe 报告 privateApi.available: true 时,消息工具除了常规文本发送外,还可以使用 iMessage 原生操作。 所有操作默认启用;使用 channels.imessage.actions 关闭单个操作:
{
  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,
        polls: true,
      },
    },
  },
}
  • react:添加/移除 iMessage tapback(messageIdemojiremove)。支持的 tapback 映射到爱心、喜欢、不喜欢、大笑、强调和疑问。不带 emoji 移除时,会清除已设置的任意 tapback。
  • reply:向现有消息发送线程回复(messageIdtextmessage,以及 chatGuidchatIdchatIdentifierto)。带附件回复还需要 send-rich 支持 --fileimsg 构建。
  • sendWithEffect:发送带 iMessage 效果的文本(textmessageeffecteffectId)。短名称:slam、loud、gentle、invisibleink、confetti、lasers、fireworks、balloon、heart、echo、happybirthday、shootingstar、sparkles、spotlight。
  • edit:在支持的 macOS/私有 API 版本上编辑已发送消息(messageIdtextnewText)。只能编辑 Gateway 网关自己发送的消息。
  • unsend:在支持的 macOS/私有 API 版本上撤回已发送消息(messageId)。只能撤回 Gateway 网关自己发送的消息。
  • upload-file:发送媒体/文件(buffer 为 base64,或已水合的 media/path/filePathfilename,可选 asVoice)。旧别名:sendAttachment
  • renameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup:当前目标为群组会话时管理群聊。这些操作会修改主机的 Messages 身份,因此需要所有者发送者或 operator.admin Gateway 网关客户端。
  • poll:创建原生 Apple Messages 投票(pollQuestionpollOption 重复 2 到 12 次,以及 chatGuidchatIdchatIdentifierto)。iOS/iPadOS/macOS 26+ 上的接收者可以原生查看并投票;较旧的 OS 版本会收到 “Sent a poll” 文本降级提示。需要 selectors.pollPayloadMessage
  • poll-vote:对现有投票投票(pollIdmessageId,以及 pollOptionIndexpollOptionIdpollOptionText 中恰好一个)。需要 selectors.pollVoteMessagepoll.vote RPC 方法。
已接受的入站投票会呈现给智能体,包含问题、带编号的选项标签、票数,以及 poll-vote 所需的投票消息 ID。
入站 iMessage 上下文在可用时同时包含短 MessageSid 值和完整消息 GUID(MessageSidFull)。短 ID 的作用域限于近期 SQLite 支持的回复缓存,使用前会根据当前聊天进行检查。如果短 ID 已过期或属于另一个聊天,请用完整的 MessageSidFull 重试。
只有当缓存的探测状态表示桥接不可用时,OpenClaw 才会隐藏私有 API 操作。如果状态未知,操作仍保持可见,并会在派发时延迟探测,因此在 imsg launch 后第一个操作无需单独手动刷新状态也可以成功。
私有 API 桥接启动后,已接受的入站聊天会被标记为已读,并且直接聊天会在轮次被接受后立即显示正在输入气泡,同时智能体准备上下文并生成回复。用以下配置禁用已读标记:
{
  channels: {
    imessage: {
      sendReadReceipts: false,
    },
  },
}
早于按方法能力列表的较旧 imsg 构建会静默关闭正在输入/已读;OpenClaw 会在每次重启后记录一次性警告,方便归因缺失的回执。
OpenClaw 订阅 iMessage tapback,并将已接受的表情回应路由为系统事件,而不是普通消息文本,因此用户 tapback 不会触发普通回复循环。通知模式由 channels.imessage.reactionNotifications 控制:
  • "own"(默认):仅当用户对机器人编写的消息作出表情回应时通知。
  • "all":通知来自授权发送者的所有入站 tapback。
  • "off":忽略入站 tapback。
按账户覆盖使用 channels.imessage.accounts.<id>.reactionNotifications
approvals.exec.enabledapprovals.plugin.enabled 为 true 且请求路由到 iMessage 时,Gateway 网关会以原生方式发送审批提示,并接受 tapback 来完成审批:
  • 👍(喜欢 tapback)→ allow-once
  • 👎(不喜欢 tapback)→ deny
  • allow-always 保留为手动降级方案:以普通回复发送 /approve <id> allow-always
表情回应处理要求作出回应的用户句柄是显式审批者。审批者列表从 channels.imessage.allowFrom(或 channels.imessage.accounts.<id>.allowFrom)读取;添加用户的 E.164 格式电话号码或其 Apple ID 邮箱(诸如 chat_id:* 的聊天目标不是有效审批者条目)。通配符条目 "*" 会生效,但允许任何发送者审批;空审批者列表会完全禁用表情回应快捷方式。表情回应快捷方式会有意绕过 reactionNotificationsdmPolicygroupAllowFrom,因为显式审批者允许列表是审批解析唯一相关的门禁。/approve 文本命令授权遵循同一列表:当 channels.imessage.allowFrom 非空时,/approve <id> <decision> 会根据该审批者列表授权(而不是更广泛的私信允许列表),在私信允许列表中被允许但不在 allowFrom 中的发送者会收到明确拒绝。当 allowFrom 为空时,同聊天降级方案仍然生效,/approve 会授权私信允许列表允许的任何人。将所有应该审批的操作员(无论通过 /approve 还是通过表情回应)添加到 allowFrom操作员说明:
  • 表情回应绑定同时存储在内存和 Gateway 网关的持久键值存储中(TTL 与审批过期时间匹配),并且 Gateway 网关还会轮询待处理提示的 tapback,因此 Gateway 网关重启后不久到达的 tapback 仍会完成审批。
  • 当该句柄是显式审批者时,操作员自己的 is_from_me=true tapback(例如来自已配对的 Apple 设备)会完成审批。
  • 只有配置了显式审批者时,审批提示才会路由到群组会话;否则任何群组成员都可能审批。
  • 旧版文本样式 tapback(很旧的 Apple 客户端发出的 Liked "…" 纯文本)无法完成审批,因为它们不携带消息 GUID;表情回应解析需要当前 macOS / iOS 客户端发出的结构化 tapback 元数据。

配置写入

iMessage 默认允许由渠道发起的配置写入(用于 commands.config: true 时的 /config set|unset)。 禁用:
{
  channels: {
    imessage: {
      configWrites: false,
    },
  },
}

合并拆分发送的私信(一次输入中的命令 + URL)

当用户同时输入命令和 URL,例如 Dump https://example.com/article,Apple 的 Messages 应用会将发送拆分成两条独立的 chat.db
  1. 文本消息("Dump")。
  2. URL 预览气泡("https://..."),带有作为附件的 OG 预览图片。
在大多数设置中,这两行会相隔约 0.8 到 2.0 秒到达 OpenClaw。没有合并时,智能体在轮次 1 只会收到命令(并且常常回复“把 URL 发给我”),随后 URL 才会在轮次 2 到达。这是 Apple 的发送管线行为,不是 OpenClaw 或 imsg 引入的。 channels.imessage.coalesceSameSenderDms 会让私信选择缓冲同一发送者连续发送的行。当 imsg 在某个源行上暴露结构化 URL 预览标记 balloon_bundle_id: "com.apple.messages.URLBalloonProvider" 时,OpenClaw 只合并该真实的拆分发送,并将其他任何缓冲的行保留为独立轮次。在完全不发出气泡元数据的较旧 imsg 构建上,OpenClaw 无法区分拆分发送和独立发送,因此会降级为合并整个桶。这样会保留元数据出现前的行为,而不是让 Dump <url> 拆分发送回退成两个轮次。群聊继续按消息派发,以保留多用户轮次结构。
在以下情况下启用:
  • 你发布的 Skills 期望一条消息内包含 command + payload(dump、paste、save、queue 等)。
  • 你的用户会把 URL 和命令一起粘贴。
  • 你可以接受增加的私信轮次延迟(见下文)。
在以下情况下保持禁用:
  • 你需要单词私信触发器的最低命令延迟。
  • 你的所有流程都是没有后续载荷的一次性命令。

场景以及智能体看到的内容

“标志开启”列展示的是会发出 balloon_bundle_idimsg 构建上的行为。在完全不发出气泡元数据的旧版 imsg 构建上,下方标记为“两轮”/“N 轮”的行会改为回退到旧版合并(一轮):OpenClaw 无法从结构上区分拆分发送和单独发送,因此会保留元数据出现之前的合并行为。一旦构建发出气泡元数据,精确分离就会激活。
用户编写内容chat.db 产生内容标志关闭(默认)标志开启 + 窗口(imsg 发出气泡元数据)
Dump https://example.com(一次发送)2 行,间隔约 1 秒两个智能体轮次:“Dump” 单独一轮,然后 URL一轮:合并文本 Dump https://example.com
Save this 📎image.jpg caption(附件 + 文本)2 行,无 URL 气泡元数据两轮观察到元数据后为两轮;在旧版/锁存前的无元数据会话中为一个合并轮次
/status(独立命令)1 行即时分发最多等待窗口时间,然后分发
单独粘贴 URL1 行即时分发最多等待窗口时间,然后分发
文本 + URL 作为两条有意分开发送的消息,间隔数分钟2 行,位于窗口之外两轮两轮(窗口在它们之间过期)
快速刷屏(窗口内 >10 条小私信)N 行,无 URL 气泡元数据N 轮观察到元数据后为 N 轮;在旧版/锁存前的无元数据会话中为一个有边界的合并轮次
群聊中两个人正在输入来自 M 个发送者的 N 行M+ 轮(每个发送者桶一个)M+ 轮 — 群聊不会被合并

桥接或 Gateway 网关重启后的入站恢复

iMessage 会恢复 Gateway 网关停机期间错过的消息,同时抑制 Apple 在 Push 恢复后可能刷出的陈旧“积压炸弹”。默认行为始终开启,基于入站去重构建。
  • 重放去重。 每条已分发的入站消息都会按其 Apple GUID 记录在持久化插件状态(imessage.inbound-dedupe)中,在摄取时声明,并在处理后提交(瞬时失败时释放,以便重试)。任何已处理的内容都会被丢弃,而不是重复分发。这让恢复可以积极重放,而无需逐消息记账。
  • 停机恢复。 启动时,监视器会记住最后分发的 chat.db rowid(一个持久化的按账户游标),并将它作为 since_rowid 传给 imsg watch.subscribe,因此 imsg 会重放 Gateway 网关停机期间落入的行,然后跟随实时数据。重放被限制在最近 500 行以及约 2 小时内的消息,去重会丢弃任何已处理内容。
  • 陈旧积压年龄围栏。 启动边界以上的行是真正的实时消息;如果某行的发送日期比到达时间早超过约 15 分钟,它就是 Push 刷出的积压,会被抑制。重放行(位于边界或边界以下)改用更宽的恢复窗口,因此最近错过的消息会送达,而久远历史不会送达。
恢复同时适用于本地和远程 cliPath 设置,因为 since_rowid 重放运行在同一条 imsg RPC 连接上。区别在于窗口:当 Gateway 网关可以读取 chat.db(本地)时,它会锚定启动 rowid 边界、限制重放跨度,并送达最多约数小时前错过的消息。通过远程 SSH cliPath 时,它无法读取数据库,因此重放不设上限,并且每一行都使用实时年龄围栏 — 它仍会恢复最近错过的消息,也仍会抑制旧积压,只是使用更窄的实时窗口。请在运行 Messages 的 Mac 上运行 Gateway 网关,以获得更宽的恢复窗口。

操作员可见信号

被抑制的积压会以默认级别记录日志,绝不会静默丢弃(recovery 标志显示应用了哪个窗口):
imessage: suppressed stale inbound backlog account=<id> sent=<iso> recovery=<bool> (<N> suppressed since start)

迁移

channels.imessage.catchup.* 已弃用 — 停机恢复是自动的,新设置无需配置。带有 catchup.enabled: true 的现有配置仍会作为恢复重放窗口的兼容性配置文件受到支持。已禁用的 catchup 块(enabled: false 或没有 enabled: true)已退役;openclaw doctor --fix 会移除这些块。

故障排查

验证二进制文件和 RPC 支持:
imsg rpc --help
imsg status --json
openclaw channels status --probe
如果探测报告不支持 RPC,请更新 imsg。如果私有 API 操作不可用,请在已登录的 macOS 用户会话中运行 imsg launch,然后再次探测。如果 Gateway 网关未在 macOS 上运行,请改用上面的通过 SSH 连接远程 Mac 设置,而不是默认的本地 imsg 路径。
首先证明消息是否到达了本地 Mac。如果 chat.db 没有变化,即使 imsg status --json 报告桥接健康,OpenClaw 也无法接收该消息。
imsg chats --limit 10 --json
imsg watch --chat-id <chat-id> --json
sqlite3 ~/Library/Messages/chat.db \
  "select datetime(max(date)/1000000000 + 978307200, 'unixepoch', 'localtime'), max(ROWID) from message;"
如果从手机发送的消息没有创建新行,请先修复 macOS Messages 和 Apple Push 层,再更改 OpenClaw 配置。一次性服务刷新通常就足够:
launchctl kickstart -k system/com.apple.apsd
launchctl kickstart -k gui/$(id -u)/com.apple.CommCenter
launchctl kickstart -k gui/$(id -u)/com.apple.identityservicesd
launchctl kickstart -k gui/$(id -u)/com.apple.imagent
imsg launch
openclaw gateway restart
从手机发送一条新的 iMessage,并在调试 OpenClaw 会话前确认出现新的 chat.db 行或 imsg watch 事件。不要将这作为周期性桥接重启循环来运行;在活跃工作期间反复执行 imsg launch 加 Gateway 网关重启可能会中断投递,并使正在进行的渠道运行滞留。
默认 cliPath: "imsg" 必须在登录了 Messages 的 Mac 上运行。在 Linux 或 Windows 上,将 channels.imessage.cliPath 设置为一个包装脚本,该脚本通过 SSH 连接到那台 Mac 并运行 imsg "$@"
#!/usr/bin/env bash
exec ssh -T messages-mac imsg "$@"
然后运行:
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
  • 来自 Gateway 网关主机的 SSH/SCP 密钥认证
  • Gateway 网关主机上的 ~/.ssh/known_hosts 中存在主机密钥
  • 运行 Messages 的 Mac 上远程路径的可读性
在同一用户/会话上下文中的交互式 GUI 终端里重新运行,并批准提示:
imsg chats --limit 1
imsg send <handle> "test"
确认为运行 OpenClaw/imsg 的进程上下文授予了“完全磁盘访问权限”和“自动化”。

配置参考指针

相关