BlueBubbles (macOS REST)
상태: BlueBubbles macOS 서버와 HTTP로 통신하는 내장 플러그인입니다. 레거시imsg 채널보다 API가 더 풍부하고 설정이 쉬워서 iMessage 연동에는 권장되는 방식입니다.
개요
- macOS에서 BlueBubbles helper app(bluebubbles.app)을 통해 실행됩니다.
- 권장 및 테스트 환경은 macOS Sequoia (15)입니다. macOS Tahoe (26)에서도 동작하지만 현재 Tahoe에서는 edit 기능이 깨져 있고, group icon 업데이트는 성공으로 표시되더라도 동기화되지 않을 수 있습니다.
- OpenClaw는 REST API(
GET /api/v1/ping,POST /message/text,POST /chat/:id/*)를 통해 BlueBubbles와 통신합니다. - 수신 메시지는 webhook으로 들어오며, 발신 응답, typing indicator, read receipt, tapback은 REST 호출로 처리합니다.
- 첨부 파일과 sticker는 수신 미디어로 가져오며, 가능한 경우 에이전트에도 전달됩니다.
- pairing 및 allowlist는 다른 채널과 동일한 방식으로 동작하며(
/channels/pairing등),channels.bluebubbles.allowFrom과 pairing code를 함께 사용합니다. - reaction은 Slack이나 Telegram과 마찬가지로 system event로 노출되므로, 에이전트가 응답 전에 이를 언급할 수 있습니다.
- 고급 기능으로 edit, unsend, reply threading, message effect, group management를 지원합니다.
빠른 시작
- Mac에 BlueBubbles server를 설치합니다(bluebubbles.app/install의 안내를 따르세요).
- BlueBubbles 설정에서 web API를 활성화하고 password를 설정합니다.
-
openclaw onboard를 실행해 BlueBubbles를 선택하거나, 아래처럼 수동으로 설정합니다. -
BlueBubbles webhook이 gateway를 가리키도록 설정합니다(예:
https://your-gateway-host:3000/bluebubbles-webhook?password=<password>). - gateway를 시작하면 webhook handler가 등록되고 pairing이 시작됩니다.
- webhook password는 항상 설정하세요.
- webhook 인증은 항상 필요합니다. OpenClaw는 loopback/proxy 구성과 관계없이
channels.bluebubbles.password와 일치하는 password/guid를 포함하지 않은 BlueBubbles webhook 요청을 거부합니다(예:?password=<password>또는x-password). - password 인증은 webhook body 전체를 읽거나 파싱하기 전에 먼저 검사합니다.
Messages.app 활성 상태 유지 (VM / headless setups)
일부 macOS VM 또는 상시 실행 환경에서는 Messages.app이 “idle” 상태가 되어, 앱을 열거나 foreground로 가져오기 전까지 수신 이벤트가 멈추는 경우가 있습니다. 간단한 우회 방법은 5분마다 Messages를 깨우는 것이며, AppleScript와 LaunchAgent로 구현할 수 있습니다.1) AppleScript 저장
다음 경로에 저장합니다.~/Scripts/poke-messages.scpt
2) LaunchAgent 설치
다음 경로에 저장합니다.~/Library/LaunchAgents/com.user.poke-messages.plist
- 이 LaunchAgent는 300초마다 그리고 로그인 시점에 실행됩니다.
- 첫 실행 시 macOS Automation 권한 요청(
osascript→ Messages)이 나타날 수 있습니다. LaunchAgent를 실행하는 동일한 사용자 세션에서 이를 허용하세요.
Onboarding
BlueBubbles는 interactive setup wizard에서 사용할 수 있습니다.- Server URL (required): BlueBubbles server 주소(예:
http://192.168.1.100:1234) - Password (required): BlueBubbles Server 설정의 API password
- Webhook path (optional): 기본값은
/bluebubbles-webhook - DM policy: pairing, allowlist, open, 또는 disabled
- Allow list: 전화번호, 이메일, 또는 chat target
접근 제어 (DM + group)
DM:- 기본값은
channels.bluebubbles.dmPolicy = "pairing"입니다. - 알 수 없는 발신자에게는 pairing code가 전송되며, 승인되기 전까지 메시지는 무시됩니다(code는 1시간 후 만료).
- 다음 명령으로 승인합니다.
openclaw pairing list bluebubblesopenclaw pairing approve bluebubbles <CODE>
- pairing이 기본 token exchange 방식입니다. 자세한 내용은 Pairing을 참고하세요.
channels.bluebubbles.groupPolicy = open | allowlist | disabled(기본값:allowlist)입니다.channels.bluebubbles.groupAllowFrom은allowlist가 설정되었을 때 group에서 누가 trigger할 수 있는지 제어합니다.
Mention gating (group)
BlueBubbles는 iMessage/WhatsApp과 비슷하게 group chat에서 mention gating을 지원합니다.- mention 감지는
agents.list[].groupChat.mentionPatterns(또는messages.groupChat.mentionPatterns)를 사용합니다. - group에
requireMention이 활성화되어 있으면, 에이전트는 mention된 경우에만 응답합니다. - 권한이 있는 발신자의 control command는 mention gating을 우회합니다.
Command gating
- control command(예:
/config,/model)은 권한이 있어야 실행할 수 있습니다. - command 권한 판정에는
allowFrom과groupAllowFrom을 사용합니다. - 권한이 있는 발신자는 group에서 mention 없이도 control command를 실행할 수 있습니다.
Typing + read receipts
- Typing indicators: 응답 생성 전과 생성 중에 자동으로 전송됩니다.
- Read receipts:
channels.bluebubbles.sendReadReceipts로 제어하며 기본값은true입니다. - Typing indicators: OpenClaw는 typing start event를 전송하고, BlueBubbles는 전송 완료나 timeout 시 typing 상태를 자동으로 해제합니다(DELETE를 사용한 수동 중지는 신뢰할 수 없습니다).
고급 액션
BlueBubbles는 config에서 활성화되면 다음과 같은 고급 message action을 지원합니다.- react: tapback reaction 추가/제거 (
messageId,emoji,remove) - edit: 전송한 메시지 수정 (
messageId,text) - unsend: 메시지 전송 취소 (
messageId) - reply: 특정 메시지에 답글 전송 (
messageId,text,to) - sendWithEffect: iMessage effect와 함께 전송 (
text,to,effectId) - renameGroup: group chat 이름 변경 (
chatGuid,displayName) - setGroupIcon: group chat icon/photo 설정 (
chatGuid,media) - macOS 26 Tahoe에서는 불안정할 수 있으며 API가 성공을 반환해도 icon이 동기화되지 않을 수 있습니다. - addParticipant: group에 참가자 추가 (
chatGuid,address) - removeParticipant: group에서 참가자 제거 (
chatGuid,address) - leaveGroup: group chat 나가기 (
chatGuid) - sendAttachment: 미디어/파일 전송 (
to,buffer,filename,asVoice)- Voice memo를 보내려면 MP3 또는 CAF 오디오와 함께
asVoice: true를 설정합니다. BlueBubbles는 voice memo 전송 시 MP3를 CAF로 변환합니다.
- Voice memo를 보내려면 MP3 또는 CAF 오디오와 함께
Message ID (short vs full)
OpenClaw는 token을 절약하기 위해 짧은 message ID(예:1, 2)를 노출할 수 있습니다.
MessageSid/ReplyToId는 short ID일 수 있습니다.MessageSidFull/ReplyToIdFull에는 provider의 full ID가 들어 있습니다.- short ID는 메모리에만 존재하므로 restart나 cache eviction 이후에는 사라질 수 있습니다.
- action은 short 또는 full
messageId모두 받을 수 있지만, short ID가 더 이상 존재하지 않으면 오류가 발생합니다.
- Template:
{{MessageSidFull}},{{ReplyToIdFull}} - Context: inbound payload의
MessageSidFull/ReplyToIdFull
Block streaming
응답을 한 개의 메시지로 보낼지, 여러 block으로 나누어 streaming할지 제어할 수 있습니다.Media + limits
- 수신 attachment는 다운로드되어 media cache에 저장됩니다.
- 수신 및 발신 media 크기 제한은
channels.bluebubbles.mediaMaxMb로 제어하며 기본값은 8 MB입니다. - 발신 text는
channels.bluebubbles.textChunkLimit에 따라 분할되며 기본값은 4000자입니다.
Configuration reference
전체 설정은 Configuration을 참고하세요. Provider 옵션:channels.bluebubbles.enabled: 채널 활성화/비활성화channels.bluebubbles.serverUrl: BlueBubbles REST API base URLchannels.bluebubbles.password: API passwordchannels.bluebubbles.webhookPath: webhook endpoint path(기본값:/bluebubbles-webhook)channels.bluebubbles.dmPolicy:pairing | allowlist | open | disabled(기본값:pairing)channels.bluebubbles.allowFrom: DM allowlist(handles, emails, E.164 numbers,chat_id:*,chat_guid:*)channels.bluebubbles.groupPolicy:open | allowlist | disabled(기본값:allowlist)channels.bluebubbles.groupAllowFrom: group sender allowlistchannels.bluebubbles.groups: group별 config(requireMention등)channels.bluebubbles.sendReadReceipts: read receipt 전송(기본값:true)channels.bluebubbles.blockStreaming: block streaming 활성화(기본값:false, streaming reply에 필요)channels.bluebubbles.textChunkLimit: 발신 chunk 크기(문자 수, 기본값: 4000)channels.bluebubbles.chunkMode:length(기본값)는textChunkLimit를 초과할 때만 분할하고,newline은 빈 줄(문단 경계) 기준으로 먼저 나눈 뒤 길이 기준 분할을 적용합니다.channels.bluebubbles.mediaMaxMb: 수신/발신 media 제한(MB, 기본값: 8)channels.bluebubbles.mediaLocalRoots: 발신 local media path에 허용되는 절대 디렉터리의 명시적 allowlist입니다. 이 값이 설정되지 않으면 local path 전송은 기본적으로 거부됩니다. 계정별 override:channels.bluebubbles.accounts.<accountId>.mediaLocalRootschannels.bluebubbles.historyLimit: group context에 포함할 최대 메시지 수(0이면 비활성화)channels.bluebubbles.dmHistoryLimit: DM history limitchannels.bluebubbles.actions: 개별 action 활성화/비활성화channels.bluebubbles.accounts: multi-account configuration
agents.list[].groupChat.mentionPatterns(또는messages.groupChat.mentionPatterns)messages.responsePrefix
Addressing / delivery targets
안정적인 라우팅을 위해서는chat_guid 사용을 권장합니다.
chat_guid:iMessage;-;+15555550123(group에서는 권장)chat_id:123chat_identifier:...- 직접 handle 지정:
+15555550123,user@example.com- 직접 handle에 기존 DM chat이 없으면 OpenClaw가
POST /api/v1/chat/new를 통해 새 chat을 생성합니다. 이 기능을 사용하려면 BlueBubbles Private API가 활성화되어 있어야 합니다.
- 직접 handle에 기존 DM chat이 없으면 OpenClaw가
Security
- webhook 요청은 query param 또는 header의
guid/password를channels.bluebubbles.password와 비교해 인증합니다.localhost에서 온 요청도 허용됩니다. - API password와 webhook endpoint는 자격 증명처럼 취급하고 비밀로 유지하세요.
- localhost 신뢰 때문에, 동일 호스트의 reverse proxy가 의도치 않게 password를 우회할 수 있습니다. gateway를 proxy 뒤에 둘 경우 proxy 자체에 인증을 적용하고
gateway.trustedProxies를 설정하세요. 자세한 내용은 Gateway security를 참고하세요. - BlueBubbles server를 LAN 외부에 노출한다면 HTTPS와 firewall rule을 함께 사용하세요.
Troubleshooting
- typing/read event가 동작하지 않으면 BlueBubbles webhook log를 확인하고, gateway 경로가
channels.bluebubbles.webhookPath와 일치하는지 점검하세요. - pairing code는 1시간 후 만료됩니다.
openclaw pairing list bluebubbles와openclaw pairing approve bluebubbles <code>를 사용하세요. - reaction에는 BlueBubbles private API(
POST /api/v1/message/react)가 필요하므로, server 버전이 해당 endpoint를 제공하는지 확인하세요. - edit/unsend는 macOS 13+와 호환되는 BlueBubbles server 버전이 필요합니다. macOS 26(Tahoe)에서는 private API 변경으로 인해 현재 edit가 동작하지 않습니다.
- group icon 업데이트는 macOS 26(Tahoe)에서 불안정할 수 있습니다. API는 성공을 반환해도 새 icon이 동기화되지 않을 수 있습니다.
- OpenClaw는 BlueBubbles server의 macOS 버전에 따라 알려진 문제의 action을 자동으로 숨깁니다. macOS 26(Tahoe)에서 edit가 계속 보이면
channels.bluebubbles.actions.edit=false로 수동 비활성화하세요. - 상태 및 health 정보는
openclaw status --all또는openclaw status --deep에서 확인할 수 있습니다.