Signal (signal-cli)

Status: integração com CLI externo. O gateway se comunica com signal-cli via HTTP JSON-RPC + SSE.

Pré-requisitos

  • OpenClaw instalado no seu servidor (fluxo Linux abaixo testado no Ubuntu 24).
  • signal-cli disponível no host onde o gateway roda.
  • Um número de telefone que possa receber um SMS de verificação (para o caminho de registro via SMS).
  • Acesso ao navegador para captcha do Signal (signalcaptchas.org) durante o registro.

Configuração rápida (iniciante)

  1. Use um número Signal separado para o bot (recomendado).
  2. Instale signal-cli (Java necessário se usar o build JVM).
  3. Escolha um caminho de configuração:
    • Caminho A (link QR): signal-cli link -n "OpenClaw" e escaneie com o Signal.
    • Caminho B (registro SMS): registre um número dedicado com captcha + verificação SMS.
  4. Configure o OpenClaw e reinicie o gateway.
  5. Envie uma primeira DM e aprove o pareamento (openclaw pairing approve signal <CODE>).

Configuração mínima:

{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",
      cliPath: "signal-cli",
      dmPolicy: "pairing",
      allowFrom: ["+15557654321"],
    },
  },
}

Referência de campos:

CampoDescrição
accountNúmero do bot no formato E.164 (+15551234567)
cliPathCaminho para signal-cli (signal-cli se no PATH)
dmPolicyPolítica de acesso a DM (pairing recomendado)
allowFromNúmeros de telefone ou valores uuid:<id> permitidos para DM

O que é

  • Canal Signal via signal-cli (não libsignal embarcado).
  • Roteamento determinístico: respostas sempre voltam para o Signal.
  • DMs compartilham a sessão principal do agente; grupos são isolados (agent:<agentId>:signal:group:<groupId>).

Config writes

Por padrão, o Signal permite escrita de configuração acionada por /config set|unset (requer commands.config: true).

Desabilite com:

{
  channels: { signal: { configWrites: false } },
}

O modelo de número (importante)

  • O gateway se conecta a um dispositivo Signal (a conta do signal-cli).
  • Se você rodar o bot na sua conta pessoal do Signal, ele ignorará suas próprias mensagens (proteção contra loop).
  • Para o cenário “eu mando mensagem pro bot e ele responde”, use um número separado para o bot.

Caminho de configuração A: vincular conta Signal existente (QR)

  1. Instale signal-cli (build JVM ou nativo).
  2. Vincule uma conta de bot:
    • signal-cli link -n "OpenClaw" e escaneie o QR no Signal.
  3. Configure o Signal e inicie o gateway.

Exemplo:

{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",
      cliPath: "signal-cli",
      dmPolicy: "pairing",
      allowFrom: ["+15557654321"],
    },
  },
}

Suporte a múltiplas contas: use channels.signal.accounts com configuração por conta e name opcional. Veja gateway/configuration para o padrão compartilhado.

Caminho de configuração B: registrar número dedicado para o bot (SMS, Linux)

Use quando quiser um número dedicado para o bot em vez de vincular uma conta existente do Signal.

  1. Obtenha um número que possa receber SMS (ou verificação por voz para linhas fixas).
    • Use um número dedicado para o bot a fim de evitar conflitos de conta/sessão.
  2. Instale signal-cli no host do gateway:
VERSION=$(curl -Ls -o /dev/null -w %{url_effective} https://github.com/AsamK/signal-cli/releases/latest | sed -e 's/^.*\/v//')
curl -L -O "https://github.com/AsamK/signal-cli/releases/download/v${VERSION}/signal-cli-${VERSION}-Linux-native.tar.gz"
sudo tar xf "signal-cli-${VERSION}-Linux-native.tar.gz" -C /opt
sudo ln -sf /opt/signal-cli /usr/local/bin/
signal-cli --version

Se usar o build JVM (signal-cli-${VERSION}.tar.gz), instale JRE 25+ primeiro. Mantenha signal-cli atualizado; o upstream indica que versões antigas podem quebrar conforme as APIs do servidor Signal mudam.

  1. Registre e verifique o número:
signal-cli -a +<NUMERO_DO_BOT> register

Se captcha for necessário:

  1. Abra https://signalcaptchas.org/registration/generate.html.
  2. Complete o captcha, copie o link signalcaptcha://... de “Open Signal”.
  3. Execute a partir do mesmo IP externo da sessão do navegador quando possível.
  4. Execute o registro novamente imediatamente (tokens de captcha expiram rapidamente):
signal-cli -a +<NUMERO_DO_BOT> register --captcha '<URL_DO_SIGNALCAPTCHA>'
signal-cli -a +<NUMERO_DO_BOT> verify <CODIGO_DE_VERIFICACAO>
  1. Configure o OpenClaw, reinicie o gateway, verifique o canal:
# Se você roda o gateway como serviço systemd de usuário:
systemctl --user restart openclaw-gateway

# Depois verifique:
openclaw doctor
openclaw channels status --probe
  1. Pareie seu remetente de DM:
    • Envie qualquer mensagem para o número do bot.
    • Aprove o código no servidor: openclaw pairing approve signal <CODIGO_DE_PAREAMENTO>.
    • Salve o número do bot como contato no seu telefone para evitar “Contato desconhecido”.

Importante: registrar uma conta de número de telefone com signal-cli pode desautenticar a sessão principal do app Signal para aquele número. Prefira um número dedicado para o bot, ou use o modo de link QR se precisar manter a configuração do app no telefone.

Referências upstream:

  • README do signal-cli: https://github.com/AsamK/signal-cli
  • Fluxo de captcha: https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha
  • Fluxo de link: https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)

Modo de daemon externo (httpUrl)

Se quiser gerenciar o signal-cli por conta própria (inicializações JVM lentas, init de container ou CPUs compartilhadas), rode o daemon separadamente e aponte o OpenClaw para ele:

{
  channels: {
    signal: {
      httpUrl: "http://127.0.0.1:8080",
      autoStart: false,
    },
  },
}

Isso ignora o auto-spawn e a espera de inicialização dentro do OpenClaw. Para inicializações lentas ao usar auto-spawn, defina channels.signal.startupTimeoutMs.

Controle de acesso (DMs + grupos)

DMs:

  • Padrão: channels.signal.dmPolicy = "pairing".
  • Remetentes desconhecidos recebem um código de pareamento; mensagens são ignoradas até aprovação (códigos expiram após 1 hora).
  • Aprove via:
    • openclaw pairing list signal
    • openclaw pairing approve signal <CODE>
  • O pareamento é a troca de token padrão para DMs do Signal. Detalhes: Pareamento
  • Remetentes apenas com UUID (de sourceUuid) são armazenados como uuid:<id> em channels.signal.allowFrom.

Grupos:

  • channels.signal.groupPolicy = open | allowlist | disabled.
  • channels.signal.groupAllowFrom controla quem pode acionar em grupos quando allowlist está definido.
  • channels.signal.groups["<group-id>" | "*"] pode sobrescrever comportamento de grupo com requireMention, tools e toolsBySender.
  • Use channels.signal.accounts.<id>.groups para sobrescritas por conta em configurações multi-conta.
  • Nota de runtime: se channels.signal está completamente ausente, o runtime faz fallback para groupPolicy="allowlist" para verificações de grupo (mesmo se channels.defaults.groupPolicy estiver definido).

Como funciona (comportamento)

  • signal-cli roda como daemon; o gateway lê eventos via SSE.
  • Mensagens de entrada são normalizadas no envelope de canal compartilhado.
  • Respostas sempre roteiam de volta para o mesmo número ou grupo.

Mídia + limites

  • Texto de saída é dividido em channels.signal.textChunkLimit (padrão 4000).
  • Divisão por nova linha opcional: defina channels.signal.chunkMode="newline" para dividir em linhas em branco (limites de parágrafo) antes da divisão por tamanho.
  • Anexos suportados (base64 obtido do signal-cli).
  • Limite de mídia padrão: channels.signal.mediaMaxMb (padrão 8).
  • Use channels.signal.ignoreAttachments para pular download de mídia.
  • Contexto de histórico de grupo usa channels.signal.historyLimit (ou channels.signal.accounts.*.historyLimit), com fallback para messages.groupChat.historyLimit. Defina 0 para desabilitar (padrão 50).

Digitação + confirmações de leitura

  • Indicadores de digitação: O OpenClaw envia sinais de digitação via signal-cli sendTyping e os renova enquanto uma resposta está sendo gerada.
  • Confirmações de leitura: quando channels.signal.sendReadReceipts é true, o OpenClaw encaminha confirmações de leitura para DMs permitidas.
  • signal-cli não expõe confirmações de leitura para grupos.

Reações (ferramenta de mensagem)

  • Use message action=react com channel=signal.
  • Alvos: E.164 do remetente ou UUID (use uuid:<id> da saída de pareamento; UUID simples também funciona).
  • messageId é o timestamp do Signal para a mensagem à qual você está reagindo.
  • Reações em grupo requerem targetAuthor ou targetAuthorUuid.

Exemplos:

message action=react channel=signal target=uuid:123e4567-e89b-12d3-a456-426614174000 messageId=1737630212345 emoji=🔥
message action=react channel=signal target=+15551234567 messageId=1737630212345 emoji=🔥 remove=true
message action=react channel=signal target=signal:group:<groupId> targetAuthor=uuid:<sender-uuid> messageId=1737630212345 emoji=✅

Configuração:

  • channels.signal.actions.reactions: habilitar/desabilitar ações de reação (padrão true).
  • channels.signal.reactionLevel: off | ack | minimal | extensive.
    • off/ack desabilita reações do agente (ferramenta de mensagem react retornará erro).
    • minimal/extensive habilita reações do agente e define o nível de orientação.
  • Sobrescritas por conta: channels.signal.accounts.<id>.actions.reactions, channels.signal.accounts.<id>.reactionLevel.

Alvos de entrega (CLI/cron)

  • DMs: signal:+15551234567 (ou E.164 simples).
  • DMs por UUID: uuid:<id> (ou UUID simples).
  • Grupos: signal:group:<groupId>.
  • Nomes de usuário: username:<name> (se suportado pela sua conta Signal).

Resolução de problemas

Execute esta sequência primeiro:

openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe

Depois confirme o estado de pareamento de DM se necessário:

openclaw pairing list signal

Falhas comuns:

  • Daemon acessível mas sem respostas: verifique configurações de conta/daemon (httpUrl, account) e modo de recebimento.
  • DMs ignoradas: remetente pendente de aprovação de pareamento.
  • Mensagens de grupo ignoradas: gating de remetente/menção de grupo bloqueando entrega.
  • Erros de validação de config após edições: execute openclaw doctor --fix.
  • Signal ausente do diagnóstico: confirme channels.signal.enabled: true.

Verificações extras:

openclaw pairing list signal
pgrep -af signal-cli
grep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20

Para fluxo de triagem: /channels/troubleshooting.

Notas de segurança

  • signal-cli armazena chaves de conta localmente (tipicamente ~/.local/share/signal-cli/data/).
  • Faça backup do estado da conta Signal antes de migração ou reconstrução de servidor.
  • Mantenha channels.signal.dmPolicy: "pairing" a menos que você explicitamente queira acesso mais amplo a DM.
  • A verificação por SMS só é necessária para fluxos de registro ou recuperação, mas perder controle do número/conta pode complicar o re-registro.

Referência de configuração (Signal)

Configuração completa: Configuração

Opções do provedor:

  • channels.signal.enabled: habilitar/desabilitar inicialização do canal.
  • channels.signal.account: E.164 para a conta do bot.
  • channels.signal.cliPath: caminho para signal-cli.
  • channels.signal.httpUrl: URL completa do daemon (sobrescreve host/porta).
  • channels.signal.httpHost, channels.signal.httpPort: bind do daemon (padrão 127.0.0.1:8080).
  • channels.signal.autoStart: auto-spawn do daemon (padrão true se httpUrl não definido).
  • channels.signal.startupTimeoutMs: timeout de espera de inicialização em ms (limite 120000).
  • channels.signal.receiveMode: on-start | manual.
  • channels.signal.ignoreAttachments: pular downloads de anexos.
  • channels.signal.ignoreStories: ignorar stories do daemon.
  • channels.signal.sendReadReceipts: encaminhar confirmações de leitura.
  • channels.signal.dmPolicy: pairing | allowlist | open | disabled (padrão: pairing).
  • channels.signal.allowFrom: allowlist de DM (E.164 ou uuid:<id>). open requer "*". Signal não tem nomes de usuário; use IDs de telefone/UUID.
  • channels.signal.groupPolicy: open | allowlist | disabled (padrão: allowlist).
  • channels.signal.groupAllowFrom: allowlist de remetentes de grupo.
  • channels.signal.groups: sobrescritas por grupo chaveadas por ID de grupo Signal (ou "*"). Campos suportados: requireMention, tools, toolsBySender.
  • channels.signal.accounts.<id>.groups: versão por conta de channels.signal.groups para configurações multi-conta.
  • channels.signal.historyLimit: máximo de mensagens de grupo para incluir como contexto (0 desabilita).
  • channels.signal.dmHistoryLimit: limite de histórico de DM em turnos de usuário. Sobrescritas por usuário: channels.signal.dms["<phone_or_uuid>"].historyLimit.
  • channels.signal.textChunkLimit: tamanho do chunk de saída (caracteres).
  • channels.signal.chunkMode: length (padrão) ou newline para dividir em linhas em branco (limites de parágrafo) antes da divisão por tamanho.
  • channels.signal.mediaMaxMb: limite de mídia de entrada/saída (MB).

Opções globais relacionadas:

  • agents.list[].groupChat.mentionPatterns (Signal não suporta menções nativas).
  • messages.groupChat.mentionPatterns (fallback global).
  • messages.responsePrefix.