Mainstream messaging
iMessage
स्थिति: native external CLI integration। Gateway imsg rpc spawn करता है और stdio पर JSON-RPC के माध्यम से communicate करता है (अलग daemon/port नहीं)। उन्नत actions के लिए imsg launch और सफल private API probe आवश्यक है।
Replies, tapbacks, effects, attachments, और group management।
iMessage DMs default रूप से pairing mode में होते हैं।
जब Gateway Messages Mac पर नहीं चल रहा हो, तो SSH wrapper का उपयोग करें।
पूर्ण iMessage field reference।
त्वरित setup
Local Mac (fast path)
Install and verify imsg
brew install steipete/tap/imsgimsg rpc --helpimsg launchopenclaw channels status --probeConfigure OpenClaw
{channels: {imessage: {enabled: true,cliPath: "/usr/local/bin/imsg",dbPath: "/Users/user/Library/Messages/chat.db",},},}Start gateway
openclaw gatewayApprove first DM pairing (default dmPolicy)
openclaw pairing list imessageopenclaw pairing approve imessage <CODE>Pairing requests 1 घंटे बाद expire हो जाते हैं।
Remote Mac over SSH
OpenClaw को केवल stdio-compatible cliPath चाहिए, इसलिए आप cliPath को ऐसे wrapper script पर point कर सकते हैं जो remote Mac पर SSH करके imsg चलाता है।
#!/usr/bin/env bashexec ssh -T gateway-host imsg "$@"attachments enabled होने पर अनुशंसित config:
{channels: {imessage: { enabled: true, cliPath: "~/.openclaw/scripts/imsg-ssh", remoteHost: "user@gateway-host", // used for SCP attachment fetches includeAttachments: true, // Optional: override allowed attachment roots. // Defaults include /Users/*/Library/Messages/Attachments attachmentRoots: ["/Users/*/Library/Messages/Attachments"], remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],},},}यदि remoteHost set नहीं है, तो OpenClaw SSH wrapper script को parse करके इसे auto-detect करने का प्रयास करता है।
remoteHost host या user@host होना चाहिए (spaces या SSH options नहीं)।
OpenClaw SCP के लिए strict host-key checking का उपयोग करता है, इसलिए relay host key पहले से ~/.ssh/known_hosts में मौजूद होनी चाहिए।
Attachment paths को allowed roots (attachmentRoots / remoteAttachmentRoots) के against validate किया जाता है।
आवश्यकताएँ और permissions (macOS)
imsgचलाने वाले Mac पर Messages signed in होना चाहिए।- OpenClaw/
imsgचलाने वाले process context के लिए Full Disk Access आवश्यक है (Messages DB access)। - Messages.app के माध्यम से messages भेजने के लिए Automation permission आवश्यक है।
- उन्नत actions (react / edit / unsend / threaded reply / effects / group ops) के लिए, System Integrity Protection disabled होना चाहिए — नीचे imsg private API सक्षम करना देखें। Basic text और media send/receive इसके बिना काम करते हैं।
SSH wrapper sends fail with AppleEvents -1743
remote-SSH setup chats पढ़ सकता है, channels status --probe pass कर सकता है, और inbound messages process कर सकता है, जबकि outbound sends फिर भी AppleEvents authorization error के साथ fail हो सकते हैं:
Not authorized to send Apple events to Messages. (-1743)signed-in Mac user's TCC database या System Settings > Privacy & Security > Automation देखें। यदि Automation entry imsg या local shell process के बजाय /usr/libexec/sshd-keygen-wrapper के लिए record है, तो macOS उस SSH server-side client के लिए usable Messages toggle expose नहीं कर सकता:
kTCCServiceAppleEvents | /usr/libexec/sshd-keygen-wrapper | auth_value=0 | com.apple.MobileSMSउस स्थिति में, tccutil reset AppleEvents दोहराना या उसी SSH wrapper के माध्यम से imsg send फिर से चलाना fail होता रह सकता है क्योंकि जिस process context को Messages Automation चाहिए वह SSH wrapper है, कोई ऐसा app नहीं जिसे UI grant कर सके।
इसके बजाय समर्थित imsg process contexts में से किसी एक का उपयोग करें:
- Gateway, या कम से कम
imsgbridge, logged-in Messages user's local session में चलाएँ। - उसी session से Full Disk Access और Automation grant करने के बाद उस user के लिए LaunchAgent के साथ Gateway शुरू करें।
- यदि आप two-user SSH topology रखते हैं, तो channel enable करने से पहले verify करें कि exact wrapper के माध्यम से real outbound
imsg sendसफल होता है। यदि इसे Automation grant नहीं किया जा सकता, तो sends के लिए SSH wrapper पर निर्भर रहने के बजाय single-userimsgsetup में reconfigure करें।
imsg private API सक्षम करना
imsg दो operational modes में ship होता है:
- Basic mode (default, SIP changes की आवश्यकता नहीं):
sendके माध्यम से outbound text और media, inbound watch/history, chat list। freshbrew install steipete/tap/imsgऔर ऊपर दी गई standard macOS permissions से out of the box यही मिलता है। - Private API mode:
imsg, internalIMCorefunctions call करने के लिएMessages.appमें helper dylib inject करता है। यहीreact,edit,unsend,reply(threaded),sendWithEffect,renameGroup,setGroupIcon,addParticipant,removeParticipant,leaveGroup, साथ ही typing indicators और read receipts unlock करता है।
इस channel page में documented advanced action surface तक पहुँचने के लिए आपको Private API mode चाहिए। imsg README requirement के बारे में स्पष्ट है:
read,typing,launch, bridge-backed rich send, message mutation, और chat management जैसी advanced features opt-in हैं। उन्हें SIP disabled होना औरMessages.appमें helper dylib inject होना आवश्यक है। SIP enabled होने परimsg launchinject करने से मना करता है।
helper-injection technique Messages private APIs तक पहुँचने के लिए imsg की अपनी dylib का उपयोग करती है। OpenClaw iMessage path में कोई third-party server या BlueBubbles runtime नहीं है।
Setup
-
Messages.app चलाने वाले Mac पर
imsginstall (या upgrade) करें:bash brew install steipete/tap/imsgimsg --versionimsg status --jsonimsg status --jsonoutputbridge_version,rpc_methods, और per-methodselectorsreport करता है ताकि start करने से पहले आप देख सकें कि current build क्या support करता है। -
System Integrity Protection, और (modern macOS पर) Library Validation disable करें। Apple-signed
Messages.appमें non-Apple helper dylib inject करने के लिए SIP off और library validation relaxed होना चाहिए। Recovery-mode SIP step macOS-version-specific है:- macOS 10.13-10.15 (Sierra-Catalina): Terminal के माध्यम से Library Validation disable करें, Recovery Mode में reboot करें,
csrutil disableचलाएँ, restart करें। - macOS 11+ (Big Sur और बाद के), Intel: Recovery Mode (या Internet Recovery),
csrutil disable, restart। - macOS 11+, Apple Silicon: Recovery में enter करने के लिए power-button startup sequence; recent macOS versions पर Continue click करते समय Left Shift key दबाए रखें, फिर
csrutil disable। Virtual-machine setups अलग flow follow करते हैं, इसलिए पहले VM snapshot लें।
macOS 11 और बाद में, केवल
csrutil disableआमतौर पर पर्याप्त नहीं होता। Apple अभी भीMessages.appके against library validation enforce करता है क्योंकि वह platform binary है, इसलिए adhoc-signed helper reject हो जाता है (Library Validation failed: ... platform binary, but mapped file is not) भले ही SIP off हो। SIP disable करने के बाद, library validation भी disable करें और reboot करें:bash sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool truemacOS 26 (Tahoe), 26.5.1 पर verified: SIP off plus ऊपर दिया गया
DisableLibraryValidationcommand 26.0 से 26.5.x तक helper inject करने के लिए पर्याप्त है। कोई boot-args required नहीं हैं। plist निर्णायक factor है और Tahoe पर injection fail होने पर सबसे common missing step है:- plist के साथ:
imsg launchinject करता है औरimsg statusadvanced_features: truereport करता है। - plist के बिना (SIP off होने पर भी):
imsg launchFailed to launch: Timeout waiting for Messages.app to initializeके साथ fail होता है। AMFI adhoc helper को load पर reject करता है, इसलिए bridge कभी ready नहीं होता और launch timeout हो जाता है। वह timeout वह symptom है जिससे Tahoe पर अधिकांश लोग टकराते हैं, और fix ऊपर वाला plist है, कुछ अधिक drastic नहीं।
macOS 26.5.1 (Apple Silicon) पर controlled before/after के साथ इसकी पुष्टि की गई: plist के साथ, dylib
Messages.appमें map हो जाती है और bridge up हो जाता है; plist remove करके reboot करें, औरimsg launchऊपर वाला timeout failure produce करता है, dylib mapped नहीं होती।यदि macOS अपग्रेड के बाद
imsg launchइंजेक्शन या विशिष्टselectorsfalse लौटाने लगें, तो आमतौर पर यही गेट कारण होता है। यह मानने से पहले कि SIP चरण ही विफल हुआ, अपनी SIP और library-validation स्थिति जांचें। यदि ये सेटिंग सही हैं और bridge फिर भी inject नहीं कर पा रहा है, तोimsg status --jsonके साथimsg launchआउटपुट इकट्ठा करें और अतिरिक्त सिस्टम-व्यापी सुरक्षा नियंत्रणों को कमजोर करने के बजाय इसेimsgप्रोजेक्ट को रिपोर्ट करें।imsg launchचलाने से पहले SIP अक्षम करने के लिए अपने Mac के लिए Apple के Recovery-mode flow का पालन करें। - macOS 10.13-10.15 (Sierra-Catalina): Terminal के माध्यम से Library Validation disable करें, Recovery Mode में reboot करें,
-
helper inject करें। SIP अक्षम होने और Messages.app में sign in होने पर:
bash imsg launchSIP अभी भी सक्षम होने पर
imsg launchinject करने से इनकार करता है, इसलिए यह इस बात की पुष्टि भी करता है कि चरण 2 लागू हो गया। -
OpenClaw से bridge सत्यापित करें:
bash openclaw channels status --probeiMessage entry को
worksरिपोर्ट करना चाहिए, औरimsg status --json | jq '.selectors'मेंretractMessagePart: trueके साथ वे edit / typing / read selectors दिखने चाहिए जिन्हें आपका macOS build expose करता है।actions.tsमें OpenClaw Plugin की per-method gating केवल उन्हीं actions को advertise करती है जिनका underlying selectortrueहै, इसलिए agent की tool list में दिखने वाला action surface वही दर्शाता है जो bridge वास्तव में इस host पर कर सकता है।
यदि openclaw channels status --probe channel को works रिपोर्ट करता है लेकिन विशिष्ट actions dispatch time पर "iMessage <action> requires the imsg private API bridge" throw करते हैं, तो imsg launch फिर चलाएं — helper बाहर हो सकता है (Messages.app restart, OS update, आदि) और cached available: true status अगली probe refresh होने तक actions को advertise करता रहेगा।
जब आप SIP अक्षम नहीं कर सकते
यदि SIP-disabled आपके threat model के लिए स्वीकार्य नहीं है:
imsgbasic mode पर fallback करता है — केवल text + media + receive।- OpenClaw Plugin अभी भी text/media send और inbound monitoring advertise करता है; यह बस action surface से
react,edit,unsend,reply,sendWithEffect, और group ops छिपा देता है (per-method capability gate के अनुसार)। - आप iMessage workload के लिए SIP off वाला एक अलग non-Apple-Silicon Mac (या dedicated bot Mac) चला सकते हैं, जबकि अपने primary devices पर SIP enabled रख सकते हैं। नीचे Dedicated bot macOS user (separate iMessage identity) देखें।
Access control और routing
DM policy
channels.imessage.dmPolicy direct messages नियंत्रित करता है:
pairing(default)allowlistopen(allowFromमें"*"शामिल होना आवश्यक)disabled
Allowlist field: channels.imessage.allowFrom.
Allowlist entries को senders की पहचान करनी होगी: handles या static sender access groups (accessGroup:<name>)। chat_id:*, chat_guid:*, या chat_identifier:* जैसे chat targets के लिए channels.imessage.groupAllowFrom का उपयोग करें; numeric chat_id registry keys के लिए channels.imessage.groups का उपयोग करें।
Group policy + mentions
channels.imessage.groupPolicy group handling नियंत्रित करता है:
allowlist(configured होने पर default)opendisabled
Group sender allowlist: channels.imessage.groupAllowFrom.
groupAllowFrom entries static sender access groups (accessGroup:<name>) को भी reference कर सकती हैं।
Runtime fallback: यदि groupAllowFrom unset है, तो iMessage group sender checks allowFrom का उपयोग करते हैं; जब DM और group admission अलग होने चाहिए, तो groupAllowFrom set करें।
Runtime note: यदि channels.imessage पूरी तरह missing है, तो runtime groupPolicy="allowlist" पर fallback करता है और warning log करता है (भले ही channels.defaults.groupPolicy set हो)।
Groups के लिए mention gating:
- iMessage में native mention metadata नहीं है
- mention detection regex patterns (
agents.list[].groupChat.mentionPatterns, fallbackmessages.groupChat.mentionPatterns) का उपयोग करता है - configured patterns न होने पर, mention gating enforce नहीं की जा सकती
Authorized senders से control commands groups में mention gating bypass कर सकते हैं।
Per-group systemPrompt:
channels.imessage.groups.* के अंतर्गत प्रत्येक entry optional systemPrompt string स्वीकार करती है। यह value उस group में message handle करने वाले हर turn पर agent के system prompt में inject की जाती है। Resolution channels.whatsapp.groups द्वारा उपयोग किए जाने वाले per-group prompt resolution को mirror करता है:
- Group-specific system prompt (
groups["<chat_id>"].systemPrompt): तब उपयोग होता है जब specific group entry map में मौजूद हो और उसकीsystemPromptkey defined हो। यदिsystemPromptempty string ("") है, तो wildcard suppress हो जाता है और उस group पर कोई system prompt apply नहीं होता। - Group wildcard system prompt (
groups["*"].systemPrompt): तब उपयोग होता है जब specific group entry map से पूरी तरह absent हो, या वह मौजूद हो लेकिन कोईsystemPromptkey define न करती हो।
{ channels: { imessage: { groupPolicy: "allowlist", groupAllowFrom: ["+15555550123"], groups: { "*": { systemPrompt: "Use British spelling." }, "8421": { requireMention: true, systemPrompt: "This is the on-call rotation chat. Keep replies under 3 sentences.", }, "9907": { // explicit suppression: the wildcard "Use British spelling." does not apply here systemPrompt: "", }, }, }, },}Per-group prompts केवल group messages पर apply होते हैं — इस channel में direct messages अप्रभावित रहते हैं।
Sessions and deterministic replies
- DMs direct routing का उपयोग करते हैं; groups group routing का उपयोग करते हैं।
- default
session.dmScope=mainके साथ, iMessage DMs agent main session में collapse हो जाते हैं। - Group sessions isolated होते हैं (
agent:<agentId>:imessage:group:<chat_id>)। - Replies originating channel/target metadata का उपयोग करके iMessage पर वापस route होते हैं।
Group-जैसा thread behavior:
कुछ multi-participant iMessage threads is_group=false के साथ आ सकते हैं।
यदि वह chat_id explicitly channels.imessage.groups के अंतर्गत configured है, तो OpenClaw उसे group traffic मानता है (group gating + group session isolation)।
ACP conversation bindings
Legacy iMessage chats को ACP sessions से भी bind किया जा सकता है।
Fast operator flow:
- DM या allowed group chat के अंदर
/acp spawn codex --bind hereचलाएं। - उसी iMessage conversation में future messages spawned ACP session तक route होंगे।
/newऔर/resetउसी bound ACP session को उसी जगह reset करते हैं।/acp closeACP session बंद करता है और binding हटाता है।
Configured persistent bindings top-level bindings[] entries के माध्यम से supported हैं, जिनमें type: "acp" और match.channel: "imessage" होता है।
match.peer.id इसका उपयोग कर सकता है:
- normalized DM handle जैसे
+15555550123याuser@example.com chat_id:<id>(stable group bindings के लिए recommended)chat_guid:<guid>chat_identifier:<identifier>
Example:
{ 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" }, }, ],}Shared ACP binding behavior के लिए ACP Agents देखें।
Deployment patterns
Dedicated bot macOS user (separate iMessage identity)
Dedicated Apple ID और macOS user का उपयोग करें ताकि bot traffic आपकी personal Messages profile से isolated रहे।
Typical flow:
- Dedicated macOS user बनाएं/sign in करें।
- उस user में bot Apple ID के साथ Messages में sign in करें।
- उस user में
imsginstall करें। - SSH wrapper बनाएं ताकि OpenClaw उस user context में
imsgचला सके। channels.imessage.accounts.<id>.cliPathऔर.dbPathको उस user profile की ओर point करें।
First run में उस bot user session में GUI approvals (Automation + Full Disk Access) की आवश्यकता हो सकती है।
Remote Mac over Tailscale (example)
Common topology:
- gateway Linux/VM पर चलता है
- iMessage +
imsgआपकी tailnet में Mac पर चलता है cliPathwrapper SSH का उपयोग करकेimsgचलाता हैremoteHostSCP attachment fetches enable करता है
Example:
{ 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 bashexec ssh -T bot@mac-mini.tailnet-1234.ts.net imsg "$@"SSH keys का उपयोग करें ताकि SSH और SCP दोनों non-interactive हों।
सुनिश्चित करें कि host key पहले trusted है (उदाहरण के लिए ssh bot@mac-mini.tailnet-1234.ts.net) ताकि known_hosts populated हो।
Multi-account pattern
iMessage channels.imessage.accounts के अंतर्गत per-account config support करता है।
प्रत्येक account cliPath, dbPath, allowFrom, groupPolicy, mediaMaxMb, history settings, और attachment root allowlists जैसे fields override कर सकता है।
Direct-message history
channels.imessage.dmHistoryLimit set करें ताकि नई direct-message sessions को उस conversation की हाल की decoded imsg history से seed किया जा सके। Per-sender overrides के लिए channels.imessage.dms["<sender>"].historyLimit का उपयोग करें, जिसमें किसी sender के लिए history disable करने हेतु 0 भी शामिल है।
iMessage DM history मांग पर imsg से fetch की जाती है। dmHistoryLimit unset छोड़ने से global DM history seeding disable हो जाती है, लेकिन positive per-sender channels.imessage.dms["<sender>"].historyLimit फिर भी उस sender के लिए seeding enable करता है।
Media, chunking, और delivery targets
अटैचमेंट और मीडिया
- इनबाउंड अटैचमेंट इनजेशन डिफ़ॉल्ट रूप से बंद है — फ़ोटो, वॉइस मेमो, वीडियो और अन्य अटैचमेंट एजेंट को भेजने के लिए
channels.imessage.includeAttachments: trueसेट करें। इसके बंद रहने पर, केवल-अटैचमेंट वाले iMessages एजेंट तक पहुँचने से पहले हटा दिए जाते हैं और हो सकता है कि कोई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.chunkModelength(डिफ़ॉल्ट)newline(पहले-पैराग्राफ विभाजन)
एड्रेसिंग फ़ॉर्मैट
पसंदीदा स्पष्ट लक्ष्य:
chat_id:123(स्थिर रूटिंग के लिए अनुशंसित)chat_guid:...chat_identifier:...
हैंडल लक्ष्य भी समर्थित हैं:
imessage:+1555...sms:+1555...user@example.com
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 टैपबैक जोड़ें/हटाएँ (
messageId,emoji,remove)। समर्थित टैपबैक love, like, dislike, laugh, emphasize और question से मैप होते हैं। - reply: किसी मौजूदा संदेश पर थ्रेडेड जवाब भेजें (
messageId,textयाmessage, साथ मेंchatGuid,chatId,chatIdentifier, याto)। - sendWithEffect: iMessage इफ़ेक्ट के साथ टेक्स्ट भेजें (
textयाmessage,effectयाeffectId)। - edit: समर्थित macOS/निजी API संस्करणों पर भेजा गया संदेश संपादित करें (
messageId,textयाnewText)। - unsend: समर्थित macOS/निजी API संस्करणों पर भेजा गया संदेश वापस लें (
messageId)। - upload-file: मीडिया/फ़ाइलें भेजें (
bufferbase64 के रूप में या hydratedmedia/path/filePath,filename, वैकल्पिकasVoice)। लेगेसी alias:sendAttachment। - renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup: जब मौजूदा लक्ष्य कोई समूह बातचीत हो, तब समूह चैट प्रबंधित करें।
संदेश ID
इनबाउंड iMessage संदर्भ उपलब्ध होने पर छोटे MessageSid मान और पूर्ण संदेश GUID, दोनों शामिल करता है। छोटे ID हाल की SQLite-समर्थित reply cache तक सीमित होते हैं और उपयोग से पहले मौजूदा चैट के विरुद्ध जाँचे जाते हैं। यदि कोई छोटा ID समाप्त हो गया है या किसी दूसरी चैट से संबंधित है, तो पूर्ण MessageSidFull के साथ फिर प्रयास करें।
क्षमता पहचान
OpenClaw निजी API कार्रवाइयाँ केवल तब छिपाता है जब cached probe status कहता है कि bridge उपलब्ध नहीं है। यदि status अज्ञात है, तो कार्रवाइयाँ दिखाई देती रहती हैं और dispatch lazily probe करता है, ताकि पहली कार्रवाई imsg launch के बाद अलग manual status refresh के बिना सफल हो सके।
Read receipts और typing
जब private API bridge चालू हो, तो स्वीकृत इनबाउंड चैट read के रूप में mark की जाती हैं और direct chats में turn स्वीकार होते ही typing bubble दिखता है, जबकि एजेंट context तैयार करता और generate करता है। read-marking बंद करने के लिए:
{ channels: { imessage: { sendReadReceipts: false, }, },}पुराने imsg builds जो per-method capability list से पहले के हैं, typing/read को चुपचाप gate off कर देंगे; OpenClaw हर restart पर एक बार warning log करता है ताकि missing receipt का कारण पहचाना जा सके।
इनबाउंड टैपबैक
OpenClaw iMessage टैपबैक subscribe करता है और स्वीकृत reactions को सामान्य message text के बजाय system events के रूप में route करता है, इसलिए user tapback सामान्य reply loop trigger नहीं करता।
Notification mode channels.imessage.reactionNotifications से नियंत्रित होता है:
"own"(डिफ़ॉल्ट): केवल तब notify करें जब user bot-authored messages पर react करें।"all": authorized senders से सभी inbound tapbacks के लिए notify करें।"off": inbound tapbacks अनदेखा करें।
Per-account overrides channels.imessage.accounts.<id>.reactionNotifications का उपयोग करते हैं।
Approval reactions (👍 / 👎)
जब approvals.exec.enabled या approvals.plugin.enabled true हो और request iMessage तक route हो, तो gateway native approval prompt deliver करता है और उसे resolve करने के लिए tapback स्वीकार करता है:
👍(Like tapback) →allow-once👎(Dislike tapback) →denyallow-alwaysmanual fallback बना रहता है: regular reply के रूप में/approve <id> allow-alwaysभेजें।
Reaction handling के लिए reacting user का handle explicit approver होना आवश्यक है। approver list channels.imessage.allowFrom (या channels.imessage.accounts.<id>.allowFrom) से पढ़ी जाती है; user का phone number E.164 form में या उनका Apple ID email जोड़ें। wildcard entry "*" मान्य है, लेकिन किसी भी sender को approve करने की अनुमति देती है। reaction shortcut जानबूझकर reactionNotifications, dmPolicy और groupAllowFrom को bypass करता है क्योंकि explicit-approver allowlist ही approval resolution के लिए मायने रखने वाला एकमात्र gate है।
इस रिलीज़ में व्यवहार परिवर्तन: जब channels.imessage.allowFrom खाली नहीं है, तो /approve <id> <decision> text command अब उसी approver list के विरुद्ध authorize होती है (विस्तृत DM allowlist के विरुद्ध नहीं)। DM allowlist पर permitted लेकिन allowFrom में नहीं मौजूद senders को स्पष्ट denial मिलेगा। पिछले behavior को बनाए रखने के लिए हर उस operator को allowFrom में जोड़ें जिसे /approve के ज़रिए (और reactions के ज़रिए) approve करने में सक्षम होना चाहिए। जब allowFrom खाली है, legacy "same-chat fallback" प्रभाव में रहता है और /approve उस किसी भी व्यक्ति को authorize करना जारी रखता है जिसे DM allowlist permit करती है।
Operator notes:
- reaction binding memory में (approval expiry से matched TTL के साथ) और gateway के persistent keyed store में, दोनों जगह store होती है, इसलिए gateway restart के थोड़ी देर बाद आने वाला tapback भी approval resolve कर देता है।
- Cross-device
is_from_me=truetapbacks (paired Apple device पर operator की अपनी reaction) जानबूझकर ignore किए जाते हैं ताकि bot self-approve न कर सके। - Legacy text-style tapbacks (
Liked "…"बहुत पुराने Apple clients से plain text) approvals resolve नहीं कर सकते क्योंकि वे message GUID नहीं रखते; reaction resolution के लिए structured tapback metadata आवश्यक है जिसे current macOS / iOS clients emit करते हैं।
Config writes
iMessage डिफ़ॉल्ट रूप से channel-initiated config writes की अनुमति देता है (/config set|unset के लिए जब commands.config: true हो)।
बंद करें:
{ channels: { imessage: { configWrites: false, }, },}Split-send DMs को coalesce करना (एक composition में command + URL)
जब user एक command और URL साथ में type करता है — जैसे Dump https://example.com/article — Apple का Messages app send को दो अलग-अलग chat.db rows में split करता है:
- एक text message (
"Dump")। - OG-preview images को attachments के रूप में रखने वाला URL-preview balloon (
"https://...")।
ज़्यादातर setups पर ये दो rows OpenClaw तक ~0.8-2.0 s के अंतर से पहुँचती हैं। Coalescing के बिना, agent को turn 1 पर केवल command मिलती है, वह reply करता है (अक्सर "मुझे URL भेजें"), और URL केवल turn 2 पर दिखता है — तब तक command context पहले ही खो चुका होता है। यह Apple की send pipeline है, OpenClaw या imsg द्वारा जोड़ी गई कोई चीज़ नहीं।
channels.imessage.coalesceSameSenderDms किसी DM को consecutive same-sender rows buffer करने में opt करता है। जब imsg source rows में से किसी एक पर structural URL-preview marker balloon_bundle_id: "com.apple.messages.URLBalloonProvider" expose करता है, तो OpenClaw केवल उस वास्तविक split-send को merge करता है और अन्य buffered rows को separate turns के रूप में रखता है। पुराने imsg builds पर, जो कोई balloon metadata emit नहीं करते, OpenClaw split-send और separate sends में अंतर नहीं बता सकता, इसलिए वह bucket merge करने पर fallback करता है। इससे Dump <url> split-sends को दो turns में regress करने के बजाय pre-metadata behavior सुरक्षित रहता है। Group chats per-message dispatch करना जारी रखते हैं ताकि multi-user turn structure सुरक्षित रहे।
कब सक्षम करें
सक्षम करें जब:
- आप ऐसे skills ship करते हैं जो एक message में
command + payloadकी अपेक्षा रखते हैं (dump, paste, save, queue, आदि)। - आपके users commands के साथ URLs paste करते हैं।
- आप जोड़ी गई DM turn latency स्वीकार कर सकते हैं (नीचे देखें)।
बंद रहने दें जब:
- आपको single-word DM triggers के लिए minimum command latency चाहिए।
- आपके सभी flows payload follow-ups के बिना one-shot commands हैं।
सक्षम करना
{ channels: { imessage: { coalesceSameSenderDms: true, // opt in (default: false) }, },}Flag on होने और कोई explicit messages.inbound.byChannel.imessage या global messages.inbound.debounceMs न होने पर, debounce window 7000 ms तक widen हो जाती है (legacy default 0 ms है — कोई debouncing नहीं)। Wider window आवश्यक है क्योंकि Apple की URL-preview split-send cadence कई seconds तक stretch हो सकती है, जब Messages.app preview row emit करता है।
Window खुद tune करने के लिए:
{ messages: { inbound: { byChannel: { // 7000 ms covers observed Messages.app URL-preview delays. imessage: 7000, }, }, },}Trade-offs
- सटीक merging के लिए current
imsgpayload metadata चाहिए। जब URL row मेंballoon_bundle_idशामिल हो, तो केवल वही वास्तविक split-send merge होता है और अन्य buffered rows separate रहते हैं। पुरानेimsgbuilds पर, जो कोई balloon metadata expose नहीं करते, OpenClaw buffered bucket merge करने पर fallback करता है ताकिDump <url>split-sends दो turns में regress न हों (interim back-compat, जबimsgupstream split-sends coalesce करेगा तब हटाया जाएगा)। - DM messages के लिए जोड़ी गई latency। Flag on होने पर, हर DM (standalone control commands और single-text follow-ups सहित) dispatch होने से पहले debounce window तक wait करता है, इस संभावना में कि URL-preview row आने वाली है। Group-chat messages instant dispatch रखते हैं।
- Merged output bounded है। Merged text explicit
…[truncated]marker के साथ 4000 chars पर cap होता है; attachments 20 पर cap होते हैं; source entries 10 पर cap होती हैं (उससे आगे first-plus-latest retained)। हर source GUID downstream telemetry के लिएcoalescedMessageGuidsमें track होता है। - केवल DM। Group chats per-message dispatch पर fall through करते हैं ताकि कई लोग typing कर रहे हों तब bot responsive रहे।
- Opt-in, per-channel। अन्य channels (Telegram, WhatsApp, Slack, …) अप्रभावित हैं। Legacy BlueBubbles configs जो
channels.bluebubbles.coalesceSameSenderDmsset करते हैं, उन्हें वह valuechannels.imessage.coalesceSameSenderDmsमें migrate करनी चाहिए।
Scenarios और agent क्या देखता है
"फ़्लैग चालू" स्तंभ उस imsg बिल्ड पर व्यवहार दिखाता है जो balloon_bundle_id उत्सर्जित करता है। पुराने imsg बिल्ड पर, जो कोई balloon मेटाडेटा बिल्कुल उत्सर्जित नहीं करते, नीचे "दो टर्न" / "N टर्न" चिह्नित पंक्तियां इसके बजाय legacy merge (एक टर्न) पर लौटती हैं: OpenClaw split-send को अलग-अलग sends से संरचनात्मक रूप से अलग नहीं बता सकता, इसलिए यह pre-metadata merge को सुरक्षित रखता है। बिल्ड के balloon मेटाडेटा उत्सर्जित करने के बाद सटीक अलगाव सक्रिय होता है।
| उपयोगकर्ता लिखता है | chat.db उत्पन्न करता है |
फ़्लैग बंद (डिफ़ॉल्ट) | फ़्लैग चालू + विंडो (imsg balloon मेटाडेटा उत्सर्जित करता है) |
|---|---|---|---|
Dump https://example.com (एक send) |
2 पंक्तियां ~1 सेकंड के अंतर पर | दो agent टर्न: केवल "Dump", फिर URL | एक टर्न: मर्ज किया गया टेक्स्ट Dump https://example.com |
Save this 📎image.jpg caption (अटैचमेंट + टेक्स्ट) |
URL balloon मेटाडेटा के बिना 2 पंक्तियां | दो टर्न | मेटाडेटा देखे जाने के बाद दो टर्न; पुराने/pre-latch मेटाडेटा-रहित सेशन पर एक मर्ज किया गया टर्न |
/status (स्वतंत्र command) |
1 पंक्ति | तुरंत dispatch | विंडो तक प्रतीक्षा करें, फिर dispatch करें |
| URL अकेले पेस्ट किया गया | 1 पंक्ति | तुरंत dispatch | विंडो तक प्रतीक्षा करें, फिर dispatch करें |
| टेक्स्ट + URL जानबूझकर दो अलग संदेशों के रूप में, मिनटों के अंतर पर भेजे गए | विंडो के बाहर 2 पंक्तियां | दो टर्न | दो टर्न (उनके बीच विंडो समाप्त हो जाती है) |
| तेज़ flood (विंडो के भीतर >10 छोटे DMs) | URL balloon मेटाडेटा के बिना N पंक्तियां | N टर्न | मेटाडेटा देखे जाने के बाद N टर्न; पुराने/pre-latch मेटाडेटा-रहित सेशन पर एक bounded मर्ज किया गया टर्न |
| समूह चैट में दो लोग टाइप कर रहे हैं | M senders से N पंक्तियां | M+ टर्न (हर sender bucket के लिए एक) | M+ टर्न — समूह चैट coalesce नहीं की जातीं |
bridge या gateway restart के बाद inbound recovery
iMessage उन संदेशों को recover करता है जो Gateway बंद होने के दौरान छूट गए थे, और साथ ही उस पुराने "backlog bomb" को दबाता है जिसे Apple Push recovery के बाद flush कर सकता है। डिफ़ॉल्ट व्यवहार हमेशा चालू रहता है, और inbound dedupe पर बना है।
- Replay dedupe। हर dispatched inbound message को persistent Plugin state (
imessage.inbound-dedupe) में उसके Apple GUID द्वारा रिकॉर्ड किया जाता है, ingestion पर claim किया जाता है और handling के बाद commit किया जाता है (transient failure पर release किया जाता है ताकि retry हो सके)। जो भी पहले ही handle हो चुका है उसे दोबारा dispatch करने के बजाय drop कर दिया जाता है। इसी से recovery per-message bookkeeping के बिना आक्रामक replay कर पाती है। - Downtime recovery। startup पर monitor अंतिम dispatched
chat.dbrowid (एक persisted per-account cursor) याद रखता है और उसेimsg watch.subscribeकोsince_rowidके रूप में पास करता है, ताकि Gateway बंद रहने के दौरान आई rows को imsg replay करे, फिर live tail करे। Replay सबसे हालिया rows और ~2 घंटे तक पुराने संदेशों तक bounded है, और dedupe पहले से handle हो चुकी किसी भी चीज़ को drop कर देता है। - Stale-backlog age fence। startup boundary से ऊपर की rows वास्तव में live होती हैं; जिसकी send date उसके arrival से ~15 मिनट से अधिक पुरानी हो, वह Push-flush backlog है और suppressed होती है। Replayed rows (boundary पर या उससे नीचे) इसके बजाय wider recovery window का उपयोग करती हैं, ताकि हाल ही में छूटा message deliver हो जबकि बहुत पुराना इतिहास न हो।
Recovery local और remote दोनों cliPath setups पर काम करती है, क्योंकि since_rowid replay उसी imsg RPC connection पर चलता है। अंतर window का है: जब Gateway chat.db पढ़ सकता है (local), तो यह startup rowid boundary anchor करता है, replay span cap करता है, और कुछ घंटे तक पुराने छूटे messages deliver करता है। remote SSH cliPath पर यह database नहीं पढ़ सकता, इसलिए replay uncapped होता है और हर row live age fence का उपयोग करती है — यह फिर भी हाल ही में छूटे messages recover करता है और पुराना backlog suppress करता है, बस संकरी live window के साथ। wider recovery window के लिए Gateway को Messages Mac पर चलाएं।
Operator-visible signal
Suppressed backlog को default level पर log किया जाता है, कभी silently drop नहीं किया जाता (recovery flag दिखाता है कि कौन सी window लागू हुई):
imessage: suppressed stale inbound backlog account=<id> sent=<iso> recovery=<bool> (<N> suppressed since start)Migration
channels.imessage.catchup.* deprecated है — downtime recovery अब automatic है और नए setups के लिए किसी config की जरूरत नहीं है। catchup.enabled: true वाले मौजूदा configs recovery replay window के लिए compatibility profile के रूप में honored रहते हैं। Disabled catchup blocks (enabled: false या कोई enabled: true नहीं) retired हैं; openclaw doctor --fix उन्हें हटाता है।
Troubleshooting
imsg not found or RPC unsupported
binary और RPC support validate करें:
imsg rpc --helpimsg status --jsonopenclaw channels status --probeअगर probe RPC unsupported report करता है, तो imsg update करें। अगर private API actions उपलब्ध नहीं हैं, तो logged-in macOS user session में imsg launch चलाएं और फिर से probe करें। अगर Gateway macOS पर नहीं चल रहा है, तो default local imsg path के बजाय ऊपर दिया गया Remote Mac over SSH setup उपयोग करें।
Messages send but inbound iMessages do not arrive
पहले साबित करें कि message local Mac तक पहुंचा या नहीं। अगर chat.db नहीं बदलता, तो OpenClaw message receive नहीं कर सकता, भले ही imsg status --json healthy bridge report करे।
imsg chats --limit 10 --jsonimsg watch --chat-id <chat-id> --jsonsqlite3 ~/Library/Messages/chat.db \"select datetime(max(date)/1000000000 + 978307200, 'unixepoch', 'localtime'), max(ROWID) from message;"अगर phone-sent messages कोई नई rows नहीं बनाते, तो OpenClaw config बदलने से पहले macOS Messages और Apple Push layer repair करें। एक one-shot service refresh अक्सर पर्याप्त होता है:
launchctl kickstart -k system/com.apple.apsdlaunchctl kickstart -k gui/$(id -u)/com.apple.CommCenterlaunchctl kickstart -k gui/$(id -u)/com.apple.identityservicesdlaunchctl kickstart -k gui/$(id -u)/com.apple.imagentimsg launchopenclaw gateway restartphone से एक नया iMessage भेजें और OpenClaw sessions debug करने से पहले नई chat.db row या imsg watch event confirm करें। इसे periodic bridge-relaunch loop के रूप में न चलाएं; active work के दौरान बार-बार imsg launch और Gateway restarts deliveries interrupt कर सकते हैं और in-flight channel runs को strand कर सकते हैं।
Gateway is not running on macOS
default cliPath: "imsg" को Messages में signed in Mac पर चलना चाहिए। Linux या Windows पर, channels.imessage.cliPath को ऐसे wrapper script पर set करें जो उस Mac पर SSH करे और imsg "$@" चलाए।
#!/usr/bin/env bashexec ssh -T messages-mac imsg "$@"फिर चलाएं:
openclaw channels status --probe --channel imessageDMs are ignored
जांचें:
channels.imessage.dmPolicychannels.imessage.allowFrom- pairing approvals (
openclaw pairing list imessage)
Group messages are ignored
जांचें:
channels.imessage.groupPolicychannels.imessage.groupAllowFromchannels.imessage.groupsallowlist behavior- mention pattern configuration (
agents.list[].groupChat.mentionPatterns)
Remote attachments fail
जांचें:
channels.imessage.remoteHostchannels.imessage.remoteAttachmentRoots- Gateway host से SSH/SCP key auth
- Gateway host पर
~/.ssh/known_hostsमें host key मौजूद है - Messages चलाने वाले Mac पर remote path readability
macOS permission prompts were missed
उसी user/session context में interactive GUI terminal में फिर से चलाएं और prompts approve करें:
imsg chats --limit 1imsg send <handle> "test"Confirm करें कि OpenClaw/imsg चलाने वाले process context के लिए Full Disk Access + Automation granted हैं।
Configuration reference pointers
Related
- Channels Overview — सभी supported channels
- BlueBubbles removal and the imsg iMessage path — announcement और migration summary
- Coming from BlueBubbles — config translation table और step-by-step cutover
- Pairing — DM authentication और pairing flow
- Groups — group chat behavior और mention gating
- Channel Routing — messages के लिए session routing
- Security — access model और hardening