Mainstream messaging

iMessage

स्थिति: native external CLI integration। Gateway imsg rpc spawn करता है और stdio पर JSON-RPC के माध्यम से communicate करता है (अलग daemon/port नहीं)। उन्नत actions के लिए imsg launch और सफल private API probe आवश्यक है।

त्वरित setup

Local Mac (fast path)

  • Install and verify imsg

    bash
    brew install steipete/tap/imsgimsg rpc --helpimsg launchopenclaw channels status --probe
  • Configure OpenClaw

    json5
    {channels: {imessage: {enabled: true,cliPath: "/usr/local/bin/imsg",dbPath: "/Users/user/Library/Messages/chat.db",},},}
  • Start gateway

    bash
    openclaw gateway
  • Approve first DM pairing (default dmPolicy)

    bash
    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 चलाता है।

    bash
    #!/usr/bin/env bashexec ssh -T gateway-host imsg "$@"

    attachments enabled होने पर अनुशंसित config:

    json5
    {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 हो सकते हैं:

    text
    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 नहीं कर सकता:

    text
    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, या कम से कम imsg bridge, 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-user imsg setup में reconfigure करें।

    imsg private API सक्षम करना

    imsg दो operational modes में ship होता है:

    • Basic mode (default, SIP changes की आवश्यकता नहीं): send के माध्यम से outbound text और media, inbound watch/history, chat list। fresh brew install steipete/tap/imsg और ऊपर दी गई standard macOS permissions से out of the box यही मिलता है।
    • Private API mode: imsg, internal IMCore functions 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 launch inject करने से मना करता है।

    helper-injection technique Messages private APIs तक पहुँचने के लिए imsg की अपनी dylib का उपयोग करती है। OpenClaw iMessage path में कोई third-party server या BlueBubbles runtime नहीं है।

    Setup

    1. Messages.app चलाने वाले Mac पर imsg install (या upgrade) करें:

      bash
      brew install steipete/tap/imsgimsg --versionimsg status --json

      imsg status --json output bridge_version, rpc_methods, और per-method selectors report करता है ताकि start करने से पहले आप देख सकें कि current build क्या support करता है।

    2. 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 true

      macOS 26 (Tahoe), 26.5.1 पर verified: SIP off plus ऊपर दिया गया DisableLibraryValidation command 26.0 से 26.5.x तक helper inject करने के लिए पर्याप्त है। कोई boot-args required नहीं हैं। plist निर्णायक factor है और Tahoe पर injection fail होने पर सबसे common missing step है:

      • plist के साथ: imsg launch inject करता है और imsg status advanced_features: true report करता है।
      • plist के बिना (SIP off होने पर भी): imsg launch Failed 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 इंजेक्शन या विशिष्ट selectors false लौटाने लगें, तो आमतौर पर यही गेट कारण होता है। यह मानने से पहले कि SIP चरण ही विफल हुआ, अपनी SIP और library-validation स्थिति जांचें। यदि ये सेटिंग सही हैं और bridge फिर भी inject नहीं कर पा रहा है, तो imsg status --json के साथ imsg launch आउटपुट इकट्ठा करें और अतिरिक्त सिस्टम-व्यापी सुरक्षा नियंत्रणों को कमजोर करने के बजाय इसे imsg प्रोजेक्ट को रिपोर्ट करें।

      imsg launch चलाने से पहले SIP अक्षम करने के लिए अपने Mac के लिए Apple के Recovery-mode flow का पालन करें।

    3. helper inject करें। SIP अक्षम होने और Messages.app में sign in होने पर:

      bash
      imsg launch

      SIP अभी भी सक्षम होने पर imsg launch inject करने से इनकार करता है, इसलिए यह इस बात की पुष्टि भी करता है कि चरण 2 लागू हो गया।

    4. OpenClaw से bridge सत्यापित करें:

      bash
      openclaw channels status --probe

      iMessage 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 selector true है, इसलिए 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 के लिए स्वीकार्य नहीं है:

    • imsg basic 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)
    • allowlist
    • open (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)
    • open
    • disabled

    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, fallback messages.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 करता है:

    1. Group-specific system prompt (groups["<chat_id>"].systemPrompt): तब उपयोग होता है जब specific group entry map में मौजूद हो और उसकी systemPrompt key defined हो। यदि systemPrompt empty string ("") है, तो wildcard suppress हो जाता है और उस group पर कोई system prompt apply नहीं होता।
    2. Group wildcard system prompt (groups["*"].systemPrompt): तब उपयोग होता है जब specific group entry map से पूरी तरह absent हो, या वह मौजूद हो लेकिन कोई systemPrompt key define न करती हो।
    json5
    {  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 close ACP 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:

    json5
    {  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:

    1. Dedicated macOS user बनाएं/sign in करें।
    2. उस user में bot Apple ID के साथ Messages में sign in करें।
    3. उस user में imsg install करें।
    4. SSH wrapper बनाएं ताकि OpenClaw उस user context में imsg चला सके।
    5. 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 पर चलता है
    • cliPath wrapper SSH का उपयोग करके imsg चलाता है
    • remoteHost SCP attachment fetches enable करता है

    Example:

    json5
    {  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",    },  },}
    bash
    #!/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.chunkMode
      • length (डिफ़ॉल्ट)
      • newline (पहले-पैराग्राफ विभाजन)
    एड्रेसिंग फ़ॉर्मैट

    पसंदीदा स्पष्ट लक्ष्य:

    • chat_id:123 (स्थिर रूटिंग के लिए अनुशंसित)
    • chat_guid:...
    • chat_identifier:...

    हैंडल लक्ष्य भी समर्थित हैं:

    • imessage:+1555...
    • sms:+1555...
    • user@example.com
    bash
    imsg chats --limit 20

    निजी API कार्रवाइयाँ

    जब imsg launch चल रहा हो और openclaw channels status --probe privateApi.available: true रिपोर्ट करे, तो संदेश टूल सामान्य टेक्स्ट भेजने के अलावा iMessage-नेटिव कार्रवाइयों का उपयोग कर सकता है।

    json5
    {  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: मीडिया/फ़ाइलें भेजें (buffer base64 के रूप में या hydrated media/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 बंद करने के लिए:

    json5
    {  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) → deny
    • allow-always manual 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=true tapbacks (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 हो)।

    बंद करें:

    json5
    {  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 करता है:

    1. एक text message ("Dump")।
    2. 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 हैं।

    सक्षम करना

    json5
    {  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 करने के लिए:

    json5
    {  messages: {    inbound: {      byChannel: {        // 7000 ms covers observed Messages.app URL-preview delays.        imessage: 7000,      },    },  },}

    Trade-offs

    • सटीक merging के लिए current imsg payload metadata चाहिए। जब URL row में balloon_bundle_id शामिल हो, तो केवल वही वास्तविक split-send merge होता है और अन्य buffered rows separate रहते हैं। पुराने imsg builds पर, जो कोई balloon metadata expose नहीं करते, OpenClaw buffered bucket merge करने पर fallback करता है ताकि Dump <url> split-sends दो turns में regress न हों (interim back-compat, जब imsg upstream 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.coalesceSameSenderDms set करते हैं, उन्हें वह value channels.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.db rowid (एक 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 लागू हुई):

    Code
    imessage: suppressed stale inbound backlog account=<id> sent=<iso> recovery=<bool> (&lt;N&gt; 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 करें:

    bash
    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 करे।

    bash
    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 अक्सर पर्याप्त होता है:

    bash
    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 restart

    phone से एक नया 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 "$@" चलाए।

    bash
    #!/usr/bin/env bashexec ssh -T messages-mac imsg "$@"

    फिर चलाएं:

    bash
    openclaw channels status --probe --channel imessage
    DMs are ignored

    जांचें:

    • channels.imessage.dmPolicy
    • channels.imessage.allowFrom
    • pairing approvals (openclaw pairing list imessage)
    Group messages are ignored

    जांचें:

    • channels.imessage.groupPolicy
    • channels.imessage.groupAllowFrom
    • channels.imessage.groups allowlist behavior
    • mention pattern configuration (agents.list[].groupChat.mentionPatterns)
    Remote attachments fail

    जांचें:

    • channels.imessage.remoteHost
    • channels.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 करें:

    bash
    imsg chats --limit 1imsg send <handle> "test"

    Confirm करें कि OpenClaw/imsg चलाने वाले process context के लिए Full Disk Access + Automation granted हैं।

    Configuration reference pointers

    Was this useful?
    On this page

    On this page