Mainstream messaging
iMessage
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.
Balasan, tapback, efek, polling, lampiran, dan manajemen grup.
DM iMessage secara default menggunakan mode pairing.
Gunakan wrapper SSH saat Gateway tidak berjalan di Mac Messages.
Referensi lengkap field iMessage.
Penyiapan cepat
Local Mac (fast path)
Install and verify imsg
brew install steipete/tap/imsgimsg rpc --helpimsg launchopenclaw channels status --probeConfigure OpenClaw
{channels: {imessage: {enabled: true,cliPath: "/usr/local/bin/imsg",dbPath: "/Users/user/Library/Messages/chat.db",},},}Start gateway
openclaw gatewayApprove first DM pairing (default dmPolicy)
openclaw pairing list imessageopenclaw pairing approve imessage <CODE>Permintaan pairing kedaluwarsa setelah 1 jam.
Remote Mac over SSH
OpenClaw hanya memerlukan cliPath yang kompatibel dengan stdio, sehingga Anda dapat mengarahkan cliPath ke skrip wrapper yang melakukan SSH ke Mac jarak jauh dan menjalankan imsg.
#!/usr/bin/env bashexec ssh -T gateway-host imsg "$@"Konfigurasi yang disarankan saat lampiran diaktifkan:
{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"],},},}Jika remoteHost tidak diatur, OpenClaw mencoba mendeteksinya otomatis dengan mengurai skrip wrapper SSH.
remoteHost harus berupa host atau user@host (tanpa spasi atau opsi SSH).
OpenClaw menggunakan pemeriksaan host-key ketat untuk SCP, jadi kunci host relay harus sudah ada di ~/.ssh/known_hosts.
Jalur lampiran divalidasi terhadap root yang diizinkan (attachmentRoots / remoteAttachmentRoots).
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.
SSH wrapper sends fail with AppleEvents -1743
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.MobileSMSDalam 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 sendkeluar yang nyata berhasil melalui wrapper yang persis sama sebelum mengaktifkan saluran. Jika Automation tidak dapat diberikan, konfigurasi ulang ke penyiapanimsgsatu 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 daribrew install steipete/tap/imsgbaru ditambah izin macOS standar di atas. - Mode private API:
imsgmenyuntikkan helper dylib keMessages.appuntuk memanggil fungsi internalIMCore. Ini membukareact,edit,unsend,reply(berutas),sendWithEffect,polldanpoll-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 keMessages.app.imsg launchmenolak 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.
Penyiapan
-
Instal (atau tingkatkan)
imsgdi Mac yang menjalankan Messages.app:bash brew install steipete/tap/imsgimsg --versionimsg status --jsonOutput
imsg status --jsonmelaporkanbridge_version,rpc_methods, danselectorsper metode sehingga Anda dapat melihat apa yang didukung build saat ini sebelum memulai. -
Nonaktifkan System Integrity Protection, dan (pada macOS modern) Library Validation. Menyuntikkan helper dylib non-Apple ke
Messages.appyang 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 disablesaja biasanya tidak cukup. Apple masih menerapkan validasi library terhadapMessages.appsebagai 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:bash sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool truemacOS 26 (Tahoe), diverifikasi pada 26.5.1: SIP dimatikan plus perintah
DisableLibraryValidationdi 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 launchmenyuntikkan danimsg statusmelaporkanadvanced_features: true. - Tanpa plist (bahkan dengan SIP dimatikan):
imsg launchgagal denganFailed 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.appdan bridge aktif; hapus plist dan reboot, laluimsg launchmenghasilkan kegagalan timeout di atas dengan dylib tidak dipetakan.Jika injeksi
imsg launchatauselectorstertentu 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, kumpulkanimsg status --jsonbeserta keluaranimsg launchdan laporkan ke proyekimsg, bukan melemahkan kontrol keamanan tambahan di seluruh sistem.Ikuti alur mode Recovery Apple untuk Mac Anda guna menonaktifkan SIP sebelum menjalankan
imsg launch. - macOS 10.13-10.15 (Sierra-Catalina): nonaktifkan Library Validation melalui Terminal, reboot ke Recovery Mode, jalankan
-
Injeksikan helper. Dengan SIP dinonaktifkan dan Messages.app sudah masuk:
bash imsg launchimsg launchmenolak melakukan injeksi ketika SIP masih aktif, jadi ini juga berfungsi sebagai konfirmasi bahwa langkah 2 berhasil. -
Verifikasi bridge dari OpenClaw:
bash openclaw channels status --probeEntri iMessage seharusnya melaporkan
works, danimsg status --json | jq '{rpc_methods, selectors}'seharusnya menampilkan kapabilitas yang diekspos oleh build macOS Anda. Pembuatan polling memerlukanselectors.pollPayloadMessage; voting memerlukanselectors.pollVoteMessagedan metode RPCpoll.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:
imsgkembali 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
DM policy
channels.imessage.dmPolicy mengontrol pesan langsung:
pairing(default)allowlistopen(memerlukanallowFromuntuk 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.
Group policy + mentions
channels.imessage.groupPolicy mengontrol penanganan grup:
allowlist(default saat dikonfigurasi)opendisabled
Allowlist pengirim grup: channels.imessage.groupAllowFrom.
Entri groupAllowFrom juga dapat mereferensikan grup akses pengirim statis (accessGroup:<name>).
Fallback runtime: jika groupAllowFrom tidak diatur, pemeriksaan pengirim grup iMessage menggunakan allowFrom; atur groupAllowFrom ketika penerimaan DM dan grup harus berbeda.
Catatan runtime: jika channels.imessage sepenuhnya tidak ada, runtime kembali ke groupPolicy="allowlist" dan mencatat peringatan (meskipun channels.defaults.groupPolicy diatur).
Gate mention untuk grup:
- iMessage tidak memiliki metadata mention bawaan
- deteksi mention menggunakan pola regex (
agents.list[].groupChat.mentionPatterns, fallbackmessages.groupChat.mentionPatterns) - tanpa pola yang dikonfigurasi, gate mention tidak dapat ditegakkan
Perintah kontrol dari pengirim resmi dapat melewati gate mention di grup.
systemPrompt per grup:
Setiap entri di bawah channels.imessage.groups.* menerima string systemPrompt opsional. Nilai tersebut disuntikkan ke prompt sistem agen pada setiap turn yang menangani pesan di grup tersebut. Resolusi mencerminkan resolusi prompt per grup yang digunakan oleh channels.whatsapp.groups:
- Prompt sistem khusus grup (
groups["<chat_id>"].systemPrompt): digunakan ketika entri grup tertentu ada di map dan kuncisystemPrompt-nya didefinisikan. JikasystemPromptadalah string kosong (""), wildcard ditekan dan tidak ada prompt sistem yang diterapkan ke grup tersebut. - Prompt sistem wildcard grup (
groups["*"].systemPrompt): digunakan ketika entri grup tertentu sepenuhnya tidak ada dari map, atau ketika entri itu ada tetapi tidak mendefinisikan kuncisystemPrompt.
{ 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: "", }, }, }, },}Prompt per grup hanya berlaku untuk pesan grup — pesan langsung di channel ini tidak terpengaruh.
Sessions and deterministic replies
- DM menggunakan routing langsung; grup menggunakan routing grup.
- Dengan
session.dmScope=maindefault, DM iMessage digabungkan ke sesi utama agen. - Sesi grup diisolasi (
agent:<agentId>:imessage:group:<chat_id>). - Balasan dirutekan kembali ke iMessage menggunakan metadata channel/target asal.
Perilaku thread yang mirip grup:
Beberapa thread iMessage multipeserta dapat datang dengan is_group=false.
Jika chat_id tersebut secara eksplisit dikonfigurasi di bawah channels.imessage.groups, OpenClaw memperlakukannya sebagai traffic grup (gate grup + isolasi sesi grup).
Binding percakapan ACP
Chat iMessage lama juga dapat diikat ke sesi ACP.
Alur operator cepat:
- Jalankan
/acp spawn codex --bind heredi dalam DM atau chat grup yang diizinkan. - Pesan berikutnya dalam percakapan iMessage yang sama dirutekan ke sesi ACP yang dibuat.
/newdan/resetmereset sesi ACP terikat yang sama di tempat./acp closemenutup 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
+15555550123atauuser@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
Dedicated bot macOS user (separate iMessage identity)
Gunakan Apple ID khusus dan pengguna macOS khusus agar traffic bot terisolasi dari profil Messages pribadi Anda.
Alur umum:
- Buat/masuk sebagai pengguna macOS khusus.
- Masuk ke Messages dengan Apple ID bot di pengguna tersebut.
- Instal
imsgdi pengguna tersebut. - Buat wrapper SSH agar OpenClaw dapat menjalankan
imsgdalam konteks pengguna tersebut. - Arahkan
channels.imessage.accounts.<id>.cliPathdan.dbPathke profil pengguna tersebut.
Eksekusi pertama mungkin memerlukan persetujuan GUI (Automation + Full Disk Access) di sesi pengguna bot tersebut.
Remote Mac over Tailscale (example)
Topologi umum:
- gateway berjalan di Linux/VM
- iMessage +
imsgberjalan di Mac dalam tailnet Anda - wrapper
cliPathmenggunakan SSH untuk menjalankanimsg remoteHostmengaktifkan 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 bashexec 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.
Multi-account pattern
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.
Direct-message history
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
Lampiran dan media
- penyerapan lampiran masuk nonaktif secara default — atur
channels.imessage.includeAttachments: trueuntuk 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 logInbound message. - jalur lampiran jarak jauh dapat diambil melalui SCP saat
remoteHostditetapkan - 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)
Pemotongan keluaran
- batas potongan teks:
channels.imessage.textChunkLimit(default 4000) - mode potongan:
channels.imessage.chunkModelength(default)newline(pemecahan yang mengutamakan paragraf)
Format pengalamatan
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 20Tindakan 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, }, }, },}Tindakan yang tersedia
- 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,textataumessage, ditambahchatGuid,chatId,chatIdentifier, atauto). - sendWithEffect: Mengirim teks dengan efek iMessage (
textataumessage,effectataueffectId). - edit: Mengedit pesan terkirim pada versi macOS/API privat yang didukung (
messageId,textataunewText). - unsend: Menarik kembali pesan terkirim pada versi macOS/API privat yang didukung (
messageId). - upload-file: Mengirim media/berkas (
buffersebagai base64 ataumedia/path/filePathyang telah dihidrasi,filename, opsionalasVoice). 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,pollOptiondiulang 2 hingga 12 kali, ditambahchatGuid,chatId,chatIdentifier, atauto). Penerima di iOS/iPadOS/macOS 26+ melihat dan memberikan suara secara native; versi OS lama menerima fallback teks "Sent a poll". Memerlukanselectors.pollPayloadMessage. - poll-vote: Memberikan suara pada polling yang sudah ada (
pollIdataumessageId, ditambah tepat salah satu daripollOptionIndex,pollOptionId, ataupollOptionText). Memerlukanselectors.pollVoteMessagedan metode RPCpoll.vote.
Polling masuk yang diterima dirender untuk agen dengan pertanyaan, label opsi bernomor, jumlah suara, dan ID pesan polling yang diperlukan oleh poll-vote.
ID Pesan
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.
Deteksi kapabilitas
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.
Tanda sudah dibaca dan mengetik
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.
Tapback masuk
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.
Reaksi persetujuan (👍 / 👎)
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) →denyallow-alwaystetap menjadi fallback manual: kirim/approve <id> allow-alwayssebagai 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:
- Pesan teks (
"Dump"). - 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.
Kapan mengaktifkan
Aktifkan saat:
- Anda mengirim Skills yang mengharapkan
command + payloaddalam 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.
Mengaktifkan
{ channels: { imessage: { coalesceSameSenderDms: true, // opt in (default: false) }, },}Dengan flag aktif dan tanpa messages.inbound.byChannel.imessage eksplisit atau messages.inbound.debounceMs global, jendela debounce melebar menjadi 7000 ms (default lama adalah 0 ms — tanpa debouncing). Jendela yang lebih lebar diperlukan karena irama split-send pratinjau URL Apple dapat memanjang hingga beberapa detik saat Messages.app memancarkan baris pratinjau.
Untuk menyesuaikan jendela sendiri:
{ messages: { inbound: { byChannel: { // 7000 ms covers observed Messages.app URL-preview delays. imessage: 7000, }, }, },}Trade-offs
- Penggabungan presisi membutuhkan metadata payload
imsgsaat ini. Saat baris URL menyertakanballoon_bundle_id, hanya split-send nyata itu yang digabungkan dan baris buffer lain tetap terpisah. Pada buildimsglama yang tidak mengekspos metadata balon, OpenClaw kembali menggabungkan bucket buffer agar split-sendDump <url>tidak mengalami regresi menjadi dua giliran (back-compat sementara, dihapus setelahimsgmenggabungkan split-send di upstream). - Latensi tambahan untuk pesan DM. Dengan flag aktif, setiap DM (termasuk perintah kontrol mandiri dan tindak lanjut teks tunggal) menunggu hingga jendela debounce sebelum dikirim, untuk berjaga-jaga jika baris pratinjau URL akan datang. Pesan obrolan grup tetap dikirim secara instan.
- Output gabungan dibatasi. Teks gabungan dibatasi hingga 4000 karakter dengan penanda eksplisit
…[truncated]; lampiran dibatasi hingga 20; entri sumber dibatasi hingga 10 (yang pertama-plus-terbaru dipertahankan setelah batas itu). Setiap GUID sumber dilacak dicoalescedMessageGuidsuntuk telemetri downstream. - Hanya DM. Obrolan grup diteruskan ke pengiriman per pesan agar bot tetap responsif saat beberapa orang sedang mengetik.
- Opt-in, per kanal. Kanal lain (Telegram, WhatsApp, Slack, …) tidak terpengaruh. Konfigurasi BlueBubbles lama yang mengatur
channels.bluebubbles.coalesceSameSenderDmsharus memigrasikan nilai itu kechannels.imessage.coalesceSameSenderDms.
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 menyusun | chat.db menghasilkan |
Flag nonaktif (default) | Flag aktif + jendela (imsg memancarkan metadata balon) |
|---|---|---|---|
Dump https://example.com (satu pengiriman) |
2 baris berjarak ~1 d | Dua giliran agen: "Dump" saja, lalu URL | Satu giliran: teks gabungan Dump https://example.com |
Save this 📎image.jpg caption (lampiran + teks) |
2 baris tanpa metadata balon URL | Dua giliran | Dua giliran setelah metadata teramati; satu giliran gabungan pada sesi lama/pra-latch tanpa metadata |
/status (perintah mandiri) |
1 baris | Pengiriman instan | Tunggu hingga jendela, lalu kirim |
| URL ditempel sendiri | 1 baris | Pengiriman instan | Tunggu hingga jendela, lalu kirim |
| Teks + URL dikirim sebagai dua pesan terpisah yang disengaja, terpaut menit | 2 baris di luar jendela | Dua giliran | Dua giliran (jendela kedaluwarsa di antaranya) |
| Banjir cepat (>10 DM kecil dalam jendela) | N baris tanpa metadata balon URL | N giliran | N giliran setelah metadata teramati; satu giliran gabungan terbatas pada sesi lama/pra-latch tanpa metadata |
| Dua orang mengetik di obrolan grup | N baris dari M pengirim | M+ 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.dbrowid terakhir yang dikirim (kursor per akun yang dipersistenkan) dan meneruskannya keimsg watch.subscribesebagaisince_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
imsg not found or RPC unsupported
Validasi binary dan dukungan RPC:
imsg rpc --helpimsg status --jsonopenclaw channels status --probeJika 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.
Messages send but inbound iMessages do not arrive
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 --jsonimsg watch --chat-id <chat-id> --jsonsqlite3 ~/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.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 restartKirim 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.
Gateway is not running on macOS
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 bashexec ssh -T messages-mac imsg "$@"Lalu jalankan:
openclaw channels status --probe --channel imessageDMs are ignored
Periksa:
channels.imessage.dmPolicychannels.imessage.allowFrom- persetujuan pairing (
openclaw pairing list imessage)
Group messages are ignored
Periksa:
channels.imessage.groupPolicychannels.imessage.groupAllowFrom- perilaku allowlist
channels.imessage.groups - konfigurasi pola mention (
agents.list[].groupChat.mentionPatterns)
Remote attachments fail
Periksa:
channels.imessage.remoteHostchannels.imessage.remoteAttachmentRoots- autentikasi kunci SSH/SCP dari host gateway
- kunci host ada di
~/.ssh/known_hostspada host gateway - keterbacaan path jarak jauh di Mac yang menjalankan Messages
macOS permission prompts were missed
Jalankan ulang di terminal GUI interaktif dalam konteks pengguna/sesi yang sama dan setujui prompt:
imsg chats --limit 1imsg send <handle> "test"Konfirmasi Full Disk Access + Automation diberikan untuk konteks proses yang menjalankan OpenClaw/imsg.
Penunjuk referensi konfigurasi
Terkait
- Ringkasan Kanal — semua kanal yang didukung
- Penghapusan BlueBubbles dan jalur imsg iMessage — pengumuman dan ringkasan migrasi
- Beralih dari BlueBubbles — tabel terjemahan konfigurasi dan cutover langkah demi langkah
- Pairing — autentikasi DM dan alur pairing
- Grup — perilaku obrolan grup dan gating mention
- Perutean Kanal — perutean sesi untuk pesan
- Keamanan — model akses dan hardening