Langsung ke konten utama
Untuk deployment iMessage OpenClaw, gunakan imsg pada host Messages macOS yang sudah masuk. Jika Gateway Anda berjalan di Linux atau Windows, arahkan channels.imessage.cliPath ke wrapper SSH yang menjalankan imsg di Mac.Pemulihan masuk otomatis. Setelah bridge atau gateway dimulai ulang, iMessage memutar ulang pesan yang terlewat saat tidak aktif dan menekan “backlog bomb” usang yang dapat dikosongkan Apple setelah pemulihan Push, melakukan deduplikasi agar tidak ada yang dikirim dua kali. Tidak ada konfigurasi yang perlu diaktifkan — lihat Pemulihan masuk setelah bridge atau gateway dimulai ulang.
Dukungan BlueBubbles telah dihapus. Migrasikan konfigurasi channels.bluebubbles ke channels.imessage; OpenClaw mendukung iMessage hanya melalui imsg. Mulai dari Penghapusan BlueBubbles dan jalur iMessage imsg untuk pengumuman singkat, atau Beralih dari BlueBubbles untuk tabel migrasi lengkap.
Status: integrasi CLI eksternal native. Gateway menjalankan imsg rpc dan berkomunikasi melalui JSON-RPC di stdio (tanpa daemon/port terpisah). Tindakan lanjutan memerlukan imsg launch dan probe private API yang berhasil.

Private API actions

Balasan, tapback, efek, polling, lampiran, dan manajemen grup.

Pairing

DM iMessage secara default menggunakan mode pairing.

Remote Mac

Gunakan wrapper SSH saat Gateway tidak berjalan di Mac Messages.

Configuration reference

Referensi lengkap field iMessage.

Penyiapan cepat

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>
Permintaan pairing kedaluwarsa setelah 1 jam.

Persyaratan dan izin (macOS)

  • Messages harus sudah masuk di Mac yang menjalankan imsg.
  • Full Disk Access diperlukan untuk konteks proses yang menjalankan OpenClaw/imsg (akses DB Messages).
  • Izin Automation diperlukan untuk mengirim pesan melalui Messages.app.
  • Untuk tindakan lanjutan (react / edit / unsend / balasan berutas / efek / polling / operasi grup), System Integrity Protection harus dinonaktifkan — lihat Mengaktifkan private API imsg di bawah. Pengiriman/penerimaan teks dan media dasar berfungsi tanpanya.
Izin diberikan per konteks proses. Jika gateway berjalan headless (LaunchAgent/SSH), jalankan perintah interaktif sekali dalam konteks yang sama untuk memicu prompt:
imsg chats --limit 1
# or
imsg send <handle> "test"
Penyiapan SSH jarak jauh dapat membaca chat, lolos channels status --probe, dan memproses pesan masuk sementara pengiriman keluar tetap gagal dengan kesalahan otorisasi AppleEvents:
Not authorized to send Apple events to Messages. (-1743)
Periksa database TCC pengguna Mac yang masuk atau System Settings > Privacy & Security > Automation. Jika entri Automation dicatat untuk /usr/libexec/sshd-keygen-wrapper, bukan proses imsg atau shell lokal, macOS mungkin tidak menampilkan toggle Messages yang dapat digunakan untuk klien sisi server SSH tersebut:
kTCCServiceAppleEvents | /usr/libexec/sshd-keygen-wrapper | auth_value=0 | com.apple.MobileSMS
Dalam kondisi tersebut, mengulangi tccutil reset AppleEvents atau menjalankan ulang imsg send melalui wrapper SSH yang sama mungkin terus gagal karena konteks proses yang membutuhkan Automation Messages adalah wrapper SSH, bukan aplikasi yang dapat diberi izin oleh UI.Gunakan salah satu konteks proses imsg yang didukung sebagai gantinya:
  • Jalankan Gateway, atau setidaknya bridge imsg, di sesi lokal pengguna Messages yang sedang masuk.
  • Mulai Gateway dengan LaunchAgent untuk pengguna tersebut setelah memberikan Full Disk Access dan Automation dari sesi yang sama.
  • Jika Anda mempertahankan topologi SSH dua pengguna, verifikasi bahwa imsg send keluar yang nyata berhasil melalui wrapper yang persis sama sebelum mengaktifkan saluran. Jika Automation tidak dapat diberikan, konfigurasi ulang ke penyiapan imsg satu pengguna alih-alih mengandalkan wrapper SSH untuk pengiriman.

Mengaktifkan private API imsg

imsg dikirim dalam dua mode operasional:
  • Mode dasar (default, tidak perlu perubahan SIP): teks dan media keluar melalui send, watch/history masuk, daftar chat. Ini yang Anda dapatkan langsung dari brew install steipete/tap/imsg baru ditambah izin macOS standar di atas.
  • Mode private API: imsg menyuntikkan helper dylib ke Messages.app untuk memanggil fungsi internal IMCore. Ini membuka react, edit, unsend, reply (berutas), sendWithEffect, poll dan poll-vote (polling Messages native), renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup, plus indikator mengetik dan tanda dibaca.
Untuk mencapai permukaan tindakan lanjutan yang didokumentasikan halaman saluran ini, Anda memerlukan mode Private API. README imsg tegas tentang persyaratan ini:
Fitur lanjutan seperti read, typing, launch, pengiriman kaya berbasis bridge, mutasi pesan, dan manajemen chat bersifat opt-in. Fitur tersebut memerlukan SIP dinonaktifkan dan helper dylib disuntikkan ke Messages.app. imsg launch menolak menyuntikkan saat SIP diaktifkan.
Teknik injeksi helper menggunakan dylib milik imsg sendiri untuk menjangkau private API Messages. Tidak ada server pihak ketiga atau runtime BlueBubbles di jalur iMessage OpenClaw.
Menonaktifkan SIP adalah kompromi keamanan nyata. SIP adalah salah satu perlindungan inti macOS terhadap eksekusi kode sistem yang dimodifikasi; mematikannya secara sistem-wide membuka permukaan serangan tambahan dan efek samping. Khususnya, menonaktifkan SIP pada Mac Apple Silicon juga menonaktifkan kemampuan untuk menginstal dan menjalankan aplikasi iOS di Mac Anda.Perlakukan ini sebagai pilihan operasional yang disengaja, bukan default. Jika model ancaman Anda tidak dapat menoleransi SIP dimatikan, iMessage bawaan terbatas pada mode dasar — hanya pengiriman/penerimaan teks dan media, tanpa reaksi / edit / unsend / efek / operasi grup.

Penyiapan

  1. Instal (atau tingkatkan) imsg di Mac yang menjalankan Messages.app:
    brew install steipete/tap/imsg
    imsg --version
    imsg status --json
    
    Output imsg status --json melaporkan bridge_version, rpc_methods, dan selectors per metode sehingga Anda dapat melihat apa yang didukung build saat ini sebelum memulai.
  2. Nonaktifkan System Integrity Protection, dan (pada macOS modern) Library Validation. Menyuntikkan helper dylib non-Apple ke Messages.app yang ditandatangani Apple memerlukan SIP dimatikan dan validasi library dilonggarkan. Langkah SIP mode Recovery spesifik untuk versi macOS:
    • macOS 10.13-10.15 (Sierra-Catalina): nonaktifkan Library Validation melalui Terminal, reboot ke Recovery Mode, jalankan csrutil disable, mulai ulang.
    • macOS 11+ (Big Sur dan yang lebih baru), Intel: Recovery Mode (atau Internet Recovery), csrutil disable, mulai ulang.
    • macOS 11+, Apple Silicon: urutan startup tombol daya untuk masuk Recovery; pada versi macOS terbaru tahan tombol Left Shift saat Anda mengklik Continue, lalu csrutil disable. Penyiapan mesin virtual mengikuti alur terpisah, jadi ambil snapshot VM terlebih dahulu.
    Pada macOS 11 dan yang lebih baru, csrutil disable saja biasanya tidak cukup. Apple masih menerapkan validasi library terhadap Messages.app sebagai binary platform, sehingga helper yang ditandatangani adhoc ditolak (Library Validation failed: ... platform binary, but mapped file is not) bahkan dengan SIP dimatikan. Setelah menonaktifkan SIP, nonaktifkan juga validasi library dan reboot:
    sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool true
    
    macOS 26 (Tahoe), diverifikasi pada 26.5.1: SIP dimatikan plus perintah DisableLibraryValidation di atas sudah cukup untuk menyuntikkan helper di seluruh 26.0 hingga 26.5.x. Tidak diperlukan boot-args. Plist adalah faktor penentu dan langkah yang paling umum terlewat saat injeksi gagal di Tahoe:
    • Dengan plist: imsg launch menyuntikkan dan imsg status melaporkan advanced_features: true.
    • Tanpa plist (bahkan dengan SIP dimatikan): imsg launch gagal dengan Failed to launch: Timeout waiting for Messages.app to initialize. AMFI menolak helper adhoc saat dimuat, sehingga bridge tidak pernah siap dan launch timeout. Timeout tersebut adalah gejala yang paling sering ditemui di Tahoe, dan perbaikannya adalah plist di atas, bukan tindakan yang lebih drastis.
    Ini dikonfirmasi dengan before/after terkontrol pada macOS 26.5.1 (Apple Silicon): dengan plist, dylib dipetakan ke Messages.app dan bridge aktif; hapus plist dan reboot, lalu imsg launch menghasilkan kegagalan timeout di atas dengan dylib tidak dipetakan. Jika injeksi imsg launch atau selectors tertentu mulai mengembalikan false setelah peningkatan macOS, gate ini biasanya penyebabnya. Periksa status SIP dan validasi pustaka Anda sebelum menganggap langkah SIP itu sendiri gagal. Jika pengaturan tersebut benar dan bridge masih tidak dapat melakukan injeksi, kumpulkan imsg status --json beserta keluaran imsg launch dan laporkan ke proyek imsg, bukan melemahkan kontrol keamanan tambahan di seluruh sistem. Ikuti alur mode Recovery Apple untuk Mac Anda guna menonaktifkan SIP sebelum menjalankan imsg launch.
  3. Injeksikan helper. Dengan SIP dinonaktifkan dan Messages.app sudah masuk:
    imsg launch
    
    imsg launch menolak melakukan injeksi ketika SIP masih aktif, jadi ini juga berfungsi sebagai konfirmasi bahwa langkah 2 berhasil.
  4. Verifikasi bridge dari OpenClaw:
    openclaw channels status --probe
    
    Entri iMessage seharusnya melaporkan works, dan imsg status --json | jq '{rpc_methods, selectors}' seharusnya menampilkan kapabilitas yang diekspos oleh build macOS Anda. Pembuatan polling memerlukan selectors.pollPayloadMessage; voting memerlukan selectors.pollVoteMessage dan metode RPC poll.vote. Plugin OpenClaw hanya mengiklankan tindakan yang didukung oleh probe yang di-cache, sementara cache kosong tetap optimistis dan melakukan probe pada pengiriman pertama.
Jika openclaw channels status --probe melaporkan channel sebagai works tetapi tindakan tertentu melempar “iMessage <action> requires the imsg private API bridge” saat pengiriman, jalankan imsg launch lagi — helper dapat terlepas (restart Messages.app, pembaruan OS, dll.) dan status available: true yang di-cache akan terus mengiklankan tindakan sampai probe berikutnya menyegarkan status.

Ketika Anda tidak dapat menonaktifkan SIP

Jika SIP yang dinonaktifkan tidak dapat diterima untuk model ancaman Anda:
  • imsg kembali ke mode dasar — teks + media + hanya menerima.
  • Plugin OpenClaw masih mengiklankan pengiriman teks/media dan pemantauan masuk; Plugin hanya menyembunyikan react, edit, unsend, reply, sendWithEffect, dan operasi grup dari permukaan tindakan (sesuai gate kapabilitas per metode).
  • Anda dapat menjalankan Mac non-Apple-Silicon terpisah (atau Mac bot khusus) dengan SIP mati untuk beban kerja iMessage, sambil tetap mengaktifkan SIP di perangkat utama Anda. Lihat Dedicated bot macOS user (separate iMessage identity) di bawah.

Kontrol akses dan routing

channels.imessage.dmPolicy mengontrol pesan langsung:
  • pairing (default)
  • allowlist
  • open (memerlukan allowFrom untuk menyertakan "*")
  • disabled
Kolom allowlist: channels.imessage.allowFrom.Entri allowlist harus mengidentifikasi pengirim: handle atau grup akses pengirim statis (accessGroup:<name>). Gunakan channels.imessage.groupAllowFrom untuk target chat seperti chat_id:*, chat_guid:*, atau chat_identifier:*; gunakan channels.imessage.groups untuk kunci registri chat_id numerik.

Binding percakapan ACP

Chat iMessage lama juga dapat diikat ke sesi ACP. Alur operator cepat:
  • Jalankan /acp spawn codex --bind here di dalam DM atau chat grup yang diizinkan.
  • Pesan berikutnya dalam percakapan iMessage yang sama dirutekan ke sesi ACP yang dibuat.
  • /new dan /reset mereset sesi ACP terikat yang sama di tempat.
  • /acp close menutup sesi ACP dan menghapus binding.
Binding persisten yang dikonfigurasi didukung melalui entri bindings[] tingkat atas dengan type: "acp" dan match.channel: "imessage". match.peer.id dapat menggunakan:
  • handle DM yang dinormalisasi seperti +15555550123 atau user@example.com
  • chat_id:<id> (direkomendasikan untuk binding grup yang stabil)
  • chat_guid:<guid>
  • chat_identifier:<identifier>
Contoh:
{
  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" },
    },
  ],
}
Lihat Agen ACP untuk perilaku binding ACP bersama.

Pola deployment

Gunakan Apple ID khusus dan pengguna macOS khusus agar traffic bot terisolasi dari profil Messages pribadi Anda.Alur umum:
  1. Buat/masuk sebagai pengguna macOS khusus.
  2. Masuk ke Messages dengan Apple ID bot di pengguna tersebut.
  3. Instal imsg di pengguna tersebut.
  4. Buat wrapper SSH agar OpenClaw dapat menjalankan imsg dalam konteks pengguna tersebut.
  5. Arahkan channels.imessage.accounts.<id>.cliPath dan .dbPath ke profil pengguna tersebut.
Eksekusi pertama mungkin memerlukan persetujuan GUI (Automation + Full Disk Access) di sesi pengguna bot tersebut.
Topologi umum:
  • gateway berjalan di Linux/VM
  • iMessage + imsg berjalan di Mac dalam tailnet Anda
  • wrapper cliPath menggunakan SSH untuk menjalankan imsg
  • remoteHost mengaktifkan pengambilan lampiran melalui SCP
Contoh:
{
  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 "$@"
Gunakan kunci SSH agar SSH dan SCP sama-sama noninteraktif. Pastikan kunci host dipercaya terlebih dahulu (misalnya ssh bot@mac-mini.tailnet-1234.ts.net) agar known_hosts terisi.
iMessage mendukung konfigurasi per akun di bawah channels.imessage.accounts.Setiap akun dapat mengganti kolom seperti cliPath, dbPath, allowFrom, groupPolicy, mediaMaxMb, pengaturan riwayat, dan allowlist root lampiran.
Atur channels.imessage.dmHistoryLimit untuk mengisi sesi pesan langsung baru dengan riwayat imsg terbaru yang sudah didekode untuk percakapan tersebut. Gunakan channels.imessage.dms["<sender>"].historyLimit untuk penggantian per pengirim, termasuk 0 untuk menonaktifkan riwayat bagi seorang pengirim.Riwayat DM iMessage diambil sesuai permintaan dari imsg. Membiarkan dmHistoryLimit tidak diatur menonaktifkan pengisian riwayat DM global, tetapi channels.imessage.dms["<sender>"].historyLimit per pengirim yang bernilai positif tetap mengaktifkan pengisian untuk pengirim tersebut.

Media, pemotongan, dan target pengiriman

  • penyerapan lampiran masuk nonaktif secara default — atur channels.imessage.includeAttachments: true untuk meneruskan foto, memo suara, video, dan lampiran lain ke agen. Jika dinonaktifkan, iMessage yang hanya berisi lampiran akan dibuang sebelum mencapai agen dan mungkin sama sekali tidak menghasilkan baris log Inbound message.
  • jalur lampiran jarak jauh dapat diambil melalui SCP saat remoteHost ditetapkan
  • jalur lampiran harus cocok dengan root yang diizinkan:
    • channels.imessage.attachmentRoots (lokal)
    • channels.imessage.remoteAttachmentRoots (mode SCP jarak jauh)
    • pola root default: /Users/*/Library/Messages/Attachments
  • SCP menggunakan pemeriksaan kunci host ketat (StrictHostKeyChecking=yes)
  • ukuran media keluar menggunakan channels.imessage.mediaMaxMb (default 16 MB)
  • batas potongan teks: channels.imessage.textChunkLimit (default 4000)
  • mode potongan: channels.imessage.chunkMode
    • length (default)
    • newline (pemecahan yang mengutamakan paragraf)
Target eksplisit yang disarankan:
  • chat_id:123 (direkomendasikan untuk perutean stabil)
  • chat_guid:...
  • chat_identifier:...
Target handle juga didukung:
  • imessage:+1555...
  • sms:+1555...
  • user@example.com
imsg chats --limit 20

Tindakan API privat

Saat imsg launch berjalan dan openclaw channels status --probe melaporkan privateApi.available: true, alat pesan dapat menggunakan tindakan native iMessage selain pengiriman teks biasa.
{
  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,
        polls: true,
      },
    },
  },
}
  • react: Menambah/menghapus tapback iMessage (messageId, emoji, remove). Tapback yang didukung dipetakan ke love, like, dislike, laugh, emphasize, dan question.
  • reply: Mengirim balasan berutas ke pesan yang sudah ada (messageId, text atau message, ditambah chatGuid, chatId, chatIdentifier, atau to).
  • sendWithEffect: Mengirim teks dengan efek iMessage (text atau message, effect atau effectId).
  • edit: Mengedit pesan terkirim pada versi macOS/API privat yang didukung (messageId, text atau newText).
  • unsend: Menarik kembali pesan terkirim pada versi macOS/API privat yang didukung (messageId).
  • upload-file: Mengirim media/berkas (buffer sebagai base64 atau media/path/filePath yang telah dihidrasi, filename, opsional asVoice). Alias lama: sendAttachment.
  • renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup: Mengelola obrolan grup saat target saat ini adalah percakapan grup.
  • poll: Membuat polling native Apple Messages (pollQuestion, pollOption diulang 2 hingga 12 kali, ditambah chatGuid, chatId, chatIdentifier, atau to). Penerima di iOS/iPadOS/macOS 26+ melihat dan memberikan suara secara native; versi OS lama menerima fallback teks “Sent a poll”. Memerlukan selectors.pollPayloadMessage.
  • poll-vote: Memberikan suara pada polling yang sudah ada (pollId atau messageId, ditambah tepat salah satu dari pollOptionIndex, pollOptionId, atau pollOptionText). Memerlukan selectors.pollVoteMessage dan metode RPC poll.vote.
Polling masuk yang diterima dirender untuk agen dengan pertanyaan, label opsi bernomor, jumlah suara, dan ID pesan polling yang diperlukan oleh poll-vote.
Konteks iMessage masuk mencakup nilai MessageSid pendek dan GUID pesan lengkap saat tersedia. ID pendek dicakupkan ke cache balasan terbaru berbasis SQLite dan diperiksa terhadap obrolan saat ini sebelum digunakan. Jika ID pendek telah kedaluwarsa atau milik obrolan lain, coba lagi dengan MessageSidFull.
OpenClaw menyembunyikan tindakan API privat hanya saat status probe yang di-cache menyatakan bridge tidak tersedia. Jika status tidak diketahui, tindakan tetap terlihat dan dispatch melakukan probe secara malas sehingga tindakan pertama dapat berhasil setelah imsg launch tanpa penyegaran status manual terpisah.
Saat bridge API privat aktif, obrolan masuk yang diterima ditandai sudah dibaca dan obrolan langsung menampilkan gelembung mengetik segera setelah giliran diterima, sementara agen menyiapkan konteks dan menghasilkan respons. Nonaktifkan penandaan baca dengan:
{
  channels: {
    imessage: {
      sendReadReceipts: false,
    },
  },
}
Build imsg lama yang mendahului daftar kapabilitas per metode akan menonaktifkan pengetikan/tanda baca secara diam-diam; OpenClaw mencatat peringatan satu kali per restart agar tanda terima yang hilang dapat dilacak penyebabnya.
OpenClaw berlangganan tapback iMessage dan merutekan reaksi yang diterima sebagai peristiwa sistem, bukan teks pesan biasa, sehingga tapback pengguna tidak memicu loop balasan biasa.Mode notifikasi dikendalikan oleh channels.imessage.reactionNotifications:
  • "own" (default): beri tahu hanya saat pengguna bereaksi ke pesan yang ditulis bot.
  • "all": beri tahu untuk semua tapback masuk dari pengirim yang diotorisasi.
  • "off": abaikan tapback masuk.
Override per akun menggunakan channels.imessage.accounts.<id>.reactionNotifications.
Saat approvals.exec.enabled atau approvals.plugin.enabled bernilai true dan permintaan dirutekan ke iMessage, Gateway mengirim prompt persetujuan secara native dan menerima tapback untuk menyelesaikannya:
  • 👍 (tapback Like) → allow-once
  • 👎 (tapback Dislike) → deny
  • allow-always tetap menjadi fallback manual: kirim /approve <id> allow-always sebagai balasan reguler.
Penanganan reaksi mengharuskan handle pengguna yang bereaksi menjadi pemberi persetujuan eksplisit. Daftar pemberi persetujuan dibaca dari channels.imessage.allowFrom (atau channels.imessage.accounts.<id>.allowFrom); tambahkan nomor telepon pengguna dalam format E.164 atau email Apple ID mereka. Entri wildcard "*" dihormati tetapi mengizinkan pengirim mana pun untuk menyetujui. Pintasan reaksi sengaja melewati reactionNotifications, dmPolicy, dan groupAllowFrom karena allowlist pemberi persetujuan eksplisit adalah satu-satunya gerbang yang penting untuk resolusi persetujuan.Perubahan perilaku dengan rilis ini: Saat channels.imessage.allowFrom tidak kosong, perintah teks /approve <id> <decision> kini diotorisasi terhadap daftar pemberi persetujuan tersebut (bukan allowlist DM yang lebih luas). Pengirim yang diizinkan pada allowlist DM tetapi tidak ada di allowFrom akan menerima penolakan eksplisit. Tambahkan setiap operator yang harus dapat menyetujui melalui /approve (dan melalui reaksi) ke allowFrom untuk mempertahankan perilaku sebelumnya. Saat allowFrom kosong, “fallback obrolan yang sama” lama tetap berlaku dan /approve terus mengotorisasi siapa pun yang diizinkan oleh allowlist DM.Catatan operator:
  • Binding reaksi disimpan baik di memori (dengan TTL yang dicocokkan dengan kedaluwarsa persetujuan) maupun di penyimpanan keyed persisten Gateway, sehingga tapback yang masuk tak lama setelah restart Gateway tetap menyelesaikan persetujuan.
  • Tapback lintas perangkat is_from_me=true (reaksi operator sendiri pada perangkat Apple yang dipasangkan) sengaja diabaikan agar bot tidak dapat menyetujui dirinya sendiri.
  • Tapback gaya teks lama (Liked "…" sebagai teks biasa dari klien Apple yang sangat lama) tidak dapat menyelesaikan persetujuan karena tidak membawa GUID pesan; resolusi reaksi memerlukan metadata tapback terstruktur yang dipancarkan klien macOS / iOS saat ini.

Penulisan konfigurasi

iMessage mengizinkan penulisan konfigurasi yang dimulai channel secara default (untuk /config set|unset saat commands.config: true). Nonaktifkan:
{
  channels: {
    imessage: {
      configWrites: false,
    },
  },
}

Menggabungkan DM split-send (perintah + URL dalam satu komposisi)

Saat pengguna mengetik perintah dan URL bersama-sama — misalnya Dump https://example.com/article — aplikasi Messages Apple memecah pengiriman menjadi dua baris chat.db terpisah:
  1. Pesan teks ("Dump").
  2. Gelembung pratinjau URL ("https://...") dengan gambar pratinjau OG sebagai lampiran.
Kedua baris tiba di OpenClaw dengan selang ~0,8-2,0 d pada sebagian besar penyiapan. Tanpa penggabungan, agen menerima perintah saja pada giliran 1, membalas (sering kali “send me the URL”), dan baru melihat URL pada giliran 2 — saat konteks perintah sudah hilang. Ini adalah pipeline pengiriman Apple, bukan sesuatu yang diperkenalkan OpenClaw atau imsg. channels.imessage.coalesceSameSenderDms membuat DM menggunakan buffering baris berurutan dari pengirim yang sama. Saat imsg mengekspos penanda struktural pratinjau URL balloon_bundle_id: "com.apple.messages.URLBalloonProvider" pada salah satu baris sumber, OpenClaw hanya menggabungkan split-send nyata tersebut dan mempertahankan baris buffer lain sebagai giliran terpisah. Pada build imsg lama yang sama sekali tidak memancarkan metadata gelembung, OpenClaw tidak dapat membedakan split-send dari pengiriman terpisah, sehingga fallback ke penggabungan bucket. Itu mempertahankan perilaku pra-metadata alih-alih meregresikan split-send Dump <url> menjadi dua giliran. Obrolan grup terus melakukan dispatch per pesan sehingga struktur giliran multi-pengguna tetap dipertahankan.
Aktifkan saat:
  • Anda mengirim Skills yang mengharapkan command + payload dalam satu pesan (dump, paste, save, queue, dll.).
  • Pengguna Anda menempelkan URL bersama perintah.
  • Anda dapat menerima latensi giliran DM tambahan (lihat di bawah).
Biarkan nonaktif saat:
  • Anda membutuhkan latensi perintah minimum untuk pemicu DM satu kata.
  • Semua flow Anda adalah perintah sekali jalan tanpa tindak lanjut payload.

Skenario dan apa yang dilihat agen

Kolom “Flag aktif” menunjukkan perilaku pada build imsg yang memancarkan balloon_bundle_id. Pada build imsg lama yang sama sekali tidak memancarkan metadata balon, baris di bawah yang ditandai “Dua giliran” / “N giliran” akan kembali ke penggabungan lama (satu giliran): OpenClaw tidak dapat membedakan secara struktural split-send dari pengiriman terpisah, sehingga mempertahankan penggabungan pra-metadata. Pemisahan presisi aktif setelah build memancarkan metadata balon.
Pengguna menyusunchat.db menghasilkanFlag nonaktif (default)Flag aktif + jendela (imsg memancarkan metadata balon)
Dump https://example.com (satu pengiriman)2 baris berjarak ~1 dDua giliran agen: “Dump” saja, lalu URLSatu giliran: teks gabungan Dump https://example.com
Save this 📎image.jpg caption (lampiran + teks)2 baris tanpa metadata balon URLDua giliranDua giliran setelah metadata teramati; satu giliran gabungan pada sesi lama/pra-latch tanpa metadata
/status (perintah mandiri)1 barisPengiriman instanTunggu hingga jendela, lalu kirim
URL ditempel sendiri1 barisPengiriman instanTunggu hingga jendela, lalu kirim
Teks + URL dikirim sebagai dua pesan terpisah yang disengaja, terpaut menit2 baris di luar jendelaDua giliranDua giliran (jendela kedaluwarsa di antaranya)
Banjir cepat (>10 DM kecil dalam jendela)N baris tanpa metadata balon URLN giliranN giliran setelah metadata teramati; satu giliran gabungan terbatas pada sesi lama/pra-latch tanpa metadata
Dua orang mengetik di obrolan grupN baris dari M pengirimM+ giliran (satu per bucket pengirim)M+ giliran — obrolan grup tidak digabungkan

Pemulihan inbound setelah bridge atau gateway dimulai ulang

iMessage memulihkan pesan yang terlewat saat gateway mati, dan pada saat yang sama menekan “bom backlog” usang yang dapat digelontorkan Apple setelah pemulihan Push. Perilaku default selalu aktif, dibangun di atas dedupe inbound.
  • Dedupe replay. Setiap pesan inbound yang dikirim dicatat berdasarkan GUID Apple-nya dalam status Plugin persisten (imessage.inbound-dedupe), diklaim saat ingestion dan dikomit setelah penanganan (dilepas pada kegagalan sementara agar dapat dicoba ulang). Apa pun yang sudah ditangani akan dijatuhkan, bukan dikirim dua kali. Inilah yang memungkinkan replay pemulihan berjalan agresif tanpa pembukuan per pesan.
  • Pemulihan downtime. Saat startup, monitor mengingat chat.db rowid terakhir yang dikirim (kursor per akun yang dipersistenkan) dan meneruskannya ke imsg watch.subscribe sebagai since_rowid, sehingga imsg memutar ulang baris yang masuk saat gateway mati, lalu mengikuti live. Replay dibatasi ke baris terbaru dan ke pesan hingga usia ~2 jam, dan dedupe menjatuhkan apa pun yang sudah ditangani.
  • Pagar usia backlog usang. Baris di atas batas startup benar-benar live; baris yang tanggal kirimnya lebih dari ~15 menit lebih lama daripada waktu kedatangannya adalah backlog Push-flush dan ditekan. Baris yang diputar ulang (di atau di bawah batas) menggunakan jendela pemulihan yang lebih lebar, sehingga pesan yang baru saja terlewat dikirim sementara riwayat kuno tidak.
Pemulihan bekerja pada setup cliPath lokal maupun jarak jauh, karena replay since_rowid berjalan melalui koneksi RPC imsg yang sama. Perbedaannya ada pada jendela: saat gateway dapat membaca chat.db (lokal), gateway menambatkan batas rowid startup, membatasi rentang replay, dan mengirim pesan yang terlewat hingga sekitar beberapa jam. Melalui cliPath SSH jarak jauh, gateway tidak dapat membaca basis data, sehingga replay tidak dibatasi dan setiap baris menggunakan pagar usia live — tetap memulihkan pesan yang baru saja terlewat dan tetap menekan backlog lama, hanya dengan jendela live yang lebih sempit. Jalankan gateway di Mac Messages untuk jendela pemulihan yang lebih lebar.

Sinyal yang terlihat operator

Backlog yang ditekan dicatat pada level default, tidak pernah dijatuhkan diam-diam (flag recovery menunjukkan jendela mana yang diterapkan):
imessage: suppressed stale inbound backlog account=<id> sent=<iso> recovery=<bool> (<N> suppressed since start)

Migrasi

channels.imessage.catchup.* tidak digunakan lagi — pemulihan downtime sekarang otomatis dan tidak memerlukan konfigurasi untuk setup baru. Konfigurasi yang sudah ada dengan catchup.enabled: true tetap dihormati sebagai profil kompatibilitas untuk jendela replay pemulihan. Blok catchup yang dinonaktifkan (enabled: false atau tanpa enabled: true) sudah dipensiunkan; openclaw doctor --fix menghapusnya.

Pemecahan masalah

Validasi binary dan dukungan RPC:
imsg rpc --help
imsg status --json
openclaw channels status --probe
Jika probe melaporkan RPC tidak didukung, perbarui imsg. Jika tindakan API privat tidak tersedia, jalankan imsg launch dalam sesi pengguna macOS yang sedang login dan probe lagi. Jika Gateway tidak berjalan di macOS, gunakan setup Remote Mac melalui SSH di atas alih-alih path imsg lokal default.
Pertama buktikan apakah pesan mencapai Mac lokal. Jika chat.db tidak berubah, OpenClaw tidak dapat menerima pesan meskipun imsg status --json melaporkan bridge yang sehat.
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;"
Jika pesan yang dikirim dari ponsel tidak membuat baris baru, perbaiki lapisan macOS Messages dan Apple Push sebelum mengubah konfigurasi OpenClaw. Refresh layanan sekali jalan sering kali cukup:
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
Kirim iMessage baru dari ponsel dan konfirmasi baris chat.db baru atau event imsg watch sebelum men-debug sesi OpenClaw. Jangan jalankan ini sebagai loop peluncuran ulang bridge berkala; imsg launch berulang plus restart gateway selama pekerjaan aktif dapat mengganggu pengiriman dan meninggalkan run kanal yang sedang berjalan.
cliPath: "imsg" default harus berjalan di Mac yang login ke Messages. Di Linux atau Windows, atur channels.imessage.cliPath ke script wrapper yang melakukan SSH ke Mac itu dan menjalankan imsg "$@".
#!/usr/bin/env bash
exec ssh -T messages-mac imsg "$@"
Lalu jalankan:
openclaw channels status --probe --channel imessage
Periksa:
  • channels.imessage.dmPolicy
  • channels.imessage.allowFrom
  • persetujuan pairing (openclaw pairing list imessage)
Periksa:
  • channels.imessage.groupPolicy
  • channels.imessage.groupAllowFrom
  • perilaku allowlist channels.imessage.groups
  • konfigurasi pola mention (agents.list[].groupChat.mentionPatterns)
Periksa:
  • channels.imessage.remoteHost
  • channels.imessage.remoteAttachmentRoots
  • autentikasi kunci SSH/SCP dari host gateway
  • kunci host ada di ~/.ssh/known_hosts pada host gateway
  • keterbacaan path jarak jauh di Mac yang menjalankan Messages
Jalankan ulang di terminal GUI interaktif dalam konteks pengguna/sesi yang sama dan setujui prompt:
imsg chats --limit 1
imsg send <handle> "test"
Konfirmasi Full Disk Access + Automation diberikan untuk konteks proses yang menjalankan OpenClaw/imsg.

Penunjuk referensi konfigurasi

Terkait