メインコンテンツへスキップ
OpenClaw iMessage デプロイでは、サインイン済みの macOS Messages ホスト上で imsg を使用します。Gateway が Linux または Windows で動作している場合は、Mac 上で imsg を実行する SSH ラッパーを channels.imessage.cliPath に指定します。インバウンド復旧は自動です。 ブリッジまたは Gateway の再起動後、iMessage は停止中に取りこぼしたメッセージを再生し、Push 復旧後に Apple がフラッシュする可能性がある古い「backlog bomb」を抑制し、重複排除によって同じものが二度ディスパッチされないようにします。有効化する設定はありません。ブリッジまたは Gateway 再起動後のインバウンド復旧を参照してください。
BlueBubbles サポートは削除されました。channels.bluebubbles 設定を channels.imessage に移行してください。OpenClaw は imsg 経由の iMessage のみをサポートします。短い告知は BlueBubbles の削除と imsg iMessage パスから、完全な移行表は BlueBubbles からの移行から開始してください。
ステータス: ネイティブ外部 CLI 統合。Gateway は imsg rpc を起動し、stdio 経由で JSON-RPC をやり取りします。別個のデーモンやポートはありません。高度なアクションには imsg launch と、private API プローブの成功が必要です。

Private API アクション

返信、tapback、エフェクト、投票、添付ファイル、グループ管理。

ペアリング

iMessage DM はデフォルトでペアリングモードになります。

SSH 経由のリモート 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

最初の DM ペアリングを承認する(デフォルトの dmPolicy)

openclaw pairing list imessage
openclaw pairing approve imessage <CODE>
ペアリングリクエストは 1 時間後に期限切れになります。

要件と権限(macOS)

  • imsg を実行する Mac で Messages にサインインしている必要があります。
  • OpenClaw/imsg を実行するプロセスコンテキストには Full Disk Access が必要です(Messages DB アクセス)。
  • Messages.app 経由でメッセージを送信するには Automation 権限が必要です。
  • 高度なアクション(react / edit / unsend / スレッド返信 / エフェクト / 投票 / グループ操作)には System Integrity Protection を無効にする必要があります。imsg private 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 エントリが imsg やローカルシェルプロセスではなく /usr/libexec/sshd-keygen-wrapper に記録されている場合、macOS はその SSH サーバー側クライアントに対して使用可能な Messages トグルを表示しないことがあります。
kTCCServiceAppleEvents | /usr/libexec/sshd-keygen-wrapper | auth_value=0 | com.apple.MobileSMS
その状態では、tccutil reset AppleEvents を繰り返したり、同じ SSH ラッパー経由で imsg send を再実行したりしても失敗し続ける可能性があります。Messages Automation を必要とするプロセスコンテキストが、UI で許可できるアプリではなく SSH ラッパーだからです。代わりに、サポートされている imsg プロセスコンテキストのいずれかを使用します。
  • Gateway、または少なくとも imsg ブリッジを、ログイン済み Messages ユーザーのローカルセッションで実行します。
  • 同じセッションから Full Disk Access と Automation を付与した後、そのユーザーの LaunchAgent で Gateway を起動します。
  • 2 ユーザー SSH トポロジを維持する場合は、チャネルを有効にする前に、実際のアウトバウンド imsg send が正確なラッパー経由で成功することを確認します。Automation を付与できない場合は、送信を SSH ラッパーに依存するのではなく、単一ユーザーの imsg セットアップに再設定してください。

imsg private API の有効化

imsg は 2 つの運用モードで提供されます。
  • 基本モード(デフォルト、SIP 変更不要): send によるアウトバウンドのテキストとメディア、インバウンドの監視/履歴、チャット一覧。これは、新しい brew install steipete/tap/imsg と上記の標準 macOS 権限だけで利用できるものです。
  • Private API モード: imsg は helper dylib を Messages.app に注入し、内部 IMCore 関数を呼び出します。これにより、reacteditunsendreply(スレッド)、sendWithEffectpollpoll-vote(ネイティブ Messages 投票)、renameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup に加え、入力インジケーターと既読通知が利用可能になります。
このページの高度なアクションサーフェスには Private API モードが必要です。imsg README は、この要件を明示しています。
readtypinglaunch、ブリッジ支援のリッチ送信、メッセージ変更、チャット管理などの高度な機能はオプトインです。SIP を無効にし、helper dylib を Messages.app に注入する必要があります。SIP が有効な場合、imsg launch は注入を拒否します。
helper 注入の手法では、imsg 独自の dylib を使用して Messages private API に到達します。OpenClaw iMessage パスには、サードパーティサーバーや BlueBubbles ランタイムはありません。
SIP を無効にすることは実際のセキュリティ上のトレードオフです。 SIP は変更されたシステムコードの実行に対する macOS の中核的な保護の 1 つです。システム全体で無効にすると、追加の攻撃面と副作用が発生します。特に、Apple Silicon Mac で SIP を無効にすると、Mac に iOS アプリをインストールして実行する機能も無効になりますこれはデフォルトではなく、意図的な運用上の選択として扱ってください。脅威モデルが SIP の無効化を許容できない場合、バンドルされた iMessage は基本モードに制限されます。つまり、テキストとメディアの送受信のみで、リアクション / edit / unsend / エフェクト / グループ操作はありません。

セットアップ

  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 署名済みの Messages.app に非 Apple の helper dylib を注入するには、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 statusadvanced_features: true を報告します。
    • plist なし(SIP がオフでも): imsg launchFailed to launch: Timeout waiting for Messages.app to initialize で失敗します。AMFI が読み込み時に adhoc helper を拒否するため、ブリッジは準備完了にならず、起動がタイムアウトします。このタイムアウトは Tahoe で多くの人が遭遇する症状です。修正は上記の plist であり、より抜本的な対応ではありません。
    macOS アップグレード後に imsg launch の注入や特定の selectors が false を返し始めた場合、このゲートが通常の原因です。SIP と library-validation の状態を確認してから、SIP 手順自体が失敗したと判断してください。これらの設定が正しくてもブリッジがまだ注入できない場合は、追加のシステム全体のセキュリティ制御を弱めるのではなく、imsg status --jsonimsg launch の出力を収集して imsg プロジェクトに報告してください。
  3. ヘルパーを注入します。 SIP を無効にし、Messages.app にサインインした状態で:
    imsg launch
    
    SIP がまだ有効な場合、imsg launch は注入を拒否するため、これは手順 2 が反映されたことの確認にもなります。
  4. OpenClaw からブリッジを検証します:
    openclaw channels status --probe
    
    iMessage の項目は works を報告するはずです。また、imsg status --json | jq '{rpc_methods, selectors}' は、使用している macOS ビルドが公開している機能を表示するはずです。投票作成には selectors.pollPayloadMessage が必要です。投票には selectors.pollVoteMessagepoll.vote RPC メソッドの両方が必要です。OpenClaw Plugin は、キャッシュされたプローブでサポートされているアクションだけを公開します。一方、空のキャッシュは楽観的に扱われ、最初のディスパッチ時にプローブします。
openclaw channels status --probe がチャネルを works と報告しているのに、特定のアクションがディスパッチ時に「iMessage <action> requires the imsg private API bridge」を投げる場合は、imsg launch をもう一度実行してください。ヘルパーは外れることがあり (Messages.app の再起動、OS 更新など)、キャッシュされた available: true ステータスは次のプローブが更新されるまでアクションを公開し続けます。

SIP を有効のままにする場合

SIP の無効化が脅威モデル上許容できない場合:
  • imsg は基本モードにフォールバックします — テキスト + メディア + 受信のみ。
  • OpenClaw Plugin は引き続きテキスト/メディア送信と受信監視を公開します。アクションサーフェスからは、メソッドごとの機能ゲートに従って reacteditunsendreplysendWithEffect、グループ操作を非表示にします。
  • iMessage ワークロード用に、SIP をオフにした別の Apple-Silicon 以外の Mac (または専用ボット Mac) を実行し、主要デバイスでは SIP を有効のままにできます。下記の 専用ボット macOS ユーザー (別の iMessage ID) を参照してください。

アクセス制御とルーティング

channels.imessage.dmPolicy はダイレクトメッセージを制御します:
  • pairing (デフォルト)
  • allowlist (少なくとも 1 つの allowFrom エントリが必要)
  • open (allowFrom"*" を含める必要あり)
  • disabled
Allowlist フィールド: channels.imessage.allowFromAllowlist エントリは送信者を識別する必要があります: ハンドル、または静的送信者アクセスグループ (accessGroup:<name>)。chat_id:*chat_guid:*chat_identifier:* などのチャットターゲットには channels.imessage.groupAllowFrom を使用します。数値の chat_id レジストリキーには channels.imessage.groups を使用します。

ACP 会話バインディング

iMessage チャットは ACP セッションにバインドできます。 高速なオペレーターフロー:
  • DM または許可されたグループチャット内で /acp spawn codex --bind here を実行します。
  • 同じ iMessage 会話内の今後のメッセージは、生成された ACP セッションにルーティングされます。
  • /new/reset は、同じバインド済み ACP セッションをその場でリセットします。
  • /acp close は ACP セッションを閉じ、バインディングを削除します。
構成済みの永続バインディングは、type: "acp"match.channel: "imessage" を持つトップレベルの bindings[] エントリを使用します。 match.peer.id には次を使用できます:
  • +15555550123user@example.com などの正規化済み DM ハンドル
  • 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 エージェント を参照してください。

デプロイパターン

ボットトラフィックを個人の Messages プロファイルから分離するために、専用の Apple ID と macOS ユーザーを使用します。一般的なフロー:
  1. 専用の macOS ユーザーを作成/サインインします。
  2. そのユーザーで、ボット用 Apple ID を使って Messages にサインインします。
  3. そのユーザーに imsg をインストールします。
  4. OpenClaw がそのユーザーコンテキストで imsg を実行できるように SSH ラッパーを作成します。
  5. channels.imessage.accounts.<id>.cliPath.dbPath をそのユーザープロファイルに向けます。
初回実行時には、そのボットユーザーセッションで 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: "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 と SCP の両方が非対話になるように SSH キーを使用します。 最初にホストキーを信頼済みにし (例: ssh bot@mac-mini.tailnet-1234.ts.net)、known_hosts が設定されていることを確認します。
iMessage は channels.imessage.accounts の下でアカウントごとの構成をサポートします。各アカウントは、cliPathdbPathallowFromgroupPolicymediaMaxMb、履歴設定、添付ファイルルート allowlist などのフィールドを上書きできます。
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 (段落優先の分割)
  • アウトバウンドの markdown 太字/斜体/下線/取り消し線はネイティブのスタイル付きテキストに変換されます (macOS 15+ の受信者はスタイルを表示し、古い受信者にはマーカーなしのプレーンテキストが表示されます)。markdown テーブルはチャンネルの markdown テーブルモードに従って変換されます
  • channels.imessage.sendTransport (auto デフォルト、bridgeapplescript) は 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 --probeprivateApi.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 は love、like、dislike、laugh、emphasize、question にマップされます。絵文字なしで削除すると、設定されていた tapback がクリアされます。
  • reply: 既存メッセージへのスレッド返信を送信します (messageIdtext または message、および chatGuidchatIdchatIdentifier、または to)。添付ファイル付き返信には、さらに send-rich--file をサポートする imsg ビルドが必要です。
  • sendWithEffect: iMessage エフェクト付きでテキストを送信します (text または messageeffect または effectId)。短い名前: slam、loud、gentle、invisibleink、confetti、lasers、fireworks、balloon、heart、echo、happybirthday、shootingstar、sparkles、spotlight。
  • edit: サポートされる macOS/プライベート API バージョンで送信済みメッセージを編集します (messageIdtext または newText)。Gateway 自身が送信したメッセージのみ編集できます。
  • unsend: サポートされる macOS/プライベート API バージョンで送信済みメッセージを取り消します (messageId)。Gateway 自身が送信したメッセージのみ送信取り消しできます。
  • upload-file: メディア/ファイルを送信します (buffer は base64、またはハイドレート済みの media/path/filePathfilename、任意の asVoice)。レガシーエイリアス: sendAttachment
  • renameGroupsetGroupIconaddParticipantremoveParticipantleaveGroup: 現在のターゲットがグループ会話の場合にグループチャットを管理します。これらはホストの Messages アイデンティティを変更するため、オーナー送信者または operator.admin Gateway クライアントが必要です。
  • poll: ネイティブの Apple Messages 投票を作成します (pollQuestion、2 から 12 回繰り返す pollOption、および chatGuidchatIdchatIdentifier、または to)。iOS/iPadOS/macOS 26+ の受信者はネイティブに表示して投票できます。古い OS バージョンでは「Sent a poll」というテキストフォールバックを受け取ります。selectors.pollPayloadMessage が必要です。
  • poll-vote: 既存の投票に投票します (pollId または messageId、および pollOptionIndexpollOptionIdpollOptionText の正確に 1 つ)。selectors.pollVoteMessagepoll.vote RPC メソッドが必要です。
受け入れられたインバウンド投票は、質問、番号付き選択肢ラベル、投票数、poll-vote に必要な投票メッセージ ID とともにエージェント向けにレンダリングされます。
インバウンド iMessage コンテキストには、利用可能な場合、短い MessageSid 値と完全なメッセージ GUID (MessageSidFull) の両方が含まれます。短い ID は最近の SQLite バックの返信キャッシュにスコープされ、使用前に現在のチャットと照合されます。短い ID の有効期限が切れているか別のチャットに属する場合は、完全な MessageSidFull で再試行してください。
OpenClaw は、キャッシュされたプローブステータスが bridge を利用不可と示す場合にのみ、プライベート API アクションを非表示にします。ステータスが不明な場合、アクションは表示されたままで、ディスパッチ時に遅延プローブを行うため、imsg launch 後に別途手動でステータスを更新しなくても最初のアクションが成功できます。
プライベート API bridge が起動している場合、受け入れられたインバウンドチャットは既読としてマークされ、ダイレクトチャットではターンが受け入れられるとすぐに、エージェントがコンテキストを準備して生成している間に入力中バブルが表示されます。既読マークを無効にするには:
{
  channels: {
    imessage: {
      sendReadReceipts: false,
    },
  },
}
メソッド別の機能リストより前の古い imsg ビルドでは、入力中/既読が黙って無効化されます。OpenClaw は再起動ごとに 1 回だけ警告をログに出すため、確認が欠落している原因を特定できます。
OpenClaw は iMessage tapback を購読し、受け入れられたリアクションを通常のメッセージテキストではなくシステムイベントとしてルーティングします。そのため、ユーザーの tapback が通常の返信ループをトリガーすることはありません。通知モードは channels.imessage.reactionNotifications で制御されます:
  • "own" (デフォルト): ユーザーがボット作成メッセージにリアクションした場合のみ通知します。
  • "all": 承認済み送信者からのすべてのインバウンド tapback を通知します。
  • "off": インバウンド tapback を無視します。
アカウントごとのオーバーライドは channels.imessage.accounts.<id>.reactionNotifications を使用します。
approvals.exec.enabled または approvals.plugin.enabled が true でリクエストが iMessage にルーティングされる場合、Gateway は承認プロンプトをネイティブに配信し、tapback を受け入れて解決します:
  • 👍 (Like tapback) → allow-once
  • 👎 (Dislike 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> はその承認者リストに対して認可されます (より広い DM 許可リストではありません)。DM 許可リストでは許可されているが allowFrom に含まれない送信者は、明示的な拒否を受け取ります。allowFrom が空の場合、同一チャットフォールバックが有効なままで、/approve は DM 許可リストが許可する任意のユーザーを認可します。承認すべきすべてのオペレーターを、/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,
    },
  },
}

分割送信 DM の結合 (1 つの構成内のコマンド + URL)

ユーザーがコマンドと URL を一緒に入力すると (例: Dump https://example.com/article)、Apple の Messages アプリは送信を2 つの別々の chat.dbに分割します:
  1. テキストメッセージ ("Dump")。
  2. OG プレビュー画像を添付ファイルとして持つ URL プレビューバルーン ("https://...")。
ほとんどのセットアップでは、2 つの行は OpenClaw に約 0.8-2.0 秒差で到着します。結合しない場合、エージェントはターン 1 でコマンドだけを受け取り (多くの場合「URL を送ってください」と返信します)、その後ターン 2 で URL が届きます。これは Apple の送信パイプラインであり、OpenClaw や imsg が導入しているものではありません。 channels.imessage.coalesceSameSenderDms は、DM で同じ送信者から連続して届く行のバッファリングを有効にします。imsg がソース行の 1 つに構造的な URL プレビューマーカー balloon_bundle_id: "com.apple.messages.URLBalloonProvider" を公開する場合、OpenClaw はその実際の分割送信だけをマージし、その他のバッファ済み行は別々のターンとして保持します。バルーンメタデータをまったく出力しない古い imsg ビルドでは、OpenClaw は分割送信と別々の送信を区別できないため、バケットのマージにフォールバックします。これにより、Dump <url> の分割送信が 2 つのターンに回帰するのではなく、メタデータ以前の動作が維持されます。グループチャットでは、複数ユーザーのターン構造を維持するため、引き続きメッセージごとにディスパッチされます。
次の場合に有効化します:
  • 1 つのメッセージ内の command + payload を想定するスキル (dump、paste、save、queue など) を提供している。
  • ユーザーがコマンドと一緒に URL を貼り付ける。
  • 追加される DM ターン遅延を許容できる (以下を参照)。
次の場合は無効のままにします:
  • 単語 1 つの DM トリガーで最小のコマンド遅延が必要。
  • すべてのフローがペイロードのフォローアップなしのワンショットコマンドである。

シナリオとエージェントに見える内容

「フラグオン」列は、balloon_bundle_id を出力する imsg ビルドでの動作を示します。バルーンメタデータをまったく出力しない古い imsg ビルドでは、下記で「2 ターン」/「N ターン」と示されている行は、代わりにレガシーマージ(1 ターン)にフォールバックします。OpenClaw は分割送信と個別送信を構造的に判別できないため、メタデータ導入前のマージを保持します。ビルドがバルーンメタデータを出力するようになると、正確な分離が有効になります。
ユーザーの作成内容chat.db の生成内容フラグオフ(デフォルト)フラグオン + ウィンドウ(imsg がバルーンメタデータを出力)
Dump https://example.com(1 回の送信)約 1 秒間隔で 2 行2 つのエージェントターン: 「Dump」のみ、その後 URL1 ターン: マージされたテキスト Dump https://example.com
Save this 📎image.jpg caption(添付ファイル + テキスト)URL バルーンメタデータなしで 2 行2 ターンメタデータが観測された後は 2 ターン。古い/ラッチ前のメタデータなしセッションでは 1 つのマージターン
/status(単独コマンド)1 行即時ディスパッチ最大でウィンドウまで待機し、その後ディスパッチ
URL のみを貼り付け1 行即時ディスパッチ最大でウィンドウまで待機し、その後ディスパッチ
テキスト + URL を数分空けて意図的に 2 つの別メッセージとして送信ウィンドウ外で 2 行2 ターン2 ターン(その間にウィンドウが期限切れ)
高速大量送信(ウィンドウ内に 10 件超の短い DM)URL バルーンメタデータなしで N 行N ターンメタデータが観測された後は N ターン。古い/ラッチ前のメタデータなしセッションでは上限付きの 1 つのマージターン
グループチャットで 2 人が入力M 人の送信者から N 行M+ ターン(送信者バケットごとに 1 つ)M+ ターン — グループチャットは結合されません

ブリッジまたは Gateway 再起動後のインバウンド復旧

iMessage は Gateway の停止中に取り逃したメッセージを復旧し、同時に Push 復旧後に Apple が吐き出すことがある古い「バックログ爆弾」を抑制します。デフォルトの動作は常に有効で、インバウンド重複排除の上に構築されています。
  • リプレイ重複排除。 ディスパッチされたすべてのインバウンドメッセージは、その Apple GUID によって永続 Plugin 状態(imessage.inbound-dedupe)に記録され、取り込み時に確保され、処理後にコミットされます(一時的な失敗時はリトライできるよう解放されます)。すでに処理済みのものは、二重にディスパッチされる代わりに破棄されます。これにより、メッセージ単位の帳簿管理なしで復旧リプレイを積極的に行えます。
  • ダウンタイム復旧。 起動時にモニターは最後にディスパッチした chat.db rowid(アカウントごとに永続化されたカーソル)を記憶し、それを since_rowid として imsg watch.subscribe に渡します。これにより、Gateway が停止している間に到着した行を imsg がリプレイし、その後ライブで追尾します。リプレイは直近 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 を更新してください。private API アクションを利用できない場合は、ログイン済み macOS ユーザーセッションで imsg launch を実行し、再度プローブしてください。Gateway が macOS 上で実行されていない場合は、デフォルトのローカル imsg パスではなく、上記の SSH 経由のリモート Mac セットアップを使用してください。
まず、メッセージがローカル 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;"
電話から送信したメッセージで新しい行が作成されない場合は、OpenClaw 設定を変更する前に macOS Messages と Apple Push レイヤーを修復してください。多くの場合、1 回限りのサービス更新で十分です。
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
OpenClaw セッションをデバッグする前に、電話から新しい iMessage を送信し、新しい chat.db 行または imsg watch イベントを確認してください。これを定期的なブリッジ再起動ループとして実行しないでください。作業中に imsg launch と Gateway 再起動を繰り返すと、配信が中断され、進行中のチャンネル実行が取り残される可能性があります。
デフォルトの cliPath: "imsg" は、Messages にサインインしている Mac 上で実行する必要があります。Linux または Windows では、channels.imessage.cliPath を、その Mac に SSH して 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 を実行するプロセスコンテキストに、フルディスクアクセス + オートメーションが付与されていることを確認してください。

設定リファレンスへのポインター

関連