Signal (signal-cli)
Estado: integración de CLI externo. El Gateway se comunica con signal-cli vía HTTP JSON-RPC + SSE.
Requisitos previos
- OpenClaw instalado en tu servidor (el flujo de Linux a continuación se probó en Ubuntu 24).
signal-clidisponible en el host donde se ejecuta el gateway.- Un número de teléfono que pueda recibir un SMS de verificación (para la ruta de registro por SMS).
- Acceso a navegador para el captcha de Signal (
signalcaptchas.org) durante el registro.
Configuración rápida (principiante)
- Usa un número de Signal separado para el bot (recomendado).
- Instala
signal-cli(se requiere Java si usas el build JVM). - Elige una ruta de configuración:
- Ruta A (enlace QR):
signal-cli link -n "OpenClaw"y escanea con Signal. - Ruta B (registro SMS): registra un número dedicado con captcha + verificación SMS.
- Ruta A (enlace QR):
- Configura OpenClaw y reinicia el gateway.
- Envía un primer DM y aprueba el emparejamiento (
openclaw pairing approve signal <CODE>).
Configuración mínima:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
cliPath: "signal-cli",
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
Referencia de campos:
| Campo | Descripción |
|---|---|
account | Número del bot en formato E.164 (+15551234567) |
cliPath | Ruta a signal-cli (signal-cli si está en PATH) |
dmPolicy | Política de acceso DM (pairing recomendado) |
allowFrom | Números o valores uuid:<id> permitidos para DM |
Qué es
- Canal de Signal vía
signal-cli(no libsignal embebido). - Enrutamiento determinista: las respuestas siempre vuelven a Signal.
- Los DMs comparten la sesión principal del agente; los grupos están aislados (
agent:<agentId>:signal:group:<groupId>).
Escrituras de configuración
Por defecto, Signal permite escribir actualizaciones de configuración activadas por /config set|unset (requiere commands.config: true).
Deshabilitar con:
{
channels: { signal: { configWrites: false } },
}
El modelo de número (importante)
- El gateway se conecta a un dispositivo Signal (la cuenta de
signal-cli). - Si ejecutas el bot en tu cuenta personal de Signal, ignorará tus propios mensajes (protección contra bucles).
- Para “le envío un mensaje al bot y me responde”, usa un número de bot separado.
Ruta de configuración A: enlazar cuenta Signal existente (QR)
- Instala
signal-cli(build JVM o nativo). - Enlaza una cuenta de bot:
signal-cli link -n "OpenClaw"y luego escanea el QR en Signal.
- Configura Signal e inicia el gateway.
Ejemplo:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
cliPath: "signal-cli",
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
Soporte multi-cuenta: usa channels.signal.accounts con configuración por cuenta y name opcional. Consulta gateway/configuration para el patrón compartido.
Ruta de configuración B: registrar número de bot dedicado (SMS, Linux)
Usa esto cuando quieras un número de bot dedicado en lugar de enlazar una cuenta existente de la app Signal.
- Obtén un número que pueda recibir SMS (o verificación por voz para líneas fijas).
- Usa un número de bot dedicado para evitar conflictos de cuenta/sesión.
- Instala
signal-clien el host del 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
Si usas el build JVM (signal-cli-${VERSION}.tar.gz), instala primero JRE 25+.
Mantén signal-cli actualizado; el proyecto advierte que versiones antiguas pueden fallar a medida que las APIs del servidor de Signal cambian.
- Registra y verifica el número:
signal-cli -a +<BOT_PHONE_NUMBER> register
Si se requiere captcha:
- Abre
https://signalcaptchas.org/registration/generate.html. - Completa el captcha, copia el enlace
signalcaptcha://...de “Open Signal”. - Ejecuta desde la misma IP externa que la sesión del navegador cuando sea posible.
- Ejecuta el registro de nuevo inmediatamente (los tokens de captcha expiran rápido):
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'
signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>
- Configura OpenClaw, reinicia el gateway, verifica el canal:
# Si ejecutas el gateway como servicio de usuario systemd:
systemctl --user restart openclaw-gateway
# Luego verifica:
openclaw doctor
openclaw channels status --probe
- Empareja tu remitente de DM:
- Envía cualquier mensaje al número del bot.
- Aprueba el código en el servidor:
openclaw pairing approve signal <PAIRING_CODE>. - Guarda el número del bot como contacto en tu teléfono para evitar “Contacto desconocido”.
Importante: registrar una cuenta de número de teléfono con signal-cli puede des-autenticar la sesión principal de la app Signal para ese número. Prefiere un número de bot dedicado, o usa el modo de enlace QR si necesitas mantener la configuración existente de tu app.
Referencias upstream:
- README de
signal-cli:https://github.com/AsamK/signal-cli - Flujo de captcha:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - Flujo de enlace:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
Modo daemon externo (httpUrl)
Si quieres gestionar signal-cli tú mismo (arranques en frío lentos del JVM, init de contenedor, o CPUs compartidas), ejecuta el daemon por separado y apunta OpenClaw a él:
{
channels: {
signal: {
httpUrl: "http://127.0.0.1:8080",
autoStart: false,
},
},
}
Esto omite el auto-spawn y la espera de inicio dentro de OpenClaw. Para arranques lentos al auto-spawn, configura channels.signal.startupTimeoutMs.
Control de acceso (DMs + grupos)
DMs:
- Predeterminado:
channels.signal.dmPolicy = "pairing". - Los remitentes desconocidos reciben un código de emparejamiento; los mensajes se ignoran hasta que se aprueben (los códigos expiran después de 1 hora).
- Aprobar vía:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- El emparejamiento es el intercambio de token predeterminado para DMs de Signal. Detalles: Emparejamiento
- Los remitentes solo UUID (de
sourceUuid) se almacenan comouuid:<id>enchannels.signal.allowFrom.
Grupos:
channels.signal.groupPolicy = open | allowlist | disabled.channels.signal.groupAllowFromcontrola quién puede activar en grupos cuandoallowlistestá configurado.channels.signal.groups["<group-id>" | "*"]puede anular el comportamiento de grupo conrequireMention,toolsytoolsBySender.- Usa
channels.signal.accounts.<id>.groupspara anulaciones por cuenta en configuraciones multi-cuenta. - Nota de ejecución: si
channels.signalfalta completamente, el runtime recurre agroupPolicy="allowlist"para verificaciones de grupo (incluso sichannels.defaults.groupPolicyestá configurado).
Cómo funciona (comportamiento)
signal-clise ejecuta como daemon; el gateway lee eventos vía SSE.- Los mensajes entrantes se normalizan en el envelope compartido del canal.
- Las respuestas siempre se enrutan de vuelta al mismo número o grupo.
Multimedia + límites
- El texto saliente se fragmenta a
channels.signal.textChunkLimit(predeterminado 4000). - Fragmentado por nueva línea opcional: configura
channels.signal.chunkMode="newline"para dividir en líneas en blanco (límites de párrafo) antes del fragmentado por longitud. - Adjuntos soportados (base64 obtenido de
signal-cli). - Límite de multimedia predeterminado:
channels.signal.mediaMaxMb(predeterminado 8). - Usa
channels.signal.ignoreAttachmentspara omitir la descarga de multimedia. - El contexto de historial de grupo usa
channels.signal.historyLimit(ochannels.signal.accounts.*.historyLimit), recurriendo amessages.groupChat.historyLimit. Configura0para deshabilitar (predeterminado 50).
Escritura + confirmaciones de lectura
- Indicadores de escritura: OpenClaw envía señales de escritura vía
signal-cli sendTypingy las refresca mientras se ejecuta una respuesta. - Confirmaciones de lectura: cuando
channels.signal.sendReadReceiptses true, OpenClaw reenvía confirmaciones de lectura para DMs permitidos. - Signal-cli no expone confirmaciones de lectura para grupos.
Reacciones (herramienta de mensajes)
- Usa
message action=reactconchannel=signal. - Destinos: E.164 del remitente o UUID (usa
uuid:<id>de la salida de emparejamiento; el UUID sin formato también funciona). messageIdes el timestamp de Signal del mensaje al que reaccionas.- Las reacciones en grupo requieren
targetAuthorotargetAuthorUuid.
Ejemplos:
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=✅
Configuración:
channels.signal.actions.reactions: habilitar/deshabilitar acciones de reacción (predeterminado true).channels.signal.reactionLevel:off | ack | minimal | extensive.off/ackdeshabilita reacciones del agente (la herramienta de mensajesreactdará error).minimal/extensivehabilita reacciones del agente y establece el nivel de guía.
- Anulaciones por cuenta:
channels.signal.accounts.<id>.actions.reactions,channels.signal.accounts.<id>.reactionLevel.
Destinos de entrega (CLI/cron)
- DMs:
signal:+15551234567(o E.164 sin formato). - DMs por UUID:
uuid:<id>(o UUID sin formato). - Grupos:
signal:group:<groupId>. - Nombres de usuario:
username:<name>(si es compatible con tu cuenta de Signal).
Resolución de problemas
Ejecuta esta secuencia primero:
openclaw status
openclaw gateway status
openclaw logs --follow
openclaw doctor
openclaw channels status --probe
Luego confirma el estado de emparejamiento de DM si es necesario:
openclaw pairing list signal
Fallos comunes:
- Daemon accesible pero sin respuestas: verifica la configuración de cuenta/daemon (
httpUrl,account) y el modo de recepción. - DMs ignorados: el remitente está pendiente de aprobación de emparejamiento.
- Mensajes de grupo ignorados: el control de remitente/mención de grupo bloquea la entrega.
- Errores de validación de configuración después de ediciones: ejecuta
openclaw doctor --fix. - Signal falta en los diagnósticos: confirma
channels.signal.enabled: true.
Verificaciones adicionales:
openclaw pairing list signal
pgrep -af signal-cli
grep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20
Para el flujo de diagnóstico: /channels/troubleshooting.
Notas de seguridad
signal-clialmacena las claves de cuenta localmente (normalmente~/.local/share/signal-cli/data/).- Haz respaldo del estado de la cuenta de Signal antes de migración o reconstrucción del servidor.
- Mantén
channels.signal.dmPolicy: "pairing"a menos que quieras explícitamente acceso DM más amplio. - La verificación por SMS solo es necesaria para flujos de registro o recuperación, pero perder el control del número/cuenta puede complicar el re-registro.
Referencia de configuración (Signal)
Configuración completa: Configuración
Opciones del proveedor:
channels.signal.enabled: habilitar/deshabilitar inicio del canal.channels.signal.account: E.164 de la cuenta del bot.channels.signal.cliPath: ruta asignal-cli.channels.signal.httpUrl: URL completa del daemon (anula host/port).channels.signal.httpHost,channels.signal.httpPort: bind del daemon (predeterminado 127.0.0.1:8080).channels.signal.autoStart: auto-spawn del daemon (predeterminado true sihttpUrlno está configurado).channels.signal.startupTimeoutMs: timeout de espera de inicio en ms (máximo 120000).channels.signal.receiveMode:on-start | manual.channels.signal.ignoreAttachments: omitir descarga de adjuntos.channels.signal.ignoreStories: ignorar historias del daemon.channels.signal.sendReadReceipts: reenviar confirmaciones de lectura.channels.signal.dmPolicy:pairing | allowlist | open | disabled(predeterminado: pairing).channels.signal.allowFrom: lista de acceso de DM (E.164 ouuid:<id>).openrequiere"*". Signal no tiene nombres de usuario; usa IDs de teléfono/UUID.channels.signal.groupPolicy:open | allowlist | disabled(predeterminado: allowlist).channels.signal.groupAllowFrom: lista de acceso de remitentes de grupo.channels.signal.groups: anulaciones por grupo indexadas por ID de grupo de Signal (o"*"). Campos soportados:requireMention,tools,toolsBySender.channels.signal.accounts.<id>.groups: versión por cuenta dechannels.signal.groupspara configuraciones multi-cuenta.channels.signal.historyLimit: máximo de mensajes de grupo para incluir como contexto (0 deshabilita).channels.signal.dmHistoryLimit: límite de historial de DM en turnos de usuario. Anulaciones por usuario:channels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: tamaño de fragmento saliente (caracteres).channels.signal.chunkMode:length(predeterminado) onewlinepara dividir en líneas en blanco (límites de párrafo) antes del fragmentado por longitud.channels.signal.mediaMaxMb: límite de multimedia entrante/saliente (MB).
Opciones globales relacionadas:
agents.list[].groupChat.mentionPatterns(Signal no soporta menciones nativas).messages.groupChat.mentionPatterns(respaldo global).messages.responsePrefix.