Mainstream messaging
iMessage
Status: integração nativa com CLI externa. O Gateway inicia imsg rpc e se comunica por JSON-RPC via stdio — sem daemon ou porta separada. O modo de API privada é fortemente recomendado para um canal iMessage completo; respostas, tapbacks, efeitos, enquetes, respostas a anexos e ações de grupo exigem imsg launch e uma sondagem bem-sucedida da API privada.
Na configuração local comum, a configuração do OpenClaw pode oferecer, mediante confirmação do usuário, a instalação ou atualização do imsg pelo Homebrew no Mac com sessão iniciada no Mensagens. A configuração manual e as topologias com wrapper SSH continuam sendo gerenciadas pelo operador: instale ou atualize o imsg no mesmo contexto de usuário que executará o Gateway ou o wrapper.
Respostas, tapbacks, efeitos, enquetes, anexos e gerenciamento de grupos.
As mensagens diretas do iMessage usam o modo de pareamento por padrão.
Use um wrapper SSH quando o Gateway não estiver sendo executado no Mac do Mensagens.
Referência completa dos campos do iMessage.
Configuração rápida
Mac local (caminho rápido)
Instalar e verificar o imsg
brew install steipete/tap/imsgbrew update && brew upgrade imsgimsg rpc --helpimsg launchopenclaw channels status --probeQuando o assistente de configuração local detecta que o comando padrão imsg está ausente, ele pode solicitar a instalação de steipete/tap/imsg pelo Homebrew. Se detectar um imsg gerenciado pelo Homebrew, ele poderá solicitar sua reinstalação ou atualização. Wrappers personalizados de cliPath não são modificados.
Configurar o OpenClaw
{channels: {imessage: {enabled: true,cliPath: "/usr/local/bin/imsg",dbPath: "/Users/user/Library/Messages/chat.db",},},}Iniciar o Gateway
openclaw gatewayAprovar o pareamento da primeira mensagem direta (dmPolicy padrão)
openclaw pairing list imessageopenclaw pairing approve imessage <CODE>As solicitações de pareamento expiram após 1 hora.
Mac remoto por SSH
A maioria das configurações não precisa de SSH. Use esta topologia somente quando o Gateway não puder ser executado no Mac com sessão iniciada no Mensagens. O OpenClaw exige apenas um cliPath compatível com stdio; portanto, você pode apontar cliPath para um script wrapper que se conecte por SSH a um Mac remoto e execute o imsg.
Instale e atualize o imsg nesse Mac remoto, não no host do Gateway:
ssh messages-mac 'brew install steipete/tap/imsg && brew update && brew upgrade imsg'#!/usr/bin/env bashexec ssh -T messages-mac imsg "$@"Configuração recomendada quando os anexos estão habilitados:
{channels: {imessage: { enabled: true, cliPath: "~/.openclaw/scripts/imsg-ssh", remoteHost: "user@gateway-host", // usado para buscar anexos via SCP includeAttachments: true, // Opcional: raízes adicionais permitidas para anexos (combinadas com o padrão // /Users/*/Library/Messages/Attachments). attachmentRoots: ["/Users/*/Library/Messages/Attachments"], remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],},},}Se remoteHost não estiver definido, o OpenClaw tentará detectá-lo automaticamente analisando o script wrapper SSH.
remoteHost deve ser host ou user@host (sem espaços nem opções SSH); valores inseguros são ignorados.
O OpenClaw usa verificação estrita da chave do host para SCP, portanto a chave do host de retransmissão já deve existir em ~/.ssh/known_hosts.
Os caminhos dos anexos são validados em relação às raízes permitidas (attachmentRoots / remoteAttachmentRoots).
Requisitos e permissões (macOS)
- Deve haver uma sessão iniciada no Mensagens no Mac que executa o
imsg. - O Acesso Total ao Disco é obrigatório para o contexto do processo que executa o OpenClaw/
imsg(acesso ao banco de dados do Mensagens). - A permissão de Automação é obrigatória para enviar mensagens pelo Messages.app.
- Para ações avançadas (reagir / editar / cancelar envio / resposta em thread / efeitos / enquetes / operações de grupo), a Proteção de Integridade do Sistema deve ser desabilitada — consulte Habilitação da API privada do imsg. O envio e o recebimento básicos de texto e mídia funcionam sem isso.
Falha em envios pelo wrapper SSH com AppleEvents -1743
Uma configuração com SSH remoto pode ler conversas, passar por channels status --probe e processar mensagens de entrada, enquanto os envios ainda falham com um erro de autorização do AppleEvents:
Não autorizado a enviar eventos Apple para o Mensagens. (-1743)Verifique o banco de dados TCC do usuário com sessão iniciada no Mac ou System Settings > Privacy & Security > Automation. Se a entrada de Automação estiver registrada para /usr/libexec/sshd-keygen-wrapper em vez do processo imsg ou do shell local, o macOS poderá não disponibilizar um controle utilizável do Mensagens para esse cliente SSH no lado do servidor:
kTCCServiceAppleEvents | /usr/libexec/sshd-keygen-wrapper | auth_value=0 | com.apple.MobileSMSNesse estado, repetir tccutil reset AppleEvents ou executar novamente imsg send pelo mesmo wrapper SSH pode continuar falhando, pois o contexto do processo que precisa da Automação do Mensagens é o wrapper SSH, não um aplicativo ao qual a interface possa conceder a permissão.
Use um dos contextos de processo compatíveis com o imsg:
- Execute o Gateway, ou pelo menos a ponte do
imsg, na sessão local do usuário com login no Mensagens. - Inicie o Gateway com um LaunchAgent para esse usuário após conceder Acesso Total ao Disco e Automação na mesma sessão.
- Se mantiver a topologia SSH com dois usuários, verifique se um envio real com
imsg sendé bem-sucedido pelo wrapper exato antes de habilitar o canal. Se não for possível conceder Automação a ele, reconfigure para uma instalação doimsgcom um único usuário, em vez de depender do wrapper SSH para envios.
Habilitação da API privada do imsg
O imsg é fornecido em dois modos operacionais. Para o OpenClaw, o modo de API privada é a configuração recomendada, pois fornece ao canal as ações nativas do iMessage esperadas pelos usuários. O modo básico continua sendo útil para instalações de baixo risco, verificação inicial ou hosts nos quais o SIP não pode ser desabilitado.
- Modo básico (padrão, nenhuma alteração no SIP é necessária): envio de texto e mídia por meio de
send, monitoramento/histórico de entrada e lista de conversas. Isso é o que se obtém imediatamente após uma nova execução debrew install steipete/tap/imsg, além das permissões padrão do macOS descritas acima. - Modo de API privada: o
imsginjeta uma dylib auxiliar noMessages.apppara chamar funções internas doIMCore. Isso liberareact,edit,unsend,reply(em thread),sendWithEffect,pollepoll-vote(enquetes nativas do Mensagens),renameGroup,setGroupIcon,addParticipant,removeParticipant,leaveGroup, além de indicadores de digitação e confirmações de leitura.
A superfície de ações recomendada nesta página exige o modo de API privada. O README do imsg é explícito quanto ao requisito:
Recursos avançados como
read,typing,launch, envio avançado apoiado pela ponte, alteração de mensagens e gerenciamento de conversas são opcionais. Eles exigem que o SIP esteja desabilitado e que uma dylib auxiliar seja injetada noMessages.app.imsg launchse recusa a realizar a injeção quando o SIP está habilitado.
A técnica de injeção do auxiliar usa a própria dylib do imsg para acessar as APIs privadas do Mensagens. Não há servidor de terceiros nem runtime do BlueBubbles no caminho do iMessage no OpenClaw.
Configuração
-
Instale (ou atualize) o
imsgno Mac que executa o Messages.app:bash brew install steipete/tap/imsgbrew update && brew upgrade imsgimsg --versionimsg status --jsonA saída de
imsg status --jsoninformabridge_version,rpc_methodse osselectorsde cada método, para que você possa ver o que a compilação atual oferece antes de começar. -
Desabilite a Proteção de Integridade do Sistema e, no macOS moderno, a Validação de Biblioteca. A injeção de uma dylib auxiliar que não seja da Apple no
Messages.app, assinado pela Apple, exige que o SIP esteja desativado e que a validação de biblioteca esteja flexibilizada. A etapa do SIP no modo de Recuperação é específica de cada versão do macOS:- macOS 10.13-10.15 (Sierra-Catalina): desabilite a Validação de Biblioteca pelo Terminal, reinicie no modo de Recuperação, execute
csrutil disablee reinicie. - macOS 11+ (Big Sur e posteriores), Intel: entre no modo de Recuperação (ou Recuperação pela Internet), execute
csrutil disablee reinicie. - macOS 11+, Apple Silicon: use a sequência de inicialização pelo botão liga/desliga para entrar na Recuperação; nas versões recentes do macOS, mantenha pressionada a tecla Left Shift ao clicar em Continue e, em seguida, execute
csrutil disable. Configurações de máquina virtual seguem um fluxo separado; portanto, primeiro crie um snapshot da VM.
No macOS 11 e posterior, apenas
csrutil disablegeralmente não é suficiente. A Apple ainda impõe a validação de bibliotecas para oMessages.appcomo um binário da plataforma; por isso, um auxiliar assinado de forma ad hoc é rejeitado (Library Validation failed: ... platform binary, but mapped file is not) mesmo com o SIP desativado. Após desativar o SIP, desative também a validação de bibliotecas e reinicie:bash sudo defaults write /Library/Preferences/com.apple.security.libraryvalidation.plist DisableLibraryValidation -bool truemacOS 26 (Tahoe), verificado na versão 26.5.1: o SIP desativado mais o comando
DisableLibraryValidationacima são suficientes para injetar o auxiliar nas versões 26.0 a 26.5.x. Nenhum boot-arg é necessário. O plist é o fator decisivo e a etapa ausente mais comum quando a injeção falha no Tahoe:- Com o plist:
imsg launchfaz a injeção eimsg statusinformaadvanced_features: true. - Sem o plist (mesmo com o SIP desativado):
imsg launchfalha comFailed to launch: Timeout waiting for Messages.app to initialize. O AMFI rejeita o auxiliar ad hoc durante o carregamento, portanto a ponte nunca fica pronta e a inicialização atinge o tempo limite. Esse tempo limite é o sintoma que a maioria das pessoas encontra no Tahoe; a correção é o plist acima, não algo mais drástico.
Se a injeção por
imsg launchouselectorsespecíficos começarem a retornar falso após uma atualização do macOS, essa barreira geralmente é a causa. Verifique o estado do SIP e da validação de bibliotecas antes de presumir que a própria etapa do SIP falhou. Se essas configurações estiverem corretas e a ponte ainda não conseguir fazer a injeção, coleteimsg status --jsonjunto com a saída deimsg launche reporte ao projetoimsg, em vez de enfraquecer outros controles de segurança de todo o sistema. - macOS 10.13-10.15 (Sierra-Catalina): desabilite a Validação de Biblioteca pelo Terminal, reinicie no modo de Recuperação, execute
-
Injete o auxiliar. Com o SIP desativado e a sessão iniciada no Messages.app:
bash imsg launchimsg launchse recusa a fazer a injeção quando o SIP ainda está ativado; portanto, isso também serve como confirmação de que a etapa 2 foi efetivada. -
Verifique a ponte pelo OpenClaw:
bash openclaw channels status --probeA entrada do iMessage deve informar
works, eimsg status --json | jq '{rpc_methods, selectors}'deve mostrar os recursos expostos pela sua compilação do macOS. A criação de enquetes exigeselectors.pollPayloadMessage; a votação exige tantoselectors.pollVoteMessagequanto o método RPCpoll.vote. O Plugin do OpenClaw anuncia somente as ações compatíveis com a sondagem armazenada em cache, enquanto um cache vazio permanece otimista e faz a sondagem no primeiro envio.
Se openclaw channels status --probe informar o canal como works, mas ações específicas gerarem "iMessage <action> requires the imsg private API bridge" no momento do envio, execute imsg launch novamente — o auxiliar pode ser desconectado (reinicialização do Messages.app, atualização do sistema operacional etc.), e o estado available: true armazenado em cache continuará anunciando ações até que a próxima sondagem o atualize.
Quando o SIP permanece ativado
Se desativar o SIP não for aceitável para o seu modelo de ameaças:
- O
imsgvolta ao modo básico — somente texto + mídia + recebimento. - O Plugin do OpenClaw ainda anuncia o envio de texto/mídia e o monitoramento de mensagens recebidas; ele oculta
react,edit,unsend,reply,sendWithEffecte operações de grupo da superfície de ações (de acordo com a barreira de recursos por método). - Você pode executar um Mac separado sem Apple Silicon (ou um Mac dedicado ao bot) com o SIP desativado para a carga de trabalho do iMessage, mantendo o SIP ativado nos seus dispositivos principais. Consulte Usuário dedicado do macOS para o bot (identidade separada do iMessage) abaixo.
Controle de acesso e roteamento
Política de mensagens diretas
channels.imessage.dmPolicy controla as mensagens diretas:
pairing(padrão)allowlist(exige pelo menos uma entrada emallowFrom)open(exige queallowFrominclua"*")disabled
Campo da lista de permissões: channels.imessage.allowFrom.
As entradas da lista de permissões devem identificar remetentes: identificadores ou grupos estáticos de acesso de remetentes (accessGroup:<name>). Use channels.imessage.groupAllowFrom para destinos de conversa como chat_id:*, chat_guid:* ou chat_identifier:*; use channels.imessage.groups para chaves numéricas chat_id do registro.
Política de grupos + menções
channels.imessage.groupPolicy controla o tratamento de grupos:
allowlist(padrão)opendisabled
Lista de permissões de remetentes de grupos: channels.imessage.groupAllowFrom.
As entradas de groupAllowFrom também podem referenciar grupos estáticos de acesso de remetentes (accessGroup:<name>).
Comportamento alternativo em tempo de execução: se groupAllowFrom não estiver definido, as verificações de remetentes de grupos do iMessage usarão allowFrom; defina groupAllowFrom quando a admissão de mensagens diretas e de grupos precisar ser diferente. Um groupAllowFrom: [] explicitamente vazio não usa o comportamento alternativo — ele bloqueia todos os remetentes de grupos em allowlist.
Observação sobre o tempo de execução: se channels.imessage estiver completamente ausente, o tempo de execução usará groupPolicy="allowlist" e registrará um aviso (mesmo que channels.defaults.groupPolicy esteja definido).
Barreira de menções para grupos:
- o iMessage não possui metadados nativos de menções
- a detecção de menções usa padrões de expressões regulares (
agents.list[].groupChat.mentionPatterns, com comportamento alternativo pormessages.groupChat.mentionPatterns) - sem padrões configurados, a barreira de menções não pode ser aplicada
- comandos de controle enviados por remetentes autorizados ignoram a barreira de menções
systemPrompt por grupo:
Cada entrada em channels.imessage.groups.* aceita uma string opcional systemPrompt, injetada no prompt de sistema do agente em cada turno que processa uma mensagem desse grupo. A resolução espelha channels.whatsapp.groups:
- Prompt de sistema específico do grupo (
groups["<chat_id>"].systemPrompt): usado quando a entrada específica do grupo existe no mapa e sua chavesystemPromptestá definida. SesystemPromptfor uma string vazia (""), o curinga será suprimido e nenhum prompt de sistema será aplicado a esse grupo. - Prompt de sistema curinga do grupo (
groups["*"].systemPrompt): usado quando a entrada específica do grupo está totalmente ausente do mapa ou quando existe, mas não define nenhuma chavesystemPrompt.
{ channels: { imessage: { groupPolicy: "allowlist", groupAllowFrom: ["+15555550123"], groups: { "*": { systemPrompt: "Use a ortografia britânica." }, "8421": { requireMention: true, systemPrompt: "Esta é a conversa da escala de plantão. Mantenha as respostas com menos de 3 frases.", }, "9907": { // supressão explícita: o curinga "Use a ortografia britânica." não se aplica aqui systemPrompt: "", }, }, }, },}Os prompts por grupo se aplicam somente a mensagens de grupos — as mensagens diretas não são afetadas.
Sessões e respostas determinísticas
- As mensagens diretas usam roteamento direto; os grupos usam roteamento de grupo.
- Com o padrão
session.dmScope=main, as mensagens diretas do iMessage são consolidadas na sessão principal do agente. - As sessões de grupos são isoladas (
agent:<agentId>:imessage:group:<chat_id>). - As respostas são encaminhadas de volta ao iMessage usando os metadados do canal/destino de origem.
Comportamento de threads semelhantes a grupos:
Algumas threads do iMessage com vários participantes podem chegar com is_group=false.
Se esse chat_id estiver configurado explicitamente em channels.imessage.groups, o OpenClaw o tratará como tráfego de grupo (barreira de grupo + isolamento da sessão de grupo).
Vínculos de conversas ACP
As conversas do iMessage podem ser vinculadas a sessões ACP.
Fluxo rápido para o operador:
- Execute
/acp spawn codex --bind heredentro da mensagem direta ou da conversa de grupo permitida. - As mensagens futuras nessa mesma conversa do iMessage serão encaminhadas para a sessão ACP criada.
/newe/resetredefinem no local a mesma sessão ACP vinculada./acp closefecha a sessão ACP e remove o vínculo.
Os vínculos persistentes configurados usam entradas bindings[] de nível superior com type: "acp" e match.channel: "imessage".
match.peer.id pode usar:
- identificador normalizado de mensagem direta, como
+15555550123ouuser@example.com chat_id:<id>(recomendado para vínculos estáveis de grupos)chat_guid:<guid>chat_identifier:<identifier>
Exemplo:
{ 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" }, }, ],}Consulte Agentes ACP para saber mais sobre o comportamento compartilhado dos vínculos ACP.
Padrões de implantação
Usuário dedicado do macOS para o bot (identidade separada do iMessage)
Use um Apple ID e um usuário do macOS dedicados para que o tráfego do bot fique isolado do seu perfil pessoal do Messages.
Fluxo típico:
- Crie um usuário dedicado do macOS e inicie a sessão nele.
- Nesse usuário, inicie uma sessão no Messages com o Apple ID do bot.
- Instale o
imsgnesse usuário. - Crie um wrapper SSH para que o OpenClaw possa executar o
imsgno contexto desse usuário. - Aponte
channels.imessage.accounts.<id>.cliPathe.dbPathpara o perfil desse usuário.
A primeira execução pode exigir aprovações pela interface gráfica (Automation + Full Disk Access) na sessão de usuário do bot.
Mac remoto por Tailscale (exemplo)
Topologia comum:
- o Gateway é executado no Linux/VM
- o iMessage +
imsgsão executados em um Mac na sua tailnet - o wrapper
cliPathusa SSH para executar oimsg remoteHostpermite buscar anexos por SCP
Exemplo:
{ 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 "$@"Use chaves SSH para que tanto o SSH quanto o SCP sejam não interativos.
Primeiro, certifique-se de que a chave do host seja confiável (por exemplo, ssh bot@mac-mini.tailnet-1234.ts.net) para que known_hosts seja preenchido.
Padrão de múltiplas contas
O iMessage oferece suporte à configuração por conta em channels.imessage.accounts.
Cada conta pode substituir campos como cliPath, dbPath, allowFrom, groupPolicy, mediaMaxMb, configurações de histórico e listas de permissões de raízes de anexos.
Histórico de mensagens diretas
Defina channels.imessage.dmHistoryLimit para preencher novas sessões de mensagens diretas com o histórico recente de imsg decodificado dessa conversa. Use channels.imessage.dms["<sender>"].historyLimit para substituições por remetente, incluindo 0 para desativar o histórico de um remetente.
O histórico de MDs do iMessage é obtido sob demanda do imsg. Deixar dmHistoryLimit sem definição desativa o preenchimento global do histórico de MDs, mas um valor positivo de channels.imessage.dms["<sender>"].historyLimit por remetente ainda ativa o preenchimento para esse remetente.
Mídia, divisão em blocos e destinos de entrega
Anexos e mídia
- a ingestão de anexos recebidos fica desativada por padrão — defina
channels.imessage.includeAttachments: truepara encaminhar fotos, mensagens de voz, vídeos e outros anexos ao agente. Com essa opção desativada, iMessages que contêm apenas anexos são descartadas antes de chegar ao agente e podem não produzir nenhuma linha de logInbound message. - caminhos de anexos remotos podem ser obtidos via SCP quando
remoteHostestá definido - os caminhos de anexos devem corresponder às raízes permitidas:
channels.imessage.attachmentRoots(local)channels.imessage.remoteAttachmentRoots(modo SCP remoto)- as raízes configuradas estendem o padrão de raiz predefinido
/Users/*/Library/Messages/Attachments(são mescladas, não substituídas)
- o SCP usa verificação estrita da chave do host (
StrictHostKeyChecking=yes) - o tamanho da mídia de saída usa
channels.imessage.mediaMaxMb(padrão de 16 MB)
Texto de saída e divisão em blocos
- limite do bloco de texto:
channels.imessage.textChunkLimit(padrão de 4000) - modo de divisão em blocos:
channels.imessage.streaming.chunkModelength(padrão)newline(divisão priorizando parágrafos)
- negrito/itálico/sublinhado/tachado em Markdown na saída é convertido em texto estilizado nativo (destinatários no macOS 15+ renderizam a estilização; destinatários em versões anteriores veem texto simples sem os marcadores); tabelas Markdown são convertidas de acordo com o modo de tabelas Markdown do canal
channels.imessage.sendTransport(autopor padrão,bridge,applescript) seleciona como oimsgrealiza os envios
Formatos de endereçamento
Destinos explícitos preferenciais:
chat_id:123(recomendado para roteamento estável)chat_guid:...chat_identifier:...
Destinos por identificador também são compatíveis:
imessage:+1555...sms:+1555...user@example.com
imsg chats --limit 20Ações da API privada
Quando imsg launch está em execução e openclaw channels status --probe informa privateApi.available: true, a ferramenta de mensagens pode usar ações nativas do iMessage além dos envios normais de texto.
Todas as ações ficam ativadas por padrão; use channels.imessage.actions para desativar ações individuais:
{ 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, }, }, },}Ações disponíveis
- react: Adiciona/remove tapbacks do iMessage (
messageId,emoji,remove). Os tapbacks compatíveis correspondem a amar, curtir, não curtir, rir, enfatizar e questionar. A remoção sem um emoji limpa qualquer tapback que esteja definido. - reply: Envia uma resposta encadeada a uma mensagem existente (
messageId,textoumessage, maischatGuid,chatId,chatIdentifierouto). A resposta com anexo também exige uma compilação doimsgcujosend-richseja compatível com--file. - sendWithEffect: Envia texto com um efeito do iMessage (
textoumessage,effectoueffectId). Nomes curtos: slam, loud, gentle, invisibleink, confetti, lasers, fireworks, balloon, heart, echo, happybirthday, shootingstar, sparkles, spotlight. - edit: Edita uma mensagem enviada em versões compatíveis do macOS/API privada (
messageId,textounewText). Somente mensagens enviadas pelo próprio gateway podem ser editadas. - unsend: Retira uma mensagem enviada em versões compatíveis do macOS/API privada (
messageId). Somente mensagens enviadas pelo próprio gateway podem ter o envio desfeito. - upload-file: Envia mídia/arquivos (
buffercomo base64 ou ummedia/path/filePathcarregado,filename,asVoiceopcional). Alias legado:sendAttachment. - renameGroup, setGroupIcon, addParticipant, removeParticipant, leaveGroup: Gerenciam conversas em grupo quando o destino atual é uma conversa em grupo. Essas ações alteram a identidade do app Mensagens no host, portanto exigem um remetente proprietário ou um cliente Gateway
operator.admin. - poll: Cria uma enquete nativa do app Mensagens da Apple (
pollQuestion,pollOptionrepetido de 2 a 12 vezes, maischatGuid,chatId,chatIdentifierouto). Destinatários no iOS/iPadOS/macOS 26+ a veem e votam nela de forma nativa; versões anteriores do sistema operacional recebem um texto alternativo "Enquete enviada". Exigeselectors.pollPayloadMessage. - poll-vote: Vota em uma enquete existente (
pollIdoumessageId, mais exatamente um entrepollOptionIndex,pollOptionIdoupollOptionText). Exigeselectors.pollVoteMessagee o método RPCpoll.vote.
As enquetes recebidas e aceitas são renderizadas para o agente com a pergunta, os rótulos numerados das opções, as contagens de votos e o ID da mensagem da enquete necessário para poll-vote.
IDs de mensagens
O contexto de entrada do iMessage inclui tanto valores curtos de MessageSid quanto GUIDs completos de mensagens (MessageSidFull), quando disponíveis. IDs curtos têm o escopo limitado ao cache recente de respostas baseado em SQLite e são verificados em relação à conversa atual antes do uso. Se um ID curto tiver expirado ou pertencer a outra conversa, tente novamente com o MessageSidFull completo.
Detecção de recursos
O OpenClaw oculta as ações da API privada somente quando o status da sondagem em cache indica que a ponte está indisponível. Se o status for desconhecido, as ações permanecem visíveis e o envio executa sondagens de forma tardia, permitindo que a primeira ação tenha êxito após imsg launch sem uma atualização manual separada do status.
Confirmações de leitura e digitação
Quando a ponte da API privada está ativa, as conversas recebidas e aceitas são marcadas como lidas, e as conversas diretas exibem um balão de digitação assim que o turno é aceito, enquanto o agente prepara o contexto e gera a resposta. Desative a marcação como lida com:
{ channels: { imessage: { sendReadReceipts: false, }, },}Compilações antigas do imsg, anteriores à lista de recursos por método, desativam silenciosamente a digitação/leitura; o OpenClaw registra um aviso uma vez a cada reinicialização para que seja possível atribuir a ausência da confirmação.
Tapbacks recebidos
O OpenClaw assina os tapbacks do iMessage e encaminha as reações aceitas como eventos do sistema, em vez de texto de mensagem normal, para que o tapback de um usuário não acione um ciclo comum de respostas.
O modo de notificação é controlado por channels.imessage.reactionNotifications:
"own"(padrão): notifica somente quando usuários reagem a mensagens criadas pelo bot."all": notifica sobre todos os tapbacks recebidos de remetentes autorizados."off": ignora tapbacks recebidos.
Substituições por conta usam channels.imessage.accounts.<id>.reactionNotifications.
Reações de aprovação (👍 / 👎)
Quando approvals.exec.enabled ou approvals.plugin.enabled é verdadeiro e a solicitação é encaminhada ao iMessage, o gateway entrega uma solicitação de aprovação de forma nativa e aceita um tapback para resolvê-la:
👍(tapback Like) →allow-once👎(tapback Dislike) →denyallow-alwayspermanece como alternativa manual: envie/approve <id> allow-alwayscomo uma resposta comum.
O processamento da reação exige que o identificador do usuário que reagiu seja de um aprovador explícito. A lista de aprovadores é lida de channels.imessage.allowFrom (ou channels.imessage.accounts.<id>.allowFrom); adicione o número de telefone do usuário no formato E.164 ou o e-mail do ID Apple dele (destinos de conversa como chat_id:* não são entradas válidas de aprovadores). A entrada curinga "*" é respeitada, mas permite que qualquer remetente aprove; uma lista de aprovadores vazia desativa completamente o atalho de reação. O atalho de reação ignora intencionalmente reactionNotifications, dmPolicy e groupAllowFrom, pois a lista de permissões de aprovadores explícitos é a única verificação relevante para resolver a aprovação.
A autorização do comando de texto /approve segue a mesma lista: quando channels.imessage.allowFrom não está vazio, /approve <id> <decision> é autorizado com base nessa lista de aprovadores (não na lista de permissões mais ampla de MDs), e remetentes permitidos na lista de permissões de MDs, mas ausentes de allowFrom, recebem uma recusa explícita. Quando allowFrom está vazio, a alternativa da mesma conversa permanece em vigor, e /approve autoriza qualquer pessoa permitida pela lista de permissões de MDs. Adicione a allowFrom todos os operadores que devam aprovar — via /approve ou por reações.
Observações para operadores:
- A associação da reação é armazenada tanto na memória quanto no armazenamento persistente com chaves do gateway (com TTL correspondente à expiração da aprovação), e o gateway também consulta periodicamente as solicitações pendentes em busca de tapbacks; portanto, um tapback recebido pouco depois da reinicialização do gateway ainda resolve a aprovação.
- O tapback
is_from_me=truedo próprio operador (por exemplo, de um dispositivo Apple emparelhado) resolve a aprovação quando esse identificador pertence a um aprovador explícito. - As solicitações de aprovação só são encaminhadas a uma conversa em grupo quando aprovadores explícitos estão configurados; caso contrário, qualquer membro do grupo poderia aprovar.
- Tapbacks legados em formato de texto (
Liked "…"como texto simples de clientes Apple muito antigos) não podem resolver aprovações porque não contêm GUID de mensagem; a resolução por reação exige os metadados estruturados de tapback emitidos pelos clientes atuais do macOS/iOS.
Gravações de configuração
O iMessage permite por padrão gravações de configuração iniciadas pelo canal (para /config set|unset quando commands.config: true).
Para desativar:
{ channels: { imessage: { configWrites: false, }, },}Agregação de MDs divididas no envio (comando + URL em uma única composição)
Quando um usuário digita um comando e uma URL juntos — por exemplo, Dump https://example.com/article — o app Mensagens da Apple divide o envio em duas linhas separadas de chat.db:
- Uma mensagem de texto (
"Dump"). - Um balão de pré-visualização de URL (
"https://...") com imagens de pré-visualização OG como anexos.
As duas linhas chegam ao OpenClaw com um intervalo de aproximadamente 0.8-2.0 s na maioria das configurações. Sem a agregação, o agente recebe apenas o comando no turno 1 (e frequentemente responde "envie-me a URL") antes de a URL chegar no turno 2. Isso faz parte do pipeline de envio da Apple, não é algo introduzido pelo OpenClaw ou pelo imsg.
channels.imessage.coalesceSameSenderDms habilita o armazenamento em buffer de linhas consecutivas do mesmo remetente em uma DM. Quando o imsg expõe o marcador estrutural de prévia de URL balloon_bundle_id: "com.apple.messages.URLBalloonProvider" em uma das linhas de origem, o OpenClaw mescla apenas esse envio realmente dividido e mantém quaisquer outras linhas armazenadas em buffer como turnos separados. Em versões mais antigas do imsg que não emitem nenhum metadado de balão, o OpenClaw não consegue distinguir um envio dividido de envios separados e, portanto, recorre à mesclagem do agrupamento. Isso preserva o comportamento anterior aos metadados, em vez de regredir envios divididos de Dump <url> para dois turnos. Os chats em grupo continuam sendo despachados por mensagem para preservar a estrutura de turnos com vários usuários.
Quando habilitar
Habilite quando:
- Você distribui Skills que esperam
command + payloadem uma única mensagem (despejar, colar, salvar, enfileirar etc.). - Seus usuários colam URLs junto com comandos.
- Você pode aceitar a latência adicional nos turnos de DM (veja abaixo).
Deixe desabilitado quando:
- Você precisa de latência mínima para comandos acionados por uma única palavra em DMs.
- Todos os seus fluxos são comandos de execução única, sem cargas adicionais posteriores.
Habilitação
{ channels: { imessage: { coalesceSameSenderDms: true, // habilitação opcional (padrão: false) }, },}Com o sinalizador ativado e sem um messages.inbound.byChannel.imessage explícito nem um messages.inbound.debounceMs global, a janela de debounce aumenta para 7000 ms (o padrão legado é 0 ms — sem debounce). A janela mais ampla é necessária porque o intervalo entre envios divididos da prévia de URL da Apple pode chegar a vários segundos enquanto o Messages.app emite a linha da prévia.
Para ajustar a janela por conta própria:
{ messages: { inbound: { byChannel: { // 7000 ms abrangem os atrasos observados nas prévias de URL do Messages.app. imessage: 7000, }, }, },}Implicações
- A mesclagem precisa exige metadados atuais da carga do
imsg. Comballoon_bundle_idpresente, apenas o envio realmente dividido é mesclado; a mesclagem de contingência sem metadados descrita acima é uma compatibilidade retroativa temporária, removida quando oimsgpassar a aglutinar os envios divididos na origem. - Latência adicional para mensagens de DM. Com o sinalizador ativado, toda DM (incluindo comandos de controle independentes e mensagens posteriores com um único texto) aguarda até o limite da janela de debounce antes de ser despachada, caso uma linha de prévia de URL esteja a caminho. As mensagens de chats em grupo mantêm o despacho imediato.
- A saída mesclada é limitada. O texto mesclado é limitado a 4000 caracteres, com um marcador explícito
…[truncated]; os anexos são limitados a 20; as entradas de origem são limitadas a 10 (além disso, a primeira e as mais recentes são mantidas). Cada GUID de origem é registrado emcoalescedMessageGuidspara telemetria posterior. - Somente DMs. Os chats em grupo seguem para o despacho por mensagem, para que o bot permaneça responsivo quando várias pessoas estiverem digitando.
- Opcional, por canal. Outros canais (Discord, Slack, Telegram, WhatsApp, …) não são afetados. Configurações legadas do BlueBubbles que definem
channels.bluebubbles.coalesceSameSenderDmsdevem migrar esse valor parachannels.imessage.coalesceSameSenderDms.
Cenários e o que o agente vê
A coluna "Sinalizador ativado" mostra o comportamento em uma versão do imsg que emite balloon_bundle_id. Em versões mais antigas do imsg que não emitem nenhum metadado de balão, as linhas abaixo marcadas como "Dois turnos"/"N turnos" recorrem a uma mesclagem legada (um turno): o OpenClaw não consegue distinguir estruturalmente um envio dividido de envios separados e, portanto, preserva a mesclagem anterior aos metadados. A separação precisa é ativada assim que a versão passa a emitir metadados de balão.
| O usuário redige | chat.db produz |
Sinalizador desativado (padrão) | Sinalizador ativado + janela (imsg emite metadados de balão) |
|---|---|---|---|
Dump https://example.com (um envio) |
2 linhas com intervalo de ~1 s | Dois turnos do agente: apenas "Dump", depois URL | Um turno: texto mesclado Dump https://example.com |
Save this 📎image.jpg caption (anexo + texto) |
2 linhas sem metadados de balão de URL | Dois turnos | Dois turnos após a observação dos metadados; um turno mesclado em sessões antigas/pré-travamento sem metadados |
/status (comando independente) |
1 linha | Despacho imediato | Aguarda até o limite da janela e então despacha |
| URL colada sozinha | 1 linha | Despacho imediato | Aguarda até o limite da janela e então despacha |
| Texto + URL enviados deliberadamente como duas mensagens separadas, com minutos de intervalo | 2 linhas fora da janela | Dois turnos | Dois turnos (a janela expira entre eles) |
| Rajada rápida (>10 DMs pequenas dentro da janela) | N linhas sem metadados de balão de URL | N turnos | N turnos após a observação dos metadados; um turno mesclado e limitado em sessões antigas/pré-travamento sem metadados |
| Duas pessoas digitando em um chat em grupo | N linhas de M remetentes | M+ turnos (um por agrupamento de remetente) | M+ turnos — chats em grupo não são aglutinados |
Recuperação de entrada após a reinicialização de uma ponte ou do Gateway
O iMessage recupera mensagens perdidas enquanto o Gateway estava inativo e, ao mesmo tempo, suprime a "bomba de mensagens pendentes" obsoletas que a Apple pode descarregar após uma recuperação de Push. O comportamento padrão está sempre ativado e é baseado na desduplicação de entrada.
- Desduplicação de repetição. Cada mensagem de entrada despachada é registrada por seu GUID da Apple no estado persistente do Plugin (
imessage.inbound-dedupe), reivindicada durante a ingestão e confirmada após o processamento (liberada em caso de falha transitória para permitir uma nova tentativa). Tudo o que já foi processado é descartado, em vez de ser despachado duas vezes. Isso permite que a recuperação repita as mensagens de forma agressiva sem manter registros individuais por mensagem. - Recuperação do período de inatividade. Na inicialização, o monitor memoriza o último rowid despachado do
chat.db(um cursor persistente por conta) e o passa paraimsg watch.subscribecomosince_rowid, para que o imsg repita as linhas recebidas enquanto o Gateway estava inativo e, em seguida, acompanhe as novas linhas em tempo real. A repetição é limitada às 500 linhas mais recentes e a mensagens com até ~2 horas, enquanto a desduplicação descarta tudo o que já tiver sido processado. - Limite de idade para mensagens pendentes obsoletas. As linhas acima do limite de inicialização são realmente novas; uma linha cuja data de envio seja mais de ~15 minutos anterior à chegada pertence às mensagens pendentes descarregadas pelo Push e é suprimida. As linhas repetidas (no limite ou abaixo dele) usam a janela de recuperação mais ampla, para que uma mensagem perdida recentemente seja entregue sem incluir o histórico antigo.
A recuperação funciona tanto em configurações locais quanto remotas de cliPath, porque a repetição de since_rowid ocorre pela mesma conexão RPC do imsg. A diferença é a janela: quando o Gateway consegue ler o chat.db (localmente), ele ancora o limite do rowid de inicialização, restringe o intervalo da repetição e entrega mensagens perdidas com até algumas horas. Por meio de um cliPath SSH remoto, ele não consegue ler o banco de dados; portanto, a repetição não é limitada e todas as linhas usam o limite de idade de mensagens em tempo real — ainda recupera mensagens perdidas recentemente e suprime mensagens pendentes antigas, mas com a janela mais estreita de mensagens em tempo real. Execute o Gateway no Mac com Messages para obter a janela de recuperação mais ampla.
Sinal visível para o operador
As mensagens pendentes suprimidas são registradas no nível padrão, nunca descartadas silenciosamente (o sinalizador recovery mostra qual janela foi aplicada):
imessage: mensagens pendentes de entrada obsoletas suprimidas account=<id> sent=<iso> recovery=<bool> (<N> suprimidas desde a inicialização)Migração
channels.imessage.catchup.* está obsoleto — a recuperação do período de inatividade é automática e não exige configuração em novas instalações. Configurações existentes com catchup.enabled: true continuam sendo respeitadas como um perfil de compatibilidade para a janela de repetição da recuperação. Blocos de recuperação desabilitados (enabled: false ou sem enabled: true) foram descontinuados; openclaw doctor --fix os remove.
Solução de problemas
imsg não encontrado ou RPC incompatível
Valide o binário e a compatibilidade com RPC:
imsg rpc --helpimsg status --jsonopenclaw channels status --probeSe a sondagem indicar incompatibilidade com RPC, atualize o imsg. Se as ações de API privada estiverem indisponíveis, execute imsg launch na sessão do usuário do macOS com login ativo e faça a sondagem novamente. Se o Gateway não estiver sendo executado no macOS, use a configuração de Mac remoto por SSH acima, em vez do caminho local padrão do imsg.
As mensagens são enviadas, mas as iMessages recebidas não chegam
Primeiro, confirme se a mensagem chegou ao Mac local. Se o chat.db não mudar, o OpenClaw não poderá receber a mensagem, mesmo que imsg status --json indique uma ponte íntegra.
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;"Se as mensagens enviadas pelo telefone não criarem novas linhas, corrija a camada do Messages do macOS e do Apple Push antes de alterar a configuração do OpenClaw. Uma única atualização dos serviços geralmente é suficiente:
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 restartEnvie uma nova iMessage pelo telefone e confirme uma nova linha no chat.db ou um evento em imsg watch antes de depurar as sessões do OpenClaw. Não execute isso como um ciclo periódico de reinicialização da ponte; repetir imsg launch e reinicializações do Gateway durante o trabalho ativo pode interromper entregas e deixar execuções do canal em andamento sem conclusão.
O Gateway não está sendo executado no macOS
O cliPath: "imsg" padrão deve ser executado no Mac conectado ao Messages. No Linux ou Windows, defina channels.imessage.cliPath como um script wrapper que se conecta via SSH a esse Mac e executa imsg "$@".
#!/usr/bin/env bashexec ssh -T messages-mac imsg "$@"Em seguida, execute:
openclaw channels status --probe --channel imessageAs DMs são ignoradas
Verifique:
channels.imessage.dmPolicychannels.imessage.allowFrom- aprovações de pareamento (
openclaw pairing list imessage)
As mensagens em grupo são ignoradas
Verifique:
channels.imessage.groupPolicychannels.imessage.groupAllowFrom- comportamento da lista de permissões de
channels.imessage.groups - configuração de padrões de menção (
agents.list[].groupChat.mentionPatterns)
Anexos remotos falham
Verifique:
channels.imessage.remoteHostchannels.imessage.remoteAttachmentRoots- autenticação por chave SSH/SCP no host do Gateway
- a chave do host existe em
~/.ssh/known_hostsno host do Gateway - legibilidade do caminho remoto no Mac que executa o Messages
As solicitações de permissão do macOS foram ignoradas
Execute novamente em um terminal gráfico interativo, no mesmo contexto de usuário/sessão, e aprove as solicitações:
imsg chats --limit 1imsg send <handle> "test"Confirme que Full Disk Access + Automation foram concedidos ao contexto de processo que executa o OpenClaw/imsg.
Referências de configuração
Relacionados
- Visão geral dos canais — todos os canais compatíveis
- Remoção do BlueBubbles e o caminho do iMessage via imsg — anúncio e resumo da migração
- Migração do BlueBubbles — tabela de conversão da configuração e transição passo a passo
- Pareamento — autenticação por mensagem direta e fluxo de pareamento
- Grupos — comportamento de chats em grupo e controle por menções
- Roteamento de canais — roteamento de sessões para mensagens
- Segurança — modelo de acesso e proteção