Mainstream messaging
BlueBubbles
상태: HTTP를 통해 BlueBubbles macOS 서버와 통신하는 번들 레거시 Plugin입니다. 기존 BlueBubbles 설정은 계속 작동하지만, 새 OpenClaw iMessage 배포에서는 호스트에 요구 사항이 맞는 경우 네이티브 iMessage Plugin을 우선 사용해야 합니다.
개요
- BlueBubbles 헬퍼 앱(bluebubbles.app)을 통해 macOS에서 실행됩니다.
- 이미 BlueBubbles 채널 ID, Webhook 상태, 그룹 대상, Cron 전달 또는 워크스페이스 라우팅에 의존하는 설치를 위한 레거시 대체 경로입니다.
- 권장/테스트됨: macOS Sequoia (15). macOS Tahoe (26)도 작동하지만, 현재 Tahoe에서는 편집이 깨져 있으며 그룹 아이콘 업데이트가 성공으로 보고되더라도 동기화되지 않을 수 있습니다.
- OpenClaw는 REST API(
GET /api/v1/ping,POST /message/text,POST /chat/:id/*)를 통해 통신합니다. - 수신 메시지는 Webhook으로 도착하며, 발신 답장, 입력 표시, 읽음 확인, tapback은 REST 호출입니다.
- 첨부 파일과 스티커는 인바운드 미디어로 수집됩니다(가능한 경우 에이전트에 노출됨).
- MP3 또는 CAF 오디오를 합성하는 자동 TTS 답장은 일반 파일 첨부 대신 iMessage 음성 메모 말풍선으로 전달됩니다.
- 페어링/허용 목록은 다른 채널(
/channels/pairing등)과 같은 방식으로channels.bluebubbles.allowFrom+ 페어링 코드를 사용합니다. - 반응은 Slack/Telegram과 마찬가지로 시스템 이벤트로 노출되어 에이전트가 답장 전에 이를 "언급"할 수 있습니다.
- 고급 기능: 편집, 보내기 취소, 답글 스레딩, 메시지 효과, 그룹 관리.
빠른 시작
BlueBubbles 설치
Mac에 BlueBubbles 서버를 설치합니다(bluebubbles.app/install의 지침을 따르세요).
웹 API 활성화
BlueBubbles 구성에서 웹 API를 활성화하고 비밀번호를 설정합니다.
OpenClaw 구성
openclaw onboard를 실행하고 BlueBubbles를 선택하거나, 수동으로 구성합니다.
{
channels: {
bluebubbles: {
enabled: true,
serverUrl: "http://192.168.1.100:1234",
password: "example-password",
webhookPath: "/bluebubbles-webhook",
},
},
}
Webhook을 Gateway로 지정
BlueBubbles Webhook이 Gateway를 가리키도록 설정합니다(예: https://your-gateway-host:3000/bluebubbles-webhook?password=<password>).
Gateway 시작
Gateway를 시작합니다. Webhook 핸들러가 등록되고 페어링이 시작됩니다.
Messages.app을 계속 실행 상태로 유지하기(VM / 헤드리스 설정)
일부 macOS VM / 상시 실행 설정에서는 Messages.app이 "유휴" 상태가 될 수 있습니다(앱을 열거나 포그라운드로 가져오기 전까지 수신 이벤트가 멈춤). 간단한 우회 방법은 AppleScript + LaunchAgent를 사용해 5분마다 Messages를 건드리는 것입니다.
AppleScript 저장
다음을 ~/Scripts/poke-messages.scpt로 저장합니다.
try
tell application "Messages"
if not running then
launch
end if
-- Touch the scripting interface to keep the process responsive.
set _chatCount to (count of chats)
end tell
on error
-- Ignore transient failures (first-run prompts, locked session, etc).
end try
LaunchAgent 설치
다음을 ~/Library/LaunchAgents/com.user.poke-messages.plist로 저장합니다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.poke-messages</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-lc</string>
<string>/usr/bin/osascript "$HOME/Scripts/poke-messages.scpt"</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>300</integer>
<key>StandardOutPath</key>
<string>/tmp/poke-messages.log</string>
<key>StandardErrorPath</key>
<string>/tmp/poke-messages.err</string>
</dict>
</plist>
이는 300초마다 그리고 로그인 시 실행됩니다. 첫 실행 시 macOS Automation 프롬프트(osascript → Messages)가 표시될 수 있습니다. LaunchAgent를 실행하는 동일한 사용자 세션에서 승인하세요.
로드
launchctl unload ~/Library/LaunchAgents/com.user.poke-messages.plist 2>/dev/null || true
launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist
온보딩
BlueBubbles는 대화형 온보딩에서 사용할 수 있습니다.
openclaw onboard
마법사가 다음 항목을 요청합니다.
Server URLstringrequiredBlueBubbles 서버 주소(예: http://192.168.1.100:1234).
PasswordstringrequiredBlueBubbles Server 설정의 API 비밀번호.
Webhook pathstringWebhook 엔드포인트 경로.
DM policystringpairing, allowlist, open 또는 disabled.
Allow liststring[]전화번호, 이메일 또는 채팅 대상.
CLI를 통해 BlueBubbles를 추가할 수도 있습니다.
openclaw channels add bluebubbles --http-url http://192.168.1.100:1234 --password <password>
접근 제어(DM + 그룹)
DM
- 기본값:
channels.bluebubbles.dmPolicy = "pairing". - 알 수 없는 발신자는 페어링 코드를 받으며, 승인될 때까지 메시지는 무시됩니다(코드는 1시간 후 만료).
- 승인 방법:
openclaw pairing list bluebubblesopenclaw pairing approve bluebubbles <CODE>
- 페어링은 기본 토큰 교환 방식입니다. 자세한 내용: 페어링
그룹
channels.bluebubbles.groupPolicy = open | allowlist | disabled(기본값:allowlist).allowlist가 설정된 경우channels.bluebubbles.groupAllowFrom은 그룹에서 누가 트리거할 수 있는지 제어합니다.
연락처 이름 보강(macOS, 선택 사항)
BlueBubbles 그룹 Webhook에는 원시 참가자 주소만 포함되는 경우가 많습니다. GroupMembers 컨텍스트에 로컬 연락처 이름을 대신 표시하려면 macOS에서 로컬 연락처 보강을 선택적으로 활성화할 수 있습니다.
channels.bluebubbles.enrichGroupParticipantsFromContacts = true는 조회를 활성화합니다. 기본값:false.- 조회는 그룹 접근, 명령 권한 부여, 멘션 게이팅이 메시지 통과를 허용한 후에만 실행됩니다.
- 이름이 없는 전화번호 참가자만 보강됩니다.
- 로컬 일치 항목을 찾지 못하면 원시 전화번호가 대체값으로 유지됩니다.
{
channels: {
bluebubbles: {
enrichGroupParticipantsFromContacts: true,
},
},
}
멘션 게이팅(그룹)
BlueBubbles는 iMessage/WhatsApp 동작과 일치하는 그룹 채팅 멘션 게이팅을 지원합니다.
agents.list[].groupChat.mentionPatterns(또는messages.groupChat.mentionPatterns)를 사용해 멘션을 감지합니다.- 그룹에
requireMention이 활성화된 경우, 에이전트는 멘션된 경우에만 응답합니다. - 권한이 있는 발신자의 제어 명령은 멘션 게이팅을 우회합니다.
그룹별 구성:
{
channels: {
bluebubbles: {
groupPolicy: "allowlist",
groupAllowFrom: ["+15555550123"],
groups: {
"*": { requireMention: true }, // default for all groups
"iMessage;-;chat123": { requireMention: false }, // override for specific group
},
},
},
}
명령 게이팅
- 제어 명령(예:
/config,/model)에는 권한 부여가 필요합니다. - 명령 권한 부여 여부를 결정하는 데
allowFrom및groupAllowFrom을 사용합니다. - 권한이 있는 발신자는 그룹에서 멘션하지 않아도 제어 명령을 실행할 수 있습니다.
그룹별 시스템 프롬프트
channels.bluebubbles.groups.* 아래의 각 항목은 선택적 systemPrompt 문자열을 허용합니다. 이 값은 해당 그룹의 메시지를 처리하는 모든 턴에서 에이전트의 시스템 프롬프트에 주입되므로, 에이전트 프롬프트를 편집하지 않고도 그룹별 페르소나 또는 동작 규칙을 설정할 수 있습니다.
{
channels: {
bluebubbles: {
groups: {
"iMessage;-;chat123": {
systemPrompt: "Keep responses under 3 sentences. Mirror the group's casual tone.",
},
},
},
},
}
키는 BlueBubbles가 그룹에 대해 보고하는 chatGuid / chatIdentifier / 숫자 chatId와 일치하며, "*" 와일드카드 항목은 정확히 일치하는 항목이 없는 모든 그룹에 대한 기본값을 제공합니다(requireMention 및 그룹별 도구 정책에서 사용하는 것과 동일한 패턴). 정확히 일치하는 항목은 항상 와일드카드보다 우선합니다. DM은 이 필드를 무시합니다. 대신 에이전트 수준 또는 계정 수준 프롬프트 사용자 지정을 사용하세요.
실제 예: 스레드 답글과 tapback 반응(비공개 API)
BlueBubbles 비공개 API가 활성화되면, 인바운드 메시지는 짧은 메시지 ID(예: [[reply_to:5]])와 함께 도착하며, 에이전트는 action=reply를 호출해 특정 메시지 아래에 스레드로 답장하거나 action=react를 호출해 tapback을 남길 수 있습니다. 그룹별 systemPrompt는 에이전트가 올바른 도구를 선택하도록 유지하는 신뢰할 수 있는 방법입니다.
{
channels: {
bluebubbles: {
groups: {
"iMessage;+;chat-family": {
systemPrompt: "When replying in this group, always call action=reply with the [[reply_to:N]] messageId from context so your response threads under the triggering message. Never send a new unlinked message. For short acknowledgements ('ok', 'got it', 'on it'), use action=react with an appropriate tapback emoji (❤️, 👍, 😂, ‼️, ❓) instead of sending a text reply.",
},
},
},
},
}
Tapback 반응과 스레드 답글은 모두 BlueBubbles 비공개 API가 필요합니다. 기본 동작은 고급 작업 및 메시지 ID를 참고하세요.
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또는[email protected]같은 정규화된 DM 핸들chat_id:<id>chat_guid:<guid>chat_identifier:<identifier>
안정적인 그룹 바인딩에는 chat_id:* 또는 chat_identifier:*를 권장합니다.
예시:
{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: { agent: "codex", backend: "acpx", mode: "persistent" },
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "bluebubbles",
accountId: "default",
peer: { kind: "dm", id: "+15555550123" },
},
acp: { label: "codex-imessage" },
},
],
}
공유 ACP 바인딩 동작은 ACP 에이전트를 참조하세요.
입력 표시 + 읽음 확인
- 입력 표시기: 응답 생성 전과 중에 자동으로 전송됩니다.
- 읽음 확인:
channels.bluebubbles.sendReadReceipts로 제어됩니다(기본값:true). - 입력 표시기: OpenClaw는 입력 시작 이벤트를 보냅니다. BlueBubbles는 전송 또는 시간 초과 시 입력 상태를 자동으로 지웁니다(DELETE를 통한 수동 중지는 신뢰할 수 없습니다).
{
channels: {
bluebubbles: {
sendReadReceipts: false, // disable read receipts
},
},
}
고급 작업
BlueBubbles는 설정에서 활성화된 경우 고급 메시지 작업을 지원합니다.
{
channels: {
bluebubbles: {
actions: {
reactions: true, // tapbacks (default: true)
edit: true, // edit sent messages (macOS 13+, broken on macOS 26 Tahoe)
unsend: true, // unsend messages (macOS 13+)
reply: true, // reply threading by message GUID
sendWithEffect: true, // message effects (slam, loud, etc.)
renameGroup: true, // rename group chats
setGroupIcon: true, // set group chat icon/photo (flaky on macOS 26 Tahoe)
addParticipant: true, // add participants to groups
removeParticipant: true, // remove participants from groups
leaveGroup: true, // leave group chats
sendAttachment: true, // send attachments/media
},
},
},
}
사용 가능한 작업
- react: 탭백 반응을 추가/제거합니다(
messageId,emoji,remove). iMessage의 기본 탭백 세트는love,like,dislike,laugh,emphasize,question입니다. 에이전트가 해당 세트 밖의 이모지(예:👀)를 선택하면, 반응 도구는 전체 요청을 실패시키는 대신 탭백이 계속 렌더링되도록love로 폴백합니다. 설정된 확인 반응은 여전히 엄격하게 검증되며 알 수 없는 값에서는 오류가 발생합니다. - 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).- 음성 메모: iMessage 음성 메시지로 보내려면 MP3 또는 CAF 오디오와 함께
asVoice: true를 설정하세요. BlueBubbles는 음성 메모를 보낼 때 MP3 → CAF로 변환합니다.
- 음성 메모: iMessage 음성 메시지로 보내려면 MP3 또는 CAF 오디오와 함께
- 레거시 별칭:
sendAttachment는 여전히 작동하지만, 정식 작업 이름은upload-file입니다.
메시지 ID(짧은 형식 vs 전체 형식)
OpenClaw는 토큰을 절약하기 위해 짧은 메시지 ID(예: 1, 2)를 표시할 수 있습니다.
MessageSid/ReplyToId는 짧은 ID일 수 있습니다.MessageSidFull/ReplyToIdFull에는 제공자 전체 ID가 포함됩니다.- 짧은 ID는 메모리 내에만 있으며, 재시작 또는 캐시 축출 시 만료될 수 있습니다.
- 작업은 짧은
messageId또는 전체messageId를 받지만, 짧은 ID를 더 이상 사용할 수 없으면 오류가 발생합니다.
내구성 있는 자동화와 저장에는 전체 ID를 사용하세요.
- 템플릿:
{{MessageSidFull}},{{ReplyToIdFull}} - 컨텍스트: 인바운드 페이로드의
MessageSidFull/ReplyToIdFull
템플릿 변수는 설정을 참조하세요.
분할 전송 DM 병합(하나의 작성 내용에 명령 + URL)
사용자가 iMessage에서 명령과 URL을 함께 입력하면(예: Dump https://example.com/article) Apple은 전송을 두 개의 별도 Webhook 전달로 분할합니다.
- 텍스트 메시지(
"Dump"). - OG 미리보기 이미지가 첨부된 URL 미리보기 말풍선(
"https://...").
대부분의 설정에서 두 Webhook은 약 0.8-2.0초 간격으로 OpenClaw에 도착합니다. 병합이 없으면 에이전트는 1번째 턴에서 명령만 받고 응답하며(흔히 "URL을 보내 주세요"), 2번째 턴에서야 URL을 보게 됩니다. 이 시점에는 이미 명령 컨텍스트가 사라진 뒤입니다.
channels.bluebubbles.coalesceSameSenderDms는 DM에서 같은 발신자의 연속 Webhook을 하나의 에이전트 턴으로 병합하도록 선택합니다. 그룹 채팅은 다중 사용자 턴 구조가 유지되도록 계속 메시지별로 키를 사용합니다.
활성화 시점
다음 경우 활성화하세요.
- 하나의 메시지에서
command + payload를 기대하는 Skills를 제공하는 경우(dump, paste, save, queue 등). - 사용자가 명령과 함께 URL, 이미지 또는 긴 콘텐츠를 붙여 넣는 경우.
- 추가되는 DM 턴 지연 시간을 허용할 수 있는 경우(아래 참조).
다음 경우 비활성화 상태로 두세요.
- 한 단어 DM 트리거의 명령 지연 시간을 최소화해야 하는 경우.
- 모든 흐름이 페이로드 후속 입력 없는 일회성 명령인 경우.
활성화
{
channels: {
bluebubbles: {
coalesceSameSenderDms: true, // opt in (default: false)
},
},
}
플래그가 켜져 있고 명시적인 messages.inbound.byChannel.bluebubbles가 없으면 디바운스 창이 2500 ms로 넓어집니다(병합하지 않을 때의 기본값은 500 ms). 더 넓은 창이 필요합니다. Apple의 0.8-2.0초 분할 전송 간격은 더 좁은 기본값에 맞지 않습니다.
창을 직접 조정하려면:
{
messages: {
inbound: {
byChannel: {
// 2500 ms works for most setups; raise to 4000 ms if your Mac is slow
// or under memory pressure (observed gap can stretch past 2 s then).
bluebubbles: 2500,
},
},
},
}
트레이드오프
- DM 제어 명령에 추가 지연 시간이 생깁니다. 플래그가 켜져 있으면 DM 제어 명령 메시지(예:
Dump,Save등)는 페이로드 Webhook이 올 수 있으므로 디스패치 전에 디바운스 창까지 대기합니다. 그룹 채팅 명령은 즉시 디스패치를 유지합니다. - 병합된 출력에는 한계가 있습니다 - 병합된 텍스트는 명시적인
…[truncated]표시와 함께 4000자로 제한됩니다. 첨부 파일은 20개로 제한됩니다. 소스 항목은 10개로 제한됩니다(그 이후는 첫 항목과 최신 항목을 유지). 모든 소스messageId는 여전히 인바운드 중복 제거에 도달하므로, 나중에 MessagePoller가 개별 이벤트를 재생해도 중복으로 인식됩니다. - 채널별 선택 사항입니다. 다른 채널(Telegram, WhatsApp, Slack, …)에는 영향을 주지 않습니다.
시나리오와 에이전트가 보는 내용
| 사용자가 작성한 내용 | Apple 전달 방식 | 플래그 꺼짐(기본값) | 플래그 켜짐 + 2500 ms 창 |
|---|---|---|---|
Dump https://example.com(한 번 전송) |
약 1초 간격의 Webhook 2개 | 두 에이전트 턴: "Dump"만, 그다음 URL | 한 턴: 병합된 텍스트 Dump https://example.com |
Save this 📎image.jpg caption(첨부 파일 + 텍스트) |
Webhook 2개 | 두 턴 | 한 턴: 텍스트 + 이미지 |
/status(독립 실행 명령) |
Webhook 1개 | 즉시 디스패치 | 창까지 대기한 다음 디스패치 |
| URL만 붙여넣음 | Webhook 1개 | 즉시 디스패치 | 즉시 디스패치(버킷에 항목이 하나뿐임) |
| 텍스트 + URL을 몇 분 간격의 의도적인 별도 메시지 두 개로 보냄 | 창 밖의 Webhook 2개 | 두 턴 | 두 턴(그 사이 창 만료) |
| 빠른 폭주(창 안에서 작은 DM 10개 초과) | Webhook N개 | N턴 | 한 턴, 제한된 출력(첫 항목 + 최신 항목, 텍스트/첨부 파일 제한 적용) |
분할 전송 병합 문제 해결
플래그가 켜져 있는데도 분할 전송이 여전히 두 턴으로 도착한다면 각 계층을 확인하세요.
설정이 실제로 로드됨
grep coalesceSameSenderDms ~/.openclaw/openclaw.json
그런 다음 openclaw gateway restart를 실행하세요. 플래그는 디바운서 레지스트리 생성 시 읽힙니다.
설정에 충분히 넓은 디바운스 창
~/Library/Logs/bluebubbles-server/main.log 아래의 BlueBubbles 서버 로그를 확인하세요.
grep -E "Dispatching event to webhook" main.log | tail -20
"Dump" 스타일 텍스트 디스패치와 뒤따르는 "https://..."; Attachments: 디스패치 사이의 간격을 측정하세요. messages.inbound.byChannel.bluebubbles를 그 간격을 충분히 감쌀 수 있게 높이세요.
세션 JSONL 타임스탬프 ≠ Webhook 도착
세션 이벤트 타임스탬프(~/.openclaw/agents/<id>/sessions/*.jsonl)는 Gateway가 에이전트에 메시지를 전달한 시점을 반영하며, Webhook이 도착한 시점이 아닙니다. [Queued messages while agent was busy]로 태그된 대기 중인 두 번째 메시지는 두 번째 Webhook이 도착했을 때 첫 번째 턴이 아직 실행 중이었다는 뜻입니다. 병합 버킷은 이미 플러시된 상태였습니다. 세션 로그가 아니라 BB 서버 로그에 맞춰 창을 조정하세요.
메모리 압박으로 느려지는 답장 디스패치
더 작은 머신(8 GB)에서는 에이전트 턴이 충분히 오래 걸려 답장이 완료되기 전에 병합 버킷이 플러시되고, URL이 대기 중인 두 번째 턴으로 들어갈 수 있습니다. memory_pressure와 ps -o rss -p $(pgrep openclaw-gateway)를 확인하세요. Gateway가 약 500 MB RSS를 넘고 압축기가 활성화되어 있다면 다른 무거운 프로세스를 닫거나 더 큰 호스트로 올리세요.
답장 인용 전송은 다른 경로
사용자가 기존 URL 말풍선에 대한 답장으로 Dump를 탭했다면(iMessage에서 Dump 말풍선에 "1 Reply" 배지가 표시됨), URL은 두 번째 Webhook이 아니라 replyToBody에 있습니다. 병합은 적용되지 않습니다. 이는 디바운서 문제가 아니라 Skill/프롬프트 문제입니다.
블록 스트리밍
응답을 단일 메시지로 보낼지 블록 단위로 스트리밍할지 제어합니다.
{
channels: {
bluebubbles: {
blockStreaming: true, // enable block streaming (off by default)
},
},
}
미디어 + 제한
- 인바운드 첨부 파일은 다운로드되어 미디어 캐시에 저장됩니다.
- 인바운드 및 아웃바운드 미디어의 미디어 한도는
channels.bluebubbles.mediaMaxMb를 통해 설정합니다(기본값: 8 MB). - 아웃바운드 텍스트는
channels.bluebubbles.textChunkLimit에 맞게 청크로 나뉩니다(기본값: 4000자).
설정 참조
전체 설정: 설정
연결 및 Webhook
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에서 게이팅을 통과한 뒤 이름이 없는 그룹 참여자를 로컬 연락처에서 선택적으로 보강합니다. 기본값: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). Private API iMessage 전송이 iMessage 프레임워크 안에서 60초 이상 멈출 수 있는 macOS 26 설정에서는 이 값을 높이세요. 예: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을 하나의 에이전트 턴으로 병합하여 Apple의 텍스트+URL 분할 전송이 단일 메시지로 도착하게 합니다(기본값:false). 시나리오, 윈도우 조정, 트레이드오프는 분할 전송 DM 병합을 참고하세요. 명시적인messages.inbound.byChannel.bluebubbles없이 활성화하면 기본 인바운드 디바운스 윈도우가 500 ms에서 2500 ms로 넓어집니다.channels.bluebubbles.historyLimit: 컨텍스트에 사용할 최대 그룹 메시지 수입니다(0이면 비활성화).channels.bluebubbles.dmHistoryLimit: DM 기록 제한입니다.channels.bluebubbles.replyContextApiFallback: 인바운드 답장이replyToBody/replyToSender없이 도착하고 메모리 내 답장 컨텍스트 캐시도 누락된 경우, 최선의 대체 수단으로 BlueBubbles HTTP API에서 원본 메시지를 가져옵니다(기본값:false). 하나의 BlueBubbles 계정을 공유하는 다중 인스턴스 배포, 프로세스 재시작 이후, 또는 오래 유지된 TTL/LRU 캐시 축출 이후에 유용합니다. 이 가져오기는 다른 모든 BlueBubbles 클라이언트 요청과 같은 정책으로 SSRF 보호되며, 예외를 던지지 않고, 이후 답장이 비용을 분산할 수 있도록 캐시를 채웁니다. 계정별 재정의:channels.bluebubbles.accounts.<accountId>.replyContextApiFallback. 채널 수준 설정은 해당 플래그를 생략한 계정으로 전파됩니다.
작업 및 계정
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,[email protected]- 직접 핸들에 기존 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 보안을 참고하세요. - LAN 외부에 노출하는 경우 BlueBubbles 서버에서 HTTPS와 방화벽 규칙을 활성화하세요.
문제 해결
- 입력/읽음 이벤트가 작동하지 않으면 BlueBubbles Webhook 로그를 확인하고 Gateway 경로가
channels.bluebubbles.webhookPath와 일치하는지 확인하세요. - 페어링 코드는 한 시간 후 만료됩니다.
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)에서 편집이 여전히 표시되면
channels.bluebubbles.actions.edit=false로 수동 비활성화하세요. coalesceSameSenderDms가 활성화되어 있지만 분할 전송(예:Dump+ URL)이 여전히 두 턴으로 도착하는 경우: 분할 전송 병합 문제 해결 체크리스트를 참고하세요. 일반적인 원인은 너무 짧은 디바운스 윈도우, Webhook 도착 시각으로 잘못 읽은 세션 로그 타임스탬프, 또는 답장 인용 전송(replyToBody를 사용하며 두 번째 Webhook이 아님)입니다.- 상태/상태 확인 정보:
openclaw status --all또는openclaw status --deep.
일반적인 채널 워크플로 참고 자료는 채널 및 Plugins 가이드를 참고하세요.