BlueBubbles(macOS REST)
ステータス: HTTP経由でBlueBubbles macOSサーバーと通信するバンドル済みPluginです。従来のimsgチャンネルと比べてAPIがより豊富でセットアップも簡単なため、iMessage連携にはこちらを推奨します。バンドル済みPlugin
現在のOpenClawリリースにはBlueBubblesがバンドルされているため、通常のパッケージ済みビルドでは別途openclaw plugins install を行う必要はありません。
概要
- BlueBubblesヘルパーアプリ(bluebubbles.app)を使ってmacOS上で動作します。
- 推奨/検証済み: macOS Sequoia(15)。macOS Tahoe(26)でも動作しますが、現在Tahoeでは編集機能が壊れており、グループアイコンの更新は成功と表示されても同期されない場合があります。
- OpenClawはREST API(
GET /api/v1/ping,POST /message/text,POST /chat/:id/*)を通じてこれと通信します。 - 受信メッセージはWebhook経由で到着し、送信返信、入力中インジケーター、既読通知、tapbackはREST呼び出しです。
- 添付ファイルとステッカーは受信メディアとして取り込まれ、可能な場合はエージェントにも渡されます。
- ペアリング/許可リストは他のチャンネルと同じように機能します(
/channels/pairingなど)。channels.bluebubbles.allowFrom+ ペアリングコードを使用します。 - リアクションはSlack/Telegramと同様にシステムイベントとして表面化されるため、エージェントは返信前にそれらに「言及」できます。
- 高度な機能: 編集、送信取り消し、スレッド返信、メッセージエフェクト、グループ管理。
クイックスタート
- MacにBlueBubblesサーバーをインストールします(手順はbluebubbles.app/installを参照してください)。
- BlueBubblesの設定でWeb APIを有効にし、パスワードを設定します。
-
openclaw onboardを実行してBlueBubblesを選択するか、手動で設定します: -
BlueBubblesのWebhookをゲートウェイに向けます(例:
https://your-gateway-host:3000/bluebubbles-webhook?password=<password>)。 - ゲートウェイを起動します。Webhookハンドラーが登録され、ペアリングが開始されます。
- 必ずWebhookパスワードを設定してください。
- Webhook認証は常に必須です。OpenClawは、
channels.bluebubbles.passwordに一致するpassword/guidを含まないBlueBubbles Webhookリクエストを拒否します(たとえば?password=<password>またはx-password)。これはloopback/proxyトポロジーに関係ありません。 - パスワード認証は、Webhook本文全体を読み取り/解析する前にチェックされます。
Messages.appを生かしておく(VM / ヘッドレス構成)
一部のmacOS VM / 常時稼働構成では、Messages.appが「アイドル」状態になり(アプリを開くか前面化するまで受信イベントが止まる)、問題になることがあります。簡単な回避策として、AppleScript + LaunchAgentを使って5分ごとにMessagesをつつく方法があります。1) AppleScriptを保存する
これを次の場所に保存します:~/Scripts/poke-messages.scpt
2) LaunchAgentをインストールする
これを次の場所に保存します:~/Library/LaunchAgents/com.user.poke-messages.plist
- これは300秒ごとおよびログイン時に実行されます。
- 初回実行時にmacOSのAutomationプロンプト(
osascript→ Messages)が表示されることがあります。LaunchAgentを実行する同じユーザーセッションで承認してください。
オンボーディング
BlueBubblesは対話型オンボーディングで利用できます:- Server URL(必須): BlueBubblesサーバーのアドレス(例:
http://192.168.1.100:1234) - Password(必須): BlueBubbles Server設定のAPIパスワード
- Webhook path(任意): デフォルトは
/bluebubbles-webhook - DM policy: pairing、allowlist、open、またはdisabled
- Allow list: 電話番号、メールアドレス、またはチャットターゲット
アクセス制御(DM + グループ)
DM:- デフォルト:
channels.bluebubbles.dmPolicy = "pairing"。 - 未知の送信者にはペアリングコードが返され、承認されるまでメッセージは無視されます(コードは1時間で期限切れになります)。
- 承認方法:
openclaw pairing list bluebubblesopenclaw pairing approve bluebubbles <CODE>
- ペアリングがデフォルトのトークン交換です。詳細: ペアリング
channels.bluebubbles.groupPolicy = open | allowlist | disabled(デフォルト:allowlist)。channels.bluebubbles.groupAllowFromは、allowlistが設定されているときに、グループ内で誰がトリガーできるかを制御します。
連絡先名の補完(macOS、任意)
BlueBubblesのグループWebhookには、生の参加者アドレスしか含まれないことがよくあります。代わりにGroupMembers コンテキストにローカルの連絡先名を表示したい場合は、macOS上でローカルContacts補完を有効にできます:
channels.bluebubbles.enrichGroupParticipantsFromContacts = trueで検索を有効にします。デフォルト:false。- 検索は、グループアクセス、コマンド認可、メンション制御によってメッセージの通過が許可された後にのみ実行されます。
- 名前のない電話参加者だけが補完されます。
- ローカル一致が見つからない場合は、生の電話番号がフォールバックとして残ります。
メンション制御(グループ)
BlueBubblesはグループチャットのメンション制御をサポートしており、iMessage/WhatsAppの動作に一致します:- メンション検出には
agents.list[].groupChat.mentionPatterns(またはmessages.groupChat.mentionPatterns)を使用します。 - グループで
requireMentionが有効な場合、エージェントはメンションされたときだけ応答します。 - 認可された送信者からの制御コマンドはメンション制御をバイパスします。
コマンド制御
- 制御コマンド(例:
/config,/model)には認可が必要です。 - コマンド認可の判定には
allowFromとgroupAllowFromを使用します。 - 認可された送信者は、グループ内でメンションしなくても制御コマンドを実行できます。
グループごとのシステムプロンプト
channels.bluebubbles.groups.* の各エントリは、任意の systemPrompt 文字列を受け付けます。この値は、そのグループでメッセージを処理するすべてのターンでエージェントのシステムプロンプトに注入されるため、エージェントのプロンプトを編集しなくても、グループごとのペルソナや振る舞いルールを設定できます:
chatGuid / chatIdentifier / 数値の chatId のいずれかに一致し、"*" ワイルドカードエントリを使うと、完全一致がないすべてのグループのデフォルトを設定できます(requireMention やグループごとのツールポリシーで使われるものと同じパターンです)。完全一致は常にワイルドカードより優先されます。DMではこのフィールドは無視されます。代わりに、エージェントレベルまたはアカウントレベルのプロンプトカスタマイズを使用してください。
実例: スレッド返信とtapbackリアクション(Private API)
BlueBubbles Private APIを有効にすると、受信メッセージには短いメッセージID(例:[[reply_to:5]])が付いて届き、エージェントは action=reply を呼び出して特定のメッセージにスレッド返信したり、action=react を呼び出してtapbackを付けたりできます。グループごとの systemPrompt は、エージェントに正しいツールを選ばせるための確実な方法です:
ACP会話バインディング
BlueBubblesチャットは、転送レイヤーを変えずに永続的なACPワークスペースにできます。 高速なオペレーター手順:- DMまたは許可されたグループチャット内で
/acp spawn codex --bind hereを実行します。 - 同じBlueBubbles会話内の以後のメッセージは、生成されたACPセッションにルーティングされます。
/newと/resetは、同じバインド済みACPセッションをその場でリセットします。/acp closeはACPセッションを閉じ、バインディングを削除します。
bindings[] エントリで type: "acp" および match.channel: "bluebubbles" を通じてサポートされます。
match.peer.id には、サポートされている任意のBlueBubblesターゲット形式を使えます:
+15555550123やuser@example.comのような正規化されたDMハンドルchat_id:<id>chat_guid:<guid>chat_identifier:<identifier>
chat_id:* または chat_identifier:* を推奨します。
例:
入力中表示 + 既読通知
- 入力中インジケーター: 応答生成の前と生成中に自動送信されます。
- 既読通知:
channels.bluebubbles.sendReadReceiptsで制御します(デフォルト:true)。 - 入力中インジケーター: OpenClawは入力開始イベントを送信します。BlueBubblesは送信時またはタイムアウト時に自動で入力中状態を解除します(DELETEによる手動停止は信頼性がありません)。
高度なアクション
BlueBubblesは、設定で有効にすると高度なメッセージアクションをサポートします:- react: tapbackリアクションを追加/削除します(
messageId,emoji,remove)。iMessageネイティブのtapbackセットはlove,like,dislike,laugh,emphasize,questionです。エージェントがこのセット外の絵文字(たとえば👀)を選んだ場合、リアクションツールはloveにフォールバックするため、リクエスト全体を失敗させずにtapbackが表示されます。設定済みのackリアクションは引き続き厳密に検証され、不明な値ではエラーになります。 - edit: 送信済みメッセージを編集します(
messageId,text) - unsend: メッセージを送信取り消しします(
messageId) - reply: 特定のメッセージに返信します(
messageId,text,to) - sendWithEffect: iMessageエフェクト付きで送信します(
text,to,effectId) - renameGroup: グループチャット名を変更します(
chatGuid,displayName) - setGroupIcon: グループチャットのアイコン/写真を設定します(
chatGuid,media)— macOS 26 Tahoeでは不安定です(APIが成功を返してもアイコンが同期されない場合があります)。 - addParticipant: 誰かをグループに追加します(
chatGuid,address) - removeParticipant: 誰かをグループから削除します(
chatGuid,address) - leaveGroup: グループチャットから退出します(
chatGuid) - upload-file: メディア/ファイルを送信します(
to,buffer,filename,asVoice)- ボイスメモ: MP3 または CAF 音声で
asVoice: trueを設定すると、iMessageの音声メッセージとして送信できます。BlueBubblesはボイスメモ送信時にMP3 → CAFへ変換します。
- ボイスメモ: MP3 または CAF 音声で
- レガシーエイリアス:
sendAttachmentも引き続き動作しますが、正式なアクション名はupload-fileです。
メッセージID(短縮版と完全版)
OpenClawは、トークン節約のために_短縮_メッセージID(例:1, 2)を表示することがあります。
MessageSid/ReplyToIdには短縮IDが入る場合があります。MessageSidFull/ReplyToIdFullにはプロバイダーの完全IDが入ります。- 短縮IDはインメモリです。再起動やキャッシュ削除で失効することがあります。
- アクションは短縮版または完全版の
messageIdを受け付けますが、短縮IDが利用できなくなっている場合はエラーになります。
- テンプレート:
{{MessageSidFull}},{{ReplyToIdFull}} - コンテキスト: 受信ペイロード内の
MessageSidFull/ReplyToIdFull
分割送信されるDMの統合(1回の入力内のコマンド + URL)
ユーザーがiMessageでコマンドとURLを一緒に入力した場合 — たとえばDump https://example.com/article — Appleは送信を2つの別々のWebhook配信に分割します:
- テキストメッセージ(
"Dump")。 - OGプレビュー画像を添付したURLプレビューバルーン(
"https://...")。
channels.bluebubbles.coalesceSameSenderDms を使うと、DMで連続して届く同一送信者のWebhookを1つのエージェントターンに統合できます。グループチャットは引き続きメッセージ単位でキー化されるため、複数ユーザーのターン構造は保たれます。
有効にするタイミング
次の場合に有効にしてください:- 1つのメッセージ内で
command + payloadを想定するSkillsを提供している(dump、paste、save、queueなど)。 - ユーザーがコマンドと一緒にURL、画像、長文コンテンツを貼り付ける。
- DMターンの待ち時間増加を許容できる(下記参照)。
- 単語1つのDMトリガーに対して最小限のコマンド遅延が必要。
- すべてのフローが、後続ペイロードなしの単発コマンドである。
有効化
messages.inbound.byChannel.bluebubbles がない場合、デバウンスウィンドウは2500 msに広がります(統合なしのデフォルトは500 ms)。この広いウィンドウが必要です。Appleの0.8〜2.0秒の分割送信間隔は、より狭いデフォルトには収まりません。
ウィンドウを自分で調整するには:
トレードオフ
- DM制御コマンドに遅延が追加されます。 このフラグをオンにすると、DMの制御コマンドメッセージ(
Dump,Saveなど)は、ペイロードWebhookが来る可能性を考慮して、デバウンスウィンドウまで待ってからディスパッチされます。グループチャットのコマンドは即時ディスパッチのままです。 - 統合後の出力には上限があります — 統合テキストは明示的な
…[truncated]マーカー付きで4000文字まで、添付ファイルは20件まで、ソースエントリは10件までです(それを超える場合も最初と最新は保持されます)。各ソースmessageIdは引き続き受信重複排除に渡されるため、後から任意の個別イベントがMessagePollerで再生されても重複として認識されます。 - チャンネル単位のオプトインです。 他のチャンネル(Telegram、WhatsApp、Slack、…)には影響しません。
シナリオとエージェントに見える内容
| ユーザーの入力 | Appleの配信 | フラグオフ(デフォルト) | フラグオン + 2500 msウィンドウ |
|---|---|---|---|
Dump https://example.com(1回送信) | 約1秒差の2つのWebhook | 2つのエージェントターン: 「Dump」のみ、次にURL | 1ターン: 統合テキスト Dump https://example.com |
Save this 📎image.jpg caption(添付 + テキスト) | 2つのWebhook | 2ターン | 1ターン: テキスト + 画像 |
/status(単独コマンド) | 1つのWebhook | 即時ディスパッチ | ウィンドウまで待ってからディスパッチ |
| URL単体の貼り付け | 1つのWebhook | 即時ディスパッチ | 即時ディスパッチ(バケットに1エントリしかないため) |
| テキスト + URLを、数分離して意図的に別メッセージで送信 | ウィンドウ外の2Webhook | 2ターン | 2ターン(間でウィンドウが期限切れになるため) |
| 連続フラッド(ウィンドウ内に10件超の小さなDM) | N個のWebhook | Nターン | 1ターン、上限付き出力(最初 + 最新、テキスト/添付上限を適用) |
分割送信統合のトラブルシューティング
フラグがオンなのに分割送信がまだ2ターンで届く場合は、各レイヤーを確認してください:-
設定が実際に読み込まれているか。
次に
openclaw gateway restartを実行します — このフラグはdebouncer-registry作成時に読み込まれます。 -
デバウンスウィンドウが環境に対して十分広いか。
~/Library/Logs/bluebubbles-server/main.logにあるBlueBubblesサーバーログを確認します:"Dump"のようなテキスト送信と、その後に続く"https://..."; Attachments:の送信の間隔を測定してください。その間隔を十分にカバーできるようにmessages.inbound.byChannel.bluebubblesを引き上げます。 -
セッションJSONLのタイムスタンプ ≠ Webhook到着時刻。 セッションイベントのタイムスタンプ(
~/.openclaw/agents/<id>/sessions/*.jsonl)は、Webhook到着時刻ではなく、ゲートウェイがメッセージをエージェントに渡した時刻を表します。2つ目のメッセージが[Queued messages while agent was busy]と表示されるなら、2つ目のWebhookが来た時点で1ターン目がまだ実行中だったことを意味します — 統合バケットはすでにフラッシュ済みです。調整はセッションログではなくBBサーバーログを基準に行ってください。 -
メモリ圧迫で返信ディスパッチが遅くなっている。 小さいマシン(8 GB)では、エージェントターンが長引いて統合バケットが返信完了前にフラッシュし、その結果URLがキュー済みの2ターン目として入ることがあります。
memory_pressureとps -o rss -p $(pgrep openclaw-gateway)を確認してください。ゲートウェイが約500 MB RSSを超え、compressorが動作している場合は、他の重いプロセスを閉じるか、より大きいホストに移してください。 -
返信引用送信は別経路です。 ユーザーが既存のURLバルーンへの返信として
Dumpをタップした場合(iMessageではDumpバブルに「1 Reply」バッジが表示されます)、URLは2つ目のWebhookではなくreplyToBodyにあります。統合は適用されません — これはdebouncerの問題ではなく、Skill/プロンプトの問題です。
ブロックストリーミング
応答を1つのメッセージとして送るか、ブロック単位でストリーミングするかを制御します:メディア + 制限
- 受信添付ファイルはダウンロードされ、メディアキャッシュに保存されます。
- 受信・送信メディアの上限は
channels.bluebubbles.mediaMaxMbで制御します(デフォルト: 8 MB)。 - 送信テキストは
channels.bluebubbles.textChunkLimitに従って分割されます(デフォルト: 4000文字)。
設定リファレンス
完全な設定: 設定 プロバイダーオプション:channels.bluebubbles.enabled: チャンネルを有効/無効にします。channels.bluebubbles.serverUrl: BlueBubbles REST APIのベースURL。channels.bluebubbles.password: APIパスワード。channels.bluebubbles.webhookPath: Webhookエンドポイントパス(デフォルト:/bluebubbles-webhook)。channels.bluebubbles.dmPolicy:pairing | allowlist | open | disabled(デフォルト:pairing)。channels.bluebubbles.allowFrom: DM許可リスト(ハンドル、メール、E.164番号、chat_id:*,chat_guid:*)。channels.bluebubbles.groupPolicy:open | allowlist | disabled(デフォルト:allowlist)。channels.bluebubbles.groupAllowFrom: グループ送信者の許可リスト。channels.bluebubbles.enrichGroupParticipantsFromContacts: macOS上で、制御通過後に名前のないグループ参加者をローカルContactsから任意で補完します。デフォルト:false。channels.bluebubbles.groups: グループごとの設定(requireMentionなど)。channels.bluebubbles.sendReadReceipts: 既読通知を送信します(デフォルト:true)。channels.bluebubbles.blockStreaming: ブロックストリーミングを有効にします(デフォルト:false。ストリーミング返信に必須)。channels.bluebubbles.textChunkLimit: 送信チャンクサイズ(文字数、デフォルト: 4000)。channels.bluebubbles.sendTimeoutMs:/api/v1/message/text経由の送信テキスト送信に対するリクエストごとのタイムアウト(ms、デフォルト: 30000)。macOS 26環境でPrivate APIのiMessage送信がiMessage framework内で60秒以上停止する場合は引き上げてください。たとえば45000または60000。現在のところ、プローブ、チャット参照、リアクション、編集、ヘルスチェックは引き続き短い10秒デフォルトを使います。リアクションと編集まで対象を広げる対応は今後予定されています。アカウントごとの上書き:channels.bluebubbles.accounts.<accountId>.sendTimeoutMs。channels.bluebubbles.chunkMode:length(デフォルト)はtextChunkLimit超過時のみ分割します。newlineは長さで分割する前に空行(段落境界)で分割します。channels.bluebubbles.mediaMaxMb: 受信/送信メディア上限(MB、デフォルト: 8)。channels.bluebubbles.mediaLocalRoots: 送信ローカルメディアパスに許可される絶対ローカルディレクトリの明示的な許可リスト。これを設定しない限り、ローカルパス送信はデフォルトで拒否されます。アカウントごとの上書き:channels.bluebubbles.accounts.<accountId>.mediaLocalRoots。channels.bluebubbles.coalesceSameSenderDms: 連続する同一送信者のDM Webhookを1つのエージェントターンに統合し、Appleのテキスト+URL分割送信を1つのメッセージとして届くようにします(デフォルト:false)。シナリオ、ウィンドウ調整、トレードオフについては 分割送信されるDMの統合 を参照してください。明示的なmessages.inbound.byChannel.bluebubblesなしで有効にすると、デフォルトの受信デバウンスウィンドウは500 msから2500 msに広がります。channels.bluebubbles.historyLimit: コンテキスト用のグループメッセージ最大数(0で無効)。channels.bluebubbles.dmHistoryLimit: DM履歴上限。channels.bluebubbles.actions: 個別アクションを有効/無効にします。channels.bluebubbles.accounts: 複数アカウント設定。
agents.list[].groupChat.mentionPatterns(またはmessages.groupChat.mentionPatterns)。messages.responsePrefix.
アドレッシング / 配信ターゲット
安定したルーティングにはchat_guid を推奨します:
chat_guid:iMessage;-;+15555550123(グループ向け推奨)chat_id:123chat_identifier:...- 直接ハンドル:
+15555550123,user@example.com- 直接ハンドルに既存のDMチャットがない場合、OpenClawは
POST /api/v1/chat/newを通じて新規作成します。これにはBlueBubbles Private APIが有効である必要があります。
- 直接ハンドルに既存のDMチャットがない場合、OpenClawは
iMessageとSMSのルーティング
同じハンドルにMac上でiMessageチャットとSMSチャットの両方がある場合(たとえばiMessage登録済みだが、緑バブルのフォールバックも受信している電話番号)、OpenClawはiMessageチャットを優先し、黙ってSMSへダウングレードすることはありません。SMSチャットを強制したい場合は、明示的なsms: ターゲット接頭辞を使ってください(例: sms:+15555550123)。一致するiMessageチャットがないハンドルは、BlueBubblesが報告するチャット経由で送信されます。
セキュリティ
- Webhookリクエストは、
guid/passwordのクエリパラメータまたはヘッダーをchannels.bluebubbles.passwordと照合して認証されます。 - APIパスワードとWebhookエンドポイントは秘密にしてください(認証情報として扱ってください)。
- BlueBubbles Webhook認証にはlocalhostバイパスはありません。Webhookトラフィックをプロキシする場合も、BlueBubblesパスワードをリクエストにエンドツーエンドで保持してください。ここでは
gateway.trustedProxiesはchannels.bluebubbles.passwordの代わりになりません。参照: Gateway security。 - LAN外に公開する場合は、BlueBubblesサーバーでHTTPS + ファイアウォールルールを有効にしてください。
トラブルシューティング
- 入力中/既読イベントが動作しなくなった場合は、BlueBubbles Webhookログを確認し、ゲートウェイパスが
channels.bluebubbles.webhookPathと一致していることを確認してください。 - ペアリングコードは1時間で期限切れになります。
openclaw pairing list bluebubblesとopenclaw pairing approve bluebubbles <code>を使用してください。 - リアクションにはBlueBubbles Private API(
POST /api/v1/message/react)が必要です。サーバーバージョンがこれを公開していることを確認してください。 - 編集/送信取り消しにはmacOS 13+と互換性のあるBlueBubblesサーバーバージョンが必要です。macOS 26(Tahoe)では、Private APIの変更により編集は現在壊れています。
- グループアイコン更新はmacOS 26(Tahoe)では不安定な場合があります。APIが成功を返しても、新しいアイコンが同期されないことがあります。
- OpenClawは、BlueBubblesサーバーのmacOSバージョンに基づいて、既知の不具合があるアクションを自動で非表示にします。macOS 26(Tahoe)でまだeditが表示される場合は、
channels.bluebubbles.actions.edit=falseで手動無効化してください。 coalesceSameSenderDmsを有効にしているのに分割送信(例:Dump+ URL)がまだ2ターンで届く場合は、分割送信統合のトラブルシューティング のチェックリストを参照してください。よくある原因は、デバウンスウィンドウが狭すぎること、セッションログのタイムスタンプをWebhook到着時刻と誤読していること、または返信引用送信(2つ目のWebhookではなくreplyToBodyを使う)です。- ステータス/ヘルス情報:
openclaw status --allまたはopenclaw status --deep。
関連
- チャンネル概要 — サポートされているすべてのチャンネル
- ペアリング — DM認証とペアリングフロー
- グループ — グループチャットの動作とメンション制御
- チャンネルルーティング — メッセージのセッションルーティング
- セキュリティ — アクセスモデルとハードニング