मुख्य सामग्री पर जाएं
OpenClaw iMessage डिप्लॉयमेंट के लिए, साइन-इन किए हुए macOS Messages होस्ट पर imsg का उपयोग करें। यदि आपका Gateway Linux या Windows पर चलता है, तो channels.imessage.cliPath को ऐसे SSH wrapper पर सेट करें जो Mac पर imsg चलाता हो।इनबाउंड रिकवरी स्वचालित है। bridge या gateway पुनरारंभ के बाद, iMessage बंद रहने के दौरान छूटे हुए संदेशों को फिर से चलाता है और Push रिकवरी के बाद Apple द्वारा फ्लश किए जा सकने वाले पुराने “backlog bomb” को दबा देता है, dedupe करके सुनिश्चित करता है कि कोई भी चीज दो बार dispatch न हो। इसे सक्षम करने के लिए कोई config नहीं है — देखें bridge या gateway पुनरारंभ के बाद इनबाउंड रिकवरी
BlueBubbles समर्थन हटा दिया गया था। channels.bluebubbles configs को channels.imessage में migrate करें; OpenClaw iMessage को केवल imsg के माध्यम से समर्थन देता है। संक्षिप्त घोषणा के लिए BlueBubbles हटाना और imsg iMessage पथ से शुरू करें, या पूर्ण migration तालिका के लिए BlueBubbles से आ रहे हैं देखें।
स्थिति: native external CLI integration। Gateway imsg rpc spawn करता है और stdio पर JSON-RPC के माध्यम से communicate करता है (अलग daemon/port नहीं)। उन्नत actions के लिए imsg launch और सफल private API probe आवश्यक है।

Private API actions

Replies, tapbacks, effects, attachments, और group management।

Pairing

iMessage DMs default रूप से pairing mode में होते हैं।

Remote Mac

जब Gateway Messages Mac पर नहीं चल रहा हो, तो SSH wrapper का उपयोग करें।

Configuration reference

पूर्ण iMessage field reference।

त्वरित setup

1

Install and verify imsg

brew install steipete/tap/imsg
imsg rpc --help
imsg launch
openclaw channels status --probe
2

Configure OpenClaw

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

Start gateway

openclaw gateway
4

Approve first DM pairing (default dmPolicy)

openclaw pairing list imessage
openclaw pairing approve imessage <CODE>
Pairing requests 1 घंटे बाद expire हो जाते हैं।

आवश्यकताएँ और 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 इसके बिना काम करते हैं।
Permissions per process context grant की जाती हैं। यदि gateway headless (LaunchAgent/SSH) चलता है, तो prompts trigger करने के लिए उसी context में one-time interactive command चलाएँ:
imsg chats --limit 1
# or
imsg send <handle> "test"
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, या कम से कम 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 नहीं है।
SIP disable करना वास्तविक security tradeoff है। SIP, modified system code चलाने के विरुद्ध macOS की core protections में से एक है; इसे system-wide बंद करने से अतिरिक्त attack surface और side effects खुलते हैं। खास तौर पर, Apple Silicon Macs पर SIP disable करने से आपके Mac पर iOS apps install और run करने की क्षमता भी disable हो जाती हैइसे deliberate operational choice मानें, default नहीं। यदि आपका threat model SIP off होना tolerate नहीं कर सकता, तो bundled iMessage basic mode तक सीमित है — केवल text और media send/receive, reactions / edit / unsend / effects / group ops नहीं।

Setup

  1. Messages.app चलाने वाले Mac पर imsg install (या upgrade) करें:
    brew install steipete/tap/imsg
    imsg --version
    imsg 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 करें:
    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 होने पर:
    imsg launch
    
    SIP अभी भी सक्षम होने पर imsg launch inject करने से इनकार करता है, इसलिए यह इस बात की पुष्टि भी करता है कि चरण 2 लागू हो गया।
  4. OpenClaw से bridge सत्यापित करें:
    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

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 का उपयोग करें।

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:
{
  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 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) की आवश्यकता हो सकती है।
Common topology:
  • gateway Linux/VM पर चलता है
  • iMessage + imsg आपकी tailnet में Mac पर चलता है
  • cliPath wrapper SSH का उपयोग करके imsg चलाता है
  • remoteHost SCP 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 bash
exec 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 हो।
iMessage channels.imessage.accounts के अंतर्गत per-account config support करता है।प्रत्येक account cliPath, dbPath, allowFrom, groupPolicy, mediaMaxMb, history settings, और attachment root allowlists जैसे fields override कर सकता है।
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
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: मीडिया/फ़ाइलें भेजें (buffer base64 के रूप में या hydrated media/path/filePath, filename, वैकल्पिक asVoice)। लेगेसी alias: sendAttachment
  • renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup: जब मौजूदा लक्ष्य कोई समूह बातचीत हो, तब समूह चैट प्रबंधित करें।
इनबाउंड iMessage संदर्भ उपलब्ध होने पर छोटे MessageSid मान और पूर्ण संदेश GUID, दोनों शामिल करता है। छोटे ID हाल की SQLite-समर्थित reply cache तक सीमित होते हैं और उपयोग से पहले मौजूदा चैट के विरुद्ध जाँचे जाते हैं। यदि कोई छोटा ID समाप्त हो गया है या किसी दूसरी चैट से संबंधित है, तो पूर्ण MessageSidFull के साथ फिर प्रयास करें।
OpenClaw निजी API कार्रवाइयाँ केवल तब छिपाता है जब cached probe status कहता है कि bridge उपलब्ध नहीं है। यदि status अज्ञात है, तो कार्रवाइयाँ दिखाई देती रहती हैं और dispatch lazily probe करता है, ताकि पहली कार्रवाई imsg launch के बाद अलग manual status refresh के बिना सफल हो सके।
जब 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 का उपयोग करते हैं।
जब 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 हो)। बंद करें:
{
  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 हैं।

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 लागू हुई):
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

binary और RPC support validate करें:
imsg rpc --help
imsg status --json
openclaw 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 उपयोग करें।
पहले साबित करें कि message local Mac तक पहुंचा या नहीं। अगर chat.db नहीं बदलता, तो OpenClaw message receive नहीं कर सकता, भले ही imsg status --json healthy bridge report करे।
imsg chats --limit 10 --json
imsg watch --chat-id <chat-id> --json
sqlite3 ~/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.apsd
launchctl kickstart -k gui/$(id -u)/com.apple.CommCenter
launchctl kickstart -k gui/$(id -u)/com.apple.identityservicesd
launchctl kickstart -k gui/$(id -u)/com.apple.imagent
imsg launch
openclaw 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 कर सकते हैं।
default cliPath: "imsg" को Messages में signed in Mac पर चलना चाहिए। Linux या Windows पर, channels.imessage.cliPath को ऐसे wrapper script पर set करें जो उस Mac पर SSH करे और imsg "$@" चलाए।
#!/usr/bin/env bash
exec ssh -T messages-mac imsg "$@"
फिर चलाएं:
openclaw channels status --probe --channel imessage
जांचें:
  • channels.imessage.dmPolicy
  • channels.imessage.allowFrom
  • pairing approvals (openclaw pairing list imessage)
जांचें:
  • channels.imessage.groupPolicy
  • channels.imessage.groupAllowFrom
  • channels.imessage.groups allowlist behavior
  • mention pattern configuration (agents.list[].groupChat.mentionPatterns)
जांचें:
  • channels.imessage.remoteHost
  • channels.imessage.remoteAttachmentRoots
  • Gateway host से SSH/SCP key auth
  • Gateway host पर ~/.ssh/known_hosts में host key मौजूद है
  • Messages चलाने वाले Mac पर remote path readability
उसी user/session context में interactive GUI terminal में फिर से चलाएं और prompts approve करें:
imsg chats --limit 1
imsg send <handle> "test"
Confirm करें कि OpenClaw/imsg चलाने वाले process context के लिए Full Disk Access + Automation granted हैं।

Configuration reference pointers