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 separados. O modo de API privada é altamente 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.
Para a configuração local comum, a configuração do OpenClaw pode oferecer, mediante confirmação do usuário, a instalação ou atualização de imsg pelo Homebrew no Mac com sessão iniciada no Mensagens. A configuração manual e as topologias com wrapper SSH continuam sob responsabilidade do operador: instale ou atualize 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 em execução 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 a ausência de um comando imsg padrão, 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 cliPath personalizados 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 primeiro pareamento por 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 via 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, é possível apontar cliPath para um script wrapper que se conecte por SSH a um Mac remoto e execute imsg.
Instale e atualize 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 (mescladas com a raiz 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 ou opções SSH); valores não seguros 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 de anexos são validados em relação às raízes permitidas (attachmentRoots / remoteAttachmentRoots).
Requisitos e permissões (macOS)
- O Mensagens deve estar com a sessão iniciada no Mac que executa
imsg. - O Acesso Total ao Disco é obrigatório para o contexto de 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 / desfazer envio / resposta em thread / efeitos / enquetes / operações de grupo), a Proteção da Integridade do Sistema deve ser desativada — consulte Ativação da API privada do imsg. O envio e recebimento básico de texto e mídia funciona sem isso.
Falha nos envios pelo wrapper SSH com AppleEvents -1743
Uma configuração com SSH remoto pode ler conversas, passar por channels status --probe e processar mensagens recebidas, enquanto os envios ainda falham com um erro de autorização do AppleEvents:
Sem autorização para enviar eventos Apple ao 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 de para imsg ou para o processo do shell local, o macOS talvez não exponha um controle utilizável do Mensagens para esse cliente no lado do servidor SSH:
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 porque o contexto de processo que precisa da Automação do Mensagens é o wrapper SSH, não um aplicativo ao qual a interface possa conceder acesso.
Em vez disso, use um dos contextos de processo imsg compatíveis:
- Execute o Gateway, ou pelo menos a ponte
imsg, na sessão local do usuário com sessão iniciada no Mensagens. - Inicie o Gateway com um LaunchAgent desse usuário depois de conceder Acesso Total ao Disco e Automação na mesma sessão.
- Se mantiver a topologia SSH com dois usuários, confirme que um envio real por
imsg sendfunciona pelo wrapper exato antes de habilitar o canal. Se não for possível conceder Automação a ele, reconfigure para uma configuraçãoimsgcom um único usuário, em vez de depender do wrapper SSH para os envios.
Ativação da API privada do imsg
imsg é fornecido em dois modos operacionais. Para o OpenClaw, o modo de API privada é a configuração recomendada porque fornece ao canal as ações nativas do iMessage esperadas pelos usuários. O modo básico continua útil para instalações de baixo risco, verificação inicial ou hosts nos quais não é possível desativar o SIP.
- Modo básico (padrão, sem necessidade de alterar o SIP): envio de texto e mídia por
send, monitoramento/histórico de entrada e lista de conversas. Isso é o que se obtém imediatamente com uma instalação nova debrew install steipete/tap/imsge as permissões padrão do macOS descritas acima. - Modo de API privada:
imsginjeta uma dylib auxiliar emMessages.apppara chamar funções internas deIMCore. Isso desbloqueiareact,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 de imsg é explícito sobre o requisito:
Recursos avançados, como
read,typing,launch, envio avançado com suporte da ponte, alteração de mensagens e gerenciamento de conversas, são opcionais. Eles exigem que o SIP esteja desativado e que uma dylib auxiliar seja injetada emMessages.app.imsg launchse recusa a fazer a injeção quando o SIP está habilitado.
A técnica de injeção do auxiliar usa a própria dylib de 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)
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_methodseselectorspor método, para que seja possível verificar o que a compilação atual oferece antes de começar. -
Desative a Proteção de Integridade do Sistema e, no macOS moderno, a Validação de Biblioteca. Injetar uma dylib auxiliar que não seja da Apple no
Messages.appassinado pela Apple exige que o SIP esteja desativado e que a validação de biblioteca esteja relaxada. A etapa do SIP no modo de Recuperação varia conforme a versão do macOS:- macOS 10.13-10.15 (Sierra-Catalina): desative 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 posteriores, apenas
csrutil disablegeralmente não é suficiente. A Apple ainda impõe a validação de biblioteca aoMessages.apppor ele ser um binário da plataforma; portanto, um auxiliar com assinatura ad hoc é rejeitado (Library Validation failed: ... platform binary, but mapped file is not) mesmo com o SIP desativado. Depois de desativar o SIP, desative também a validação de biblioteca 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 argumento de inicialização é 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 com assinatura 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 alguma medida mais drástica.
Se a injeção de
imsg launchou algumselectorsespecífico começar a retornar falso após uma atualização do macOS, essa restrição geralmente é a causa. Verifique o estado do SIP e da validação de biblioteca antes de presumir que a própria etapa do SIP falhou. Se essas configurações estiverem corretas e ainda não for possível injetar a ponte, coleteimsg status --jsonjunto com a saída deimsg launche informe ao projetoimsg, em vez de enfraquecer outros controles de segurança em todo o sistema. - macOS 10.13-10.15 (Sierra-Catalina): desative a Validação de Biblioteca pelo Terminal, reinicie no modo de Recuperação, execute
-
Injete o auxiliar. Com o SIP desativado e uma 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 realizada. -
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 exigeselectors.pollVoteMessagee 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 lançarem "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 status available: true armazenado em cache continuará anunciando as 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:
imsgrecorre ao modo básico — somente texto, mídia e recebimento.- O plugin do OpenClaw continua anunciando 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 restrição de recursos por método). - É possível executar um Mac separado que não use Apple Silicon (ou um Mac dedicado ao bot) com o SIP desativado para a carga de trabalho do iMessage, mantendo o SIP ativado nos 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 do registro chat_id.
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>).
Alternativa 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 em mensagens diretas e grupos precisar ser diferente. Um groupAllowFrom: [] explicitamente vazio não usa a alternativa — 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 recorrerá a groupPolicy="allowlist" e registrará um aviso (mesmo que channels.defaults.groupPolicy esteja definido).
Restrição por menção em grupos:
- o iMessage não possui metadados nativos de menção
- a detecção de menções usa padrões de expressões regulares (
agents.list[].groupChat.mentionPatterns, com alternativa emmessages.groupChat.mentionPatterns) - sem padrões configurados, a restrição por menção não pode ser aplicada
- comandos de controle de remetentes autorizados ignoram a restrição por menção
systemPrompt por grupo:
Cada entrada em channels.imessage.groups.* aceita uma string systemPrompt opcional, injetada no prompt de sistema do agente em cada turno que trata uma mensagem desse grupo. A resolução segue a mesma lógica de 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 ao grupo. - Prompt de sistema curinga para grupos (
groups["*"].systemPrompt): usado quando a entrada específica do grupo está completamente 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: "", }, }, }, },}Prompts por grupo se aplicam somente a mensagens de grupo — mensagens diretas não são afetadas.
Sessões e respostas determinísticas
- Mensagens diretas usam roteamento direto; grupos usam roteamento de grupo.
- Com o
session.dmScope=mainpadrão, as mensagens diretas do iMessage são consolidadas na sessão principal do agente. - As sessões de grupo são isoladas (
agent:<agentId>:imessage:group:<chat_id>). - As respostas são encaminhadas de volta ao iMessage usando os metadados do canal e do 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 explicitamente configurado em channels.imessage.groups, o OpenClaw o tratará como tráfego de grupo (restrições 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 operadores:
- 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 à sessão ACP criada.
/newe/resetredefinem no local a mesma sessão ACP vinculada./acp closeencerra a sessão ACP e remove o vínculo.
Vínculos persistentes configurados usam entradas bindings[] de nível superior com type: "acp" e match.channel: "imessage".
match.peer.id pode usar:
- um identificador normalizado de mensagem direta, como
+15555550123ouuser@example.com chat_id:<id>(recomendado para vínculos de grupo estáveis)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 conhecer 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/inicie sessão em um usuário dedicado do macOS.
- Inicie sessão no Mensagens com o ID Apple do bot nesse usuário.
- Instale
imsgnesse usuário. - Crie um wrapper SSH para que o OpenClaw possa executar
imsgno contexto desse usuário. - Aponte
channels.imessage.accounts.<id>.cliPathe.dbPathpara esse perfil de usuário.
A primeira execução pode exigir aprovações pela interface gráfica (Automação + Acesso Total ao Disco) na sessão desse usuário do bot.
Mac remoto via Tailscale (exemplo)
Topologia comum:
- o Gateway é executado em Linux/VM
- o iMessage +
imsgsão executados em um Mac na sua tailnet - o wrapper
cliPathusa SSH para executarimsg remoteHosthabilita a obtenção de anexos via 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, garanta 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 várias contas
O iMessage aceita 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 decodificado de imsg dessa conversa. Use channels.imessage.dms["<sender>"].historyLimit para substituições por remetente, incluindo 0 para desabilitar o histórico de um remetente.
O histórico de MDs do iMessage é obtido sob demanda de imsg. Deixar dmHistoryLimit sem definição desabilita o preenchimento global do histórico de MDs, mas um valor positivo de channels.imessage.dms["<sender>"].historyLimit por remetente ainda habilita o preenchimento para esse remetente.
Mídia, divisão em partes 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, gravações de voz, vídeos e outros anexos ao agente. Com essa opção desabilitada, iMessages que contêm apenas anexos são descartadas antes de chegar ao agente e podem não gerar 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 ampliam o padrão de raiz padrão
/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 partes
- limite de caracteres por parte:
channels.imessage.textChunkLimit(padrão de 4000) - modo de divisão em partes:
channels.imessage.streaming.chunkModelength(padrão)newline(divisão priorizando parágrafos)
- negrito/itálico/sublinhado/tachado em Markdown de saída é convertido em texto estilizado nativo (destinatários no macOS 15+ veem a estilização; destinatários em versões anteriores veem texto simples sem os marcadores); tabelas Markdown são convertidas conforme o modo de tabela Markdown do canal
channels.imessage.sendTransport(autopor padrão,bridge,applescript) seleciona comoimsgrealiza 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 são habilitadas 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 definido. - reply: Envia uma resposta em thread a uma mensagem existente (
messageId,textoumessage, além dechatGuid,chatId,chatIdentifierouto). A resposta com anexo também requer uma versão deimsgcujosend-richseja compatível com--file. - sendWithEffect: Envia texto com um efeito do iMessage (
textoumessage,effectoueffectId). Nomes abreviados: 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 ser retiradas. - upload-file: Envia mídia/arquivos (
buffercomo base64 ou ummedia/path/filePathhidratado,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 Mensagens do host, portanto exigem um remetente proprietário ou um cliente Gateway
operator.admin. - poll: Cria uma enquete nativa do Mensagens da Apple (
pollQuestion,pollOptionrepetido de 2 a 12 vezes, além dechatGuid,chatId,chatIdentifierouto). Destinatários no iOS/iPadOS/macOS 26+ veem e votam nela de forma nativa; versões anteriores dos sistemas operacionais recebem o texto alternativo "Enquete enviada". Requerselectors.pollPayloadMessage. - poll-vote: Vota em uma enquete existente (
pollIdoumessageId, além de exatamente um entrepollOptionIndex,pollOptionIdoupollOptionText). Requerselectors.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 valores curtos de MessageSid e GUIDs completos de mensagens (MessageSidFull), quando disponíveis. IDs curtos têm o escopo do cache de respostas recentes baseado em SQLite e são verificados em relação à conversa atual antes do uso. Se um ID curto expirar, tente novamente com seu MessageSidFull direcionando para a conversa que o forneceu. IDs completos não ignoram a vinculação à conversa ou à conta; portanto, substitua um ID de outra conversa por um do destino atual. Chamadas delegadas remotamente podem rejeitar IDs completos obsoletos quando não há evidência disponível da conversa atual.
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 despacho executa sondagens de forma adiada, para que a primeira ação possa ser bem-sucedida após imsg launch sem uma atualização manual separada do status.
Confirmações de leitura e indicador de 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. Desabilite a marcação como lida com:
{ channels: { imessage: { sendReadReceipts: false, }, },}Versões antigas de imsg anteriores à lista de recursos por método desativam silenciosamente a digitação/leitura; o OpenClaw registra um aviso único a cada reinicialização para que a ausência da confirmação possa ser atribuída.
Tapbacks recebidos
O OpenClaw assina os tapbacks do iMessage e encaminha as reações aceitas como eventos do sistema, em vez de texto normal de mensagem, para que um tapback do 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 os usuários reagem a mensagens criadas pelo bot."all": notifica sobre todos os tapbacks recebidos de remetentes autorizados."off": ignora tapbacks recebidos.
As 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 é roteada para o iMessage, o Gateway entrega uma solicitação de aprovação de forma nativa e aceita um tapback para resolvê-la:
👍(tapback Curtir) →allow-once👎(tapback Não Curtir) →denyallow-alwayspermanece como alternativa manual: envie/approve <id> allow-alwayscomo uma resposta normal.
O processamento de reações 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 de aprovador válidas). A entrada curinga "*" é respeitada, mas permite que qualquer remetente aprove; uma lista de aprovadores vazia desabilita completamente o atalho de reação. O atalho de reação ignora intencionalmente reactionNotifications, dmPolicy e groupAllowFrom, pois a lista explícita de aprovadores permitidos é a única verificação relevante para a resolução da 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 em relação a essa lista de aprovadores (não à lista mais ampla de permissões de MD), e remetentes permitidos na lista de permissões de MD, 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 MD. Adicione todos os operadores que devem poder aprovar — por meio de /approve ou de reações — a allowFrom.
Observações para operadores:
- A associação da reação é armazenada tanto na memória quanto no armazenamento persistente por chave do gateway (com o TTL correspondente à expiração da aprovação), e o gateway também consulta periodicamente os prompts pendentes em busca de tapbacks; portanto, um tapback recebido logo após a 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 é um aprovador explícito. - Os prompts de aprovação são encaminhados para uma conversa em grupo somente quando aprovadores explícitos estão configurados; caso contrário, qualquer membro do grupo poderia aprovar.
- Tapbacks legados em formato de texto (
Liked "…"em texto simples de clientes Apple muito antigos) não podem resolver aprovações porque não contêm o GUID da mensagem; a resolução por reação exige os metadados estruturados de tapback emitidos pelos clientes macOS / iOS atuais.
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 DMs com envio dividido (comando + URL em uma 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 chat.db separadas:
- Uma mensagem de texto (
"Dump"). - Um balão de pré-visualização de URL (
"https://...") com imagens da 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 agregação, o agente recebe apenas o comando no turno 1 (e frequentemente responde "envie 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 por imsg.
channels.imessage.coalesceSameSenderDms permite que uma DM armazene em buffer linhas consecutivas do mesmo remetente. Quando imsg expõe o marcador estrutural de pré-visualização de URL balloon_bundle_id: "com.apple.messages.URLBalloonProvider" em uma das linhas de origem, o OpenClaw mescla somente esse envio realmente dividido e mantém quaisquer outras linhas armazenadas em buffer como turnos separados. Em builds mais antigos de 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 conjunto. 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 ativar
Ative quando:
- Você disponibiliza 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).
Mantenha desativado quando:
- Você precisa da menor latência possível para comandos de acionamento de uma única palavra em DMs.
- Todos os seus fluxos usam comandos únicos, sem payloads enviados em seguida.
Ativação
{ channels: { imessage: { coalesceSameSenderDms: true, // ativação opcional (padrão: false) }, },}Com o sinalizador ativado e sem um messages.inbound.byChannel.imessage explícito ou um messages.inbound.debounceMs global, a janela de debounce é ampliada para 7000 ms (o padrão legado é 0 ms — sem debounce). A janela maior é necessária porque a cadência de envio dividido da pré-visualização de URL da Apple pode se estender por vários segundos enquanto o Messages.app emite a linha de pré-visualização.
Para ajustar a janela manualmente:
{ messages: { inbound: { byChannel: { // 7000 ms abrangem os atrasos observados na pré-visualização de URLs do Messages.app. imessage: 7000, }, }, },}Compensações
- A mesclagem precisa exige metadados atuais no payload de
imsg. Quandoballoon_bundle_idestá presente, somente o envio realmente dividido é mesclado; a mesclagem de fallback sem metadados descrita acima é uma compatibilidade retroativa temporária, removida assim queimsgagregar 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 de acompanhamento com um único texto) aguarda até o fim da janela de debounce antes do despacho, caso uma linha de pré-visualização de URL esteja a caminho. As mensagens de chats em grupo continuam sendo despachadas imediatamente.
- A saída mesclada é limitada. O texto mesclado é limitado a 4000 caracteres, com um marcador
…[truncated]explícito; os anexos são limitados a 20; as entradas de origem são limitadas a 10 (a primeira e as mais recentes são mantidas além desse limite). 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.
- Ativação 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 um build de imsg que emite balloon_bundle_id. Em builds mais antigos de imsg, que não emitem nenhum metadado de balão, as linhas abaixo marcadas como "Dois turnos" / "N turnos" recorrem, em vez disso, 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 o build passa a emitir metadados de balão.
| O usuário compõe | 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: "Dump" sozinho, depois a 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 os metadados serem observados; um turno mesclado em sessões antigas/anteriores ao latch sem metadados |
/status (comando independente) |
1 linha | Despacho imediato | Aguarda até o fim da janela e então despacha |
| URL colada sozinha | 1 linha | Despacho imediato | Aguarda até o fim 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) |
| Enxurrada rápida (>10 DMs pequenas dentro da janela) | N linhas sem metadados de balão de URL | N turnos | N turnos após os metadados serem observados; um turno mesclado e limitado em sessões antigas/anteriores ao latch sem metadados |
| Duas pessoas digitando em um chat em grupo | N linhas de M remetentes | M+ turnos (um por conjunto de remetente) | M+ turnos — chats em grupo não são agregados |
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 backlog" obsoleta que a Apple pode descarregar após uma recuperação de Push. O comportamento padrão está sempre ativado e se baseia 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), reservada na ingestão e confirmada após o processamento (liberada em caso de falha transitória para que possa ser tentada novamente). Tudo que já tiver sido processado é descartado, em vez de ser despachado duas vezes. Isso permite que a recuperação repita mensagens de forma agressiva sem manter registros por mensagem. - Recuperação do período de inatividade. Na inicialização, o monitor recupera o último rowid despachado de
chat.db(um cursor persistente por conta) e o passa paraimsg watch.subscribecomosince_rowid, para que o imsg repita as linhas que chegaram enquanto o gateway estava inativo e depois acompanhe as mensagens ao vivo. A repetição é limitada às 500 linhas mais recentes e a mensagens com até aproximadamente 2 horas, e a desduplicação descarta tudo que já tiver sido processado. - Limite de idade para backlog obsoleto. As linhas acima do limite de inicialização são realmente ao vivo; uma linha cuja data de envio seja mais de aproximadamente 15 minutos anterior à chegada pertence ao backlog descarregado pelo Push e é suprimida. As linhas repetidas (no limite ou abaixo dele) usam a janela de recuperação mais ampla, permitindo 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, pois a repetição de since_rowid é executada pela mesma conexão RPC de imsg. A diferença está na janela: quando o gateway consegue ler chat.db (local), ele fixa o limite de rowid da inicialização, limita o intervalo de repetição e entrega mensagens perdidas com até algumas horas de idade. Por meio de um cliPath SSH remoto, ele não consegue ler o banco de dados; portanto, a repetição não tem limite e cada linha usa o limite de idade das mensagens ao vivo — ele ainda recupera mensagens perdidas recentemente e suprime o backlog antigo, mas com a janela menor das mensagens ao vivo. Execute o gateway no Mac com o Mensagens para obter a janela de recuperação mais ampla.
Sinal visível para o operador
O backlog suprimido é registrado no nível padrão, nunca descartado silenciosamente (o sinalizador recovery mostra qual janela foi aplicada):
imessage: backlog de entrada obsoleto suprimido account=<id> sent=<iso> recovery=<bool> (<N> suprimidos 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 desativados (enabled: false ou sem enabled: true) foram descontinuados; openclaw doctor --fix os remove.
Solução de problemas
imsg não encontrado ou RPC sem suporte
Valide o binário e o suporte a RPC:
imsg rpc --helpimsg status --jsonopenclaw channels status --probeSe a verificação informar que RPC não é compatível, atualize imsg. Se as ações de API privada não estiverem disponíveis, execute imsg launch na sessão do usuário conectado ao macOS e verifique novamente. Se o Gateway não estiver em execução no macOS, use a configuração de Mac remoto via SSH descrita acima, em vez do caminho local padrão de imsg.
As mensagens são enviadas, mas as iMessages recebidas não chegam
Primeiro, confirme se a mensagem chegou ao Mac local. Se chat.db não mudar, o OpenClaw não conseguirá receber a mensagem, mesmo quando imsg status --json indicar 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, repare a camada do Mensagens do macOS e do Apple Push antes de alterar a configuração do OpenClaw. Uma atualização pontual do serviço 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 chat.db ou um evento imsg watch antes de depurar as sessões do OpenClaw. Não execute isso como um loop periódico de reinicialização da ponte; reinicializações repetidas de imsg launch junto com reinicializações do Gateway durante o trabalho ativo podem interromper entregas e deixar execuções do canal em andamento sem continuidade.
O Gateway não está em execução 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 por 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 mensagens diretas são ignoradas
Verifique:
channels.imessage.dmPolicychannels.imessage.allowFrom- aprovações de pareamento (
openclaw pairing list imessage)
As mensagens de grupo são ignoradas
Verifique:
channels.imessage.groupPolicychannels.imessage.groupAllowFromchannels.imessage.groupscomportamento da lista de permissões- configuração do padrão de menção (
agents.list[].groupChat.mentionPatterns)
Falha nos anexos remotos
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 - a legibilidade do caminho remoto no Mac que executa o Mensagens
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 Acesso Total ao Disco + Automação foram concedidos ao contexto do processo que executa o OpenClaw/imsg.
Referências da 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 tradução da configuração e transição passo a passo
- Emparelhamento — autenticação de mensagens diretas e fluxo de emparelhamento
- Grupos — comportamento de conversas em grupo e controle por menções
- Roteamento de canais — roteamento de sessões para mensagens
- Segurança — modelo de acesso e proteção