Skip to main content
对于 OpenClaw iMessage 部署,请在已登录的 macOS Messages 主机上使用 imsg。如果你的 Gateway 运行在 Linux 或 Windows 上,请将 channels.imessage.cliPath 指向一个通过 SSH 在 Mac 上运行 imsg 的包装器。入站恢复是自动的。 在桥接或网关重启后,iMessage 会重放停机期间遗漏的消息,并抑制 Apple 在 Push 恢复后可能刷出的过时“积压炸弹”,通过去重确保不会重复分发任何内容。无需启用任何配置——请参见桥接或网关重启后的入站恢复
BlueBubbles 支持已被移除。请将 channels.bluebubbles 配置迁移到 channels.imessage;OpenClaw 仅通过 imsg 支持 iMessage。从 BlueBubbles 移除与 imsg iMessage 路径 查看简短公告,或从 来自 BlueBubbles 查看完整迁移表。
状态:原生外部 CLI 集成。Gateway 会启动 imsg rpc,并通过 stdio 上的 JSON-RPC 通信(没有单独的守护进程/端口)。高级操作需要 imsg launch 以及成功的私有 API 探测。

私有 API 操作

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

配对

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

远程 Mac

当 Gateway 不在 Messages 所在的 Mac 上运行时,请使用 SSH 包装器。

配置参考

iMessage 字段完整参考。

快速设置

1

安装并验证 imsg

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

配置 OpenClaw

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

启动 gateway

openclaw gateway
4

批准首次私信配对(默认 dmPolicy)

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

要求和权限(macOS)

  • Messages 必须在运行 imsg 的 Mac 上已登录。
  • 运行 OpenClaw/imsg 的进程上下文需要完全磁盘访问权限(用于访问 Messages 数据库)。
  • 通过 Messages.app 发送消息需要自动化权限。
  • 对于高级操作(react / edit / unsend / threaded reply / effects / group ops),必须禁用系统完整性保护(SIP)——见下方 启用 imsg 私有 API。基础文本和媒体收发在不禁用 SIP 的情况下也能工作。
权限是按进程上下文授予的。如果 gateway 以无头方式运行(LaunchAgent/SSH),请在相同上下文中运行一次交互式命令以触发权限提示:
imsg chats --limit 1
# 或
imsg send <handle> "test"
远程 SSH 设置可以读取聊天、通过 channels status --probe,并处理入站消息,但外发发送仍会因 AppleEvents 授权错误而失败:
Not authorized to send Apple events to Messages. (-1743)
检查已登录 Mac 用户的 TCC 数据库或“系统设置” > “隐私与安全性” > “自动化”。如果自动化条目记录在 /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。
  • 在授予同一会话中的完全磁盘访问权限和自动化权限后,使用该用户的 LaunchAgent 启动 Gateway。
  • 如果你保留双用户 SSH 拓扑,请在启用通道之前,验证一次真实的外发 imsg send 是否能通过确切的包装器成功。如果无法授予 Automation,请改为单用户 imsg 设置,而不要依赖 SSH 包装器来发送消息。

启用 imsg 私有 API

imsg 提供两种运行模式:
  • 基础模式(默认,不需要更改 SIP):通过 send 发送外发文本和媒体、入站监控/历史、聊天列表。这就是在全新安装 brew install steipete/tap/imsg 并授予上面列出的标准 macOS 权限后可直接获得的能力。
  • 私有 API 模式imsg 会将一个 helper dylib 注入 Messages.app,以调用内部 IMCore 函数。这会解锁 reacteditunsendreply(线程式)、sendWithEffectrenameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup,以及输入状态指示和已读回执。
要达到本页面所描述的这个通道的高级操作能力,你需要私有 API 模式。imsg 的 README 明确说明了这一点:
诸如 readtypinglaunch、基于桥接的富发送、消息变更和聊天管理等高级功能都是可选的。它们需要禁用 SIP,并将一个 helper dylib 注入到 Messages.app 中。启用 SIP 时,imsg launch 会拒绝注入。
这种 helper 注入技术使用的是 imsg 自己的 dylib 来访问 Messages 的私有 API。在 OpenClaw 的 iMessage 路径中,没有第三方服务器或 BlueBubbles 运行时。
禁用 SIP 是真实的安全权衡。 SIP 是 macOS 防止运行被修改系统代码的核心保护之一;在系统范围内关闭它会带来额外的攻击面和副作用。尤其是,在 Apple Silicon Mac 上禁用 SIP 也会禁用在你的 Mac 上安装和运行 iOS App 的能力请将其视为一个有意的运维决策,而不是默认设置。如果你的威胁模型不能接受关闭 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. 禁用系统完整性保护,并且(在现代 macOS 上)禁用 Library Validation。 将非 Apple 的 helper 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 时按住 Left Shift 键,然后运行 csrutil disable。虚拟机环境遵循单独流程,因此请先拍摄 VM 快照。
    在 macOS 11 及更高版本上,单独执行 csrutil disable 通常还不够。 Apple 仍然会将 Messages.app 作为平台二进制文件执行 library validation,因此即使关闭 SIP,adhoc 签名的 helper 也会被拒绝(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 之间注入 helper。不需要 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 helper,因此 bridge 永远无法就绪,启动也会超时。这个超时是 Tahoe 上大多数人遇到的症状,修复方法就是上面的 plist,而不是采取更激进的措施。
    这一点已在 macOS 26.5.1(Apple Silicon)上通过受控的前后对比得到确认:有 plist 时,dylib 会映射进 Messages.app,bridge 会启动;移除 plist 并重启后,imsg launch 会产生上面的超时失败,并且 dylib 不会被映射。 如果在 macOS 升级后,imsg launch 注入或某些特定 selectors 开始返回 false,通常就是这个门槛导致的。在假设 SIP 步骤本身失败之前,请先检查你的 SIP 和 library-validation 状态。如果这些设置都正确,但 bridge 仍然无法注入,请收集 imsg status --jsonimsg launch 的输出并反馈给 imsg 项目,而不是进一步削弱系统级安全控制。 在运行 imsg launch 之前,请按照 Apple 针对你的 Mac 的恢复模式流程禁用 SIP。
  3. 注入 helper。 在 SIP 已禁用且 Messages.app 已登录的情况下:
    imsg launch
    
    当 SIP 仍启用时,imsg launch 会拒绝注入,因此这也可作为第 2 步是否生效的确认。
  4. 从 OpenClaw 验证桥接:
    openclaw channels status --probe
    
    iMessage 条目应报告为 works,并且 imsg status --json | jq '.selectors' 应显示 retractMessagePart: true,以及你的 macOS 构建所暴露的编辑 / 输入状态 / 已读等选择器。OpenClaw 插件在 actions.ts 中按方法进行的能力门控,只会公开其底层 selector 为 true 的操作,因此你在代理工具列表中看到的动作范围,反映了该主机上的桥接实际能做什么。
如果 openclaw channels status --probe 将该通道报告为 works,但在分发时某些特定操作抛出 “iMessage <action> requires the imsg private API bridge”,请再次运行 imsg launch——helper 可能会脱落(Messages.app 重启、系统更新等),而缓存的 available: true 状态会继续宣告这些操作,直到下一次探测刷新它为止。

当你无法禁用 SIP 时

如果你的威胁模型不接受禁用 SIP:
  • imsg 会回退到基础模式——仅文本 + 媒体 + 接收。
  • OpenClaw 插件仍会公开文本/媒体发送和入站监控;只是会根据按方法的能力门控,在动作面上隐藏 reacteditunsendreplysendWithEffect 和群组操作。
  • 你可以在另一台非 Apple Silicon Mac(或一台专用 bot Mac)上关闭 SIP 来承担 iMessage 工作负载,同时在你的主设备上保持 SIP 启用。见下方 专用 bot macOS 用户(独立 iMessage 身份)

访问控制和路由

channels.imessage.dmPolicy 控制私信:
  • pairing(默认)
  • allowlist
  • open(要求 allowFrom 包含 "*")
  • disabled
允许列表字段:channels.imessage.allowFromAllowlist 条目必须标识发送者: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 可以使用:
  • 规范化的 DM handle,例如 +15555550123[email protected]
  • 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 Agents

部署模式

使用专用 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 授权(Automation + Full Disk Access)。
常见拓扑:
  • gateway 运行在 Linux/VM 上
  • iMessage + imsg 运行在你 tailnet 中的一台 Mac 上
  • cliPath 包装脚本使用 SSH 运行 imsg
  • remoteHost 启用通过 SCP 拉取附件
示例:
{
  channels: {
    imessage: {
      enabled: true,
      cliPath: "~/.openclaw/scripts/imsg-ssh",
      remoteHost: "[email protected]",
      includeAttachments: true,
      dbPath: "/Users/bot/Library/Messages/chat.db",
    },
  },
}
#!/usr/bin/env bash
exec ssh -T [email protected] imsg "$@"
使用 SSH 密钥,以便 SSH 和 SCP 都是非交互式的。 先确保主机密钥是受信任的(例如 ssh [email protected]),以便填充 known_hosts
iMessage 支持在 channels.imessage.accounts 下为每个账号进行配置。每个账号都可以覆盖诸如 cliPathdbPathallowFromgroupPolicymediaMaxMb、历史设置以及附件根目录允许列表等字段。
channels.imessage.dmHistoryLimit 设为一个值,可使用该会话最近解码过的 imsg 历史为新的直接消息会话播种。使用 channels.imessage.dms["<sender>"].historyLimit 可按发送者覆盖,包括设置为 0 以禁用该发送者的历史。iMessage DM 历史会按需从 imsg 获取。保持未设置 dmHistoryLimit 会禁用全局 DM 历史播种,但为某个发送者设置正值的 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(优先按段落拆分)
推荐的显式目标:
  • chat_id:123(推荐用于稳定路由)
  • chat_guid:...
  • chat_identifier:...
也支持 handle 目标:
imsg chats --limit 20

私有 API 动作

imsg launch 正在运行,并且 openclaw channels status --probe 报告 privateApi.available: true 时,消息工具除了正常文本发送之外,还可以使用 iMessage 原生动作。
{
  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(messageIdemojiremove)。支持的 tapback 映射到 love、like、dislike、laugh、emphasize 和 question。
  • reply:对现有消息发送线程式回复(messageIdtextmessage,以及 chatGuidchatIdchatIdentifierto)。
  • sendWithEffect:发送带有 iMessage 效果的文本(textmessageeffecteffectId)。
  • edit:在支持的 macOS/私有 API 版本上编辑已发送消息(messageIdtextnewText)。
  • unsend:在支持的 macOS/私有 API 版本上撤回已发送消息(messageId)。
  • upload-file:发送媒体/文件(buffer 为 base64,或已加载的 media/path/filePathfilename,可选 asVoice)。旧别名:sendAttachment
  • renameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup:当当前目标是群聊时,管理群聊。
入站 iMessage 上下文在可用时会同时包含简短的 MessageSid 值和完整的消息 GUID。简短 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 时,网关会原生投递批准请求并接受 tapback 来解决它:
  • 👍(Like tapback)→ allow-once
  • 👎(Dislike tapback)→ deny
  • allow-always 仍然是手动回退方式:作为普通回复发送 /approve <id> allow-always
反应处理要求作出反应的用户 handle 明确属于审批人。审批人列表从 channels.imessage.allowFrom(或 channels.imessage.accounts.<id>.allowFrom)读取;请添加用户的 E.164 格式电话号码或其 Apple ID 电子邮件。通配符条目 "*" 会被接受,但会允许任何发送者进行批准。该反应快捷方式会刻意绕过 reactionNotificationsdmPolicygroupAllowFrom,因为显式审批人允许列表才是批准解析真正需要的唯一门槛。此版本的行为变化:channels.imessage.allowFrom 非空时,/approve <id> <decision> 文本命令现在会依据该审批人列表进行授权(而不是更宽泛的 DM 允许列表)。虽然在 DM 允许列表中获准但不在 allowFrom 中的发送者将收到明确拒绝。请将所有应该能够通过 /approve(以及通过反应)进行批准的操作员添加到 allowFrom 中,以保留先前行为。当 allowFrom 为空时,旧的“同聊天回退”仍然生效,且 /approve 继续授权任何 DM 允许列表所允许的用户。操作员说明:
  • 该反应绑定会同时存储在内存中(TTL 与批准过期时间匹配)以及网关的持久键值存储中,因此在网关重启后不久到达的 tapback 仍可解析为该批准。
  • 来自其他设备的 is_from_me=true tapback(操作者在已配对 Apple 设备上的自身反应)会被刻意忽略,因此机器人不能自我批准。
  • 旧式文本风格 tapback(非常老旧 Apple 客户端发出的纯文本 Liked "…")无法解析批准,因为它们不携带消息 GUID;反应解析需要当前 macOS / iOS 客户端发出的结构化 tapback 元数据。

配置写入

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

合并拆分发送的 DM(命令 + URL 在同一条输入中)

当用户把命令和 URL 一起输入时——例如 Dump https://example.com/article——Apple 的 Messages 应用会把发送拆分成两条独立的 chat.db 记录
  1. 一条文本消息("Dump")。
  2. 一条 URL 预览气泡("https://..."),并附带 OG 预览图片作为附件。
在大多数环境中,这两条记录会在约 0.8-2.0 秒内先后到达 OpenClaw。若不进行合并,代理会在第 1 轮只收到命令,随后回复(通常是“把 URL 发给我”),而直到第 2 轮才看到 URL——此时命令上下文已经丢失。这是 Apple 的发送流程导致的,不是 OpenClaw 或 imsg 引入的行为。 channels.imessage.coalesceSameSenderDms 会将 DM 纳入对同一发送者连续行的缓冲。当 imsg 在某条源记录上暴露结构化的 URL 预览标记 balloon_bundle_id: "com.apple.messages.URLBalloonProvider" 时,OpenClaw 只合并那次真实的拆分发送,并保持其他缓冲记录作为独立轮次。在较旧、完全不输出 balloon 元数据的 imsg 版本上,OpenClaw 无法区分拆分发送和独立发送,因此会回退为合并整个缓冲桶。这样可以保留元数据引入前的行为,而不是把 Dump <url> 的拆分发送退化成两轮。群聊仍按每条消息分发,以保留多用户轮次结构。
在以下情况下启用:
  • 你提供的技能期望在同一条消息里同时包含 command + payload(dump、paste、save、queue 等)。
  • 你的用户会把 URL 和命令一起粘贴。
  • 你可以接受额外的 DM 轮次延迟(见下文)。
在以下情况下保持关闭:
  • 你需要单词 DM 触发器的最低命令延迟。
  • 所有流程都是不带后续负载的单次命令。

场景以及代理看到的内容

“启用标志”列显示的是在会输出 balloon_bundle_idimsg 构建版本上的行为。在更旧、完全不输出 balloon 元数据的 imsg 构建上,下方标记为“两轮”/“N 轮”的行会回退为旧式合并(1 轮):OpenClaw 无法从结构上区分拆分发送和独立发送,因此会保留元数据引入前的合并行为。只有当构建版本开始输出 balloon 元数据后,精确分离才会启用。
用户输入内容chat.db 产出关闭标志(默认)启用标志 + 窗口(imsg 输出 balloon 元数据)
Dump https://example.com(一次发送)约 1 秒内产生 2 行两轮代理交互:先单独收到 “Dump”,再收到 URL一轮:合并后的文本 Dump https://example.com
Save this 📎image.jpg caption(附件 + 文本)2 行,且没有 URL balloon 元数据两轮两轮(在无元数据构建上采用旧式合并)
/status(独立命令)1 行立即分发最多等待一个窗口,然后分发
单独粘贴的 URL1 行立即分发最多等待一个窗口,然后分发
文本 + URL 被刻意拆成两条独立消息发送,且相隔几分钟窗口外的 2 行两轮两轮(窗口在它们之间过期)
在窗口内快速突发发送超过 10 条小 DM2 行,没有 URL balloon 元数据N 轮N 轮(在无元数据构建上采用旧式合并)
群聊里有两个人同时输入来自 M 个发送者的 N 行M+ 轮(每个发送者桶一轮)M+ 轮——群聊不会被合并

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

iMessage 会恢复网关停机期间遗漏的消息,同时抑制 Apple 在 Push 恢复后可能一次性刷出的陈旧“积压爆发”。默认行为始终开启,建立在入站去重之上。
  • 重放去重。 每条已分发的入站消息都会通过其 Apple GUID 记录到持久化插件状态(imessage.inbound-dedupe)中,在接收时认领,并在处理完成后提交(若发生临时失败则释放,以便重试)。任何已经处理过的内容都会被丢弃,而不会重复分发。这使得恢复可以激进地重放,而无需逐条记录状态。
  • 停机恢复。 启动时,监控会记住最后一次分发的 chat.db 行号(每个账户持久化的游标),并将其作为 since_rowid 传给 imsg watch.subscribe,这样 imsg 就会重放网关停机期间到达的那些行,然后继续追踪实时流。重放范围限制在最近的若干行以及约 2 小时内的消息,去重机制会丢弃任何已经处理过的内容。
  • 陈旧积压年龄防线。 启动边界之上的行是真正实时的;其中发送时间比到达时间早超过约 15 分钟的,则是 Push 刷出的积压消息,会被抑制。重放的行(处于边界之上或之下)则使用更宽的恢复窗口,因此最近遗漏的消息会被投递,而更早的历史消息不会。
恢复机制同时适用于本地和远程 cliPath,因为 since_rowid 重放通过同一个 imsg RPC 连接运行。区别在于窗口:当网关能够读取 chat.db(本地)时,它会锚定启动时的行号边界,限制重放跨度,并投递最多几小时前遗漏的消息;通过远程 SSH cliPath 时则无法读取数据库,因此重放不设上限,所有行都使用实时年龄防线——它仍会恢复最近遗漏的消息,也仍会抑制旧积压,只是使用更窄的实时窗口。要获得更宽的恢复窗口,请在 Messages 所在的 Mac 上运行网关。

运维可见信号

被抑制的积压会按默认级别记录日志,不会静默丢弃(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 路径。
默认的 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
  • 网关主机上的 SSH/SCP 密钥认证
  • 网关主机的 ~/.ssh/known_hosts 中是否存在主机密钥
  • 运行 Messages 的 Mac 上远程路径是否可读
在相同用户/会话上下文中的交互式 GUI 终端里重新运行并批准提示:
imsg chats --limit 1
imsg send <handle> "test"
确认运行 OpenClaw/imsg 的进程上下文已授予完全磁盘访问和自动化权限。

配置参考指针

相关内容