Bot de Signal con IA local
Qué cubre este artículo
- Cómo construir un bot de Signal con signal-cli y Ollama.
- Registro de número de bot y emparejamiento de dispositivo.
- Recepción y envío mediante JSON-RPC y modo daemon.
- Extensiones: grupos, RAG, adjuntos, reacciones.
- Por qué Signal es la plataforma de bots más privada.
Introducción
Signal es la única plataforma convencional con cifrado de extremo a extremo genuino para todo, incluidos los mensajes de bot. Si necesitas un bot de IA para comunicación confidencial (periodistas, abogados, secretos empresariales), Signal es tu opción.
El inconveniente: no existe una API oficial de bot. El enfoque estándar es signal-cli, un CLI de Java que implementa el protocolo Signal y ofrece modo daemon con JSON-RPC. Técnicamente, tu bot es un “cliente de Signal” que funciona como un dispositivo normal.
Casos de uso típicos
- Asistente de IA confidencial: Los chats permanecen cifrados de extremo a extremo hasta tu servidor, ideal para preguntas sensibles.
- Bot para familia o equipo: Comunicación interna sin Meta, Google ni nubes.
- Alertas: Notificaciones de monitoreo cifradas de extremo a extremo en el móvil (mejor que email).
- Asistente de documentos: Envía documentos confidenciales por Signal para procesar localmente.
- Contacto editorial: Las fuentes pueden hablar anónimamente con la IA.
Requisitos previos
- Un número de teléfono para el bot (funciona teléfono fijo: verificación por llamada; o segunda SIM/eSIM)
- Java 17+ (signal-cli es Java) o la imagen Docker
- Ollama con un modelo (como
llama3.1:8b) - Python para la lógica del bot
Paso 1: instalar y registrar signal-cli
# Descarga binaria (Linux)
wget https://github.com/AsamK/signal-cli/releases/download/v0.13.x/signal-cli-0.13.x-Linux.tar.gz
sudo tar xf signal-cli-*.tar.gz -C /opt
sudo ln -s /opt/signal-cli-*/bin/signal-cli /usr/local/bin/signal-cli
Registra el número (requiere captcha: obtén el enlace de https://signalcaptchas.org/):
signal-cli -a +4917612345678 register
signal-cli -a +4917612345678 verify 123456
signal-cli -a +4917612345678 updateProfile --name "Asistente de IA"
Alternativa: vincula el bot como dispositivo a tu cuenta existente. El bot enviará mensajes como tú (adecuado para asistentes personales, no para bots públicos):
signal-cli link -n "Bot-Server"
# devuelve enlace sgnl:// → muéstralo como código QR en el móvil (p. ej., con qrencode) y escanéalo
Paso 2: modo daemon con JSON-RPC
signal-cli puede ejecutarse como daemon JSON-RPC. Tu código Python se comunica por TCP o HTTP:
# Daemon TCP
signal-cli -a +4917612345678 daemon --tcp 127.0.0.1:7583
# o HTTP (estilo REST)
signal-cli -a +4917612345678 daemon --http 127.0.0.1:8080
Métodos JSON-RPC (selección): send, receive, listGroups, sendTyping, addReaction, updateProfile.
Paso 3: lógica del bot con Ollama
La forma más simple es un loop de receive mediante llamadas CLI (bueno para empezar):
#!/usr/bin/env python3
import json
import subprocess
import ollama
BOT_NUMBER = "+4917612345678"
MODEL = "llama3.1:8b"
ALLOWED = {"+491701234567"} # Quién puede usar el bot
conversations = {}
client = ollama.Client(host="http://localhost:11434")
def send(recipient, text):
subprocess.run([
"signal-cli", "-a", BOT_NUMBER, "send",
"-m", text, recipient
], check=False)
def ask_ollama(user, text):
history = conversations.setdefault(user, [])
history.append({"role": "user", "content": text})
history = history[-10:]
resp = client.chat(
model=MODEL,
messages=[{"role": "system", "content":
"Eres un asistente útil. Responde brevemente."}] + history,
)
answer = resp["message"]["content"]
history.append({"role": "assistant", "content": answer})
conversations[user] = history
return answer
def main():
proc = subprocess.Popen(
["signal-cli", "-a", BOT_NUMBER, "receive", "-t", "-1",
"--output", "json"],
stdout=subprocess.PIPE, text=True,
)
for line in proc.stdout:
line = line.strip()
if not line:
continue
try:
envelope = json.loads(line)
except json.JSONDecodeError:
continue
msg = envelope.get("envelope", {})
source = msg.get("sourceNumber") or msg.get("source")
data = msg.get("dataMessage")
if not data or source not in ALLOWED:
continue
text = data.get("message")
if not text:
continue
print(f"[{source}] {text}")
answer = ask_ollama(source, text)
# Límite de Signal: ~64k, pero las respuestas cortas son mejores
send(source, answer[:6000])
if __name__ == "__main__":
main()
Funciona inmediatamente: modo polling, sin webhooks.
Extensiones
Funcionamiento en grupos
signal-cli puede gestionar grupos. El bot responde en grupos solo si se menciona o hay un prefijo:
data = msg.get("dataMessage")
group = data.get("groupInfo") # {"groupId": "...", "type": "..."}
text = data.get("message") or ""
if group:
if not text.startswith("!ki"):
continue
text = text[3:].strip()
# La respuesta va al grupo:
subprocess.run(["signal-cli", "-a", BOT_NUMBER, "send",
"-g", group["groupId"], "-m", answer])
Crea o gestiona grupos por CLI:
signal-cli -a +49... updateGroup -n "IA-Equipo" -m +491701234567 +491702345678
signal-cli -a +49... listGroups
Reacciones e indicador de escritura
# Mostrar que está escribiendo
signal-cli -a +49... sendTyping +491701234567
# Enviar reacción
signal-cli -a +49... sendReaction -e "👍" -a +491701234567 -t 1695123456789 +491701234567
Adjuntos: imágenes a modelo de visión
dataMessage.attachments contiene rutas de archivos: envía imágenes a minicpm-v o llava, audio a Whisper:
for att in data.get("attachments", []):
if att.get("contentType", "").startswith("image/"):
resp = client.chat(model="minicpm-v", messages=[{
"role": "user",
"content": "¿Qué hay en esta imagen?",
"images": [att["file"]],
}])
send(source, resp["message"]["content"])
RAG como en Telegram
Patrón idéntico: embedding del mensaje → Qdrant → contexto en el prompt del sistema. Ver Bot de Telegram con RAG y RAG local.
Implementación
Docker: signal-cli como daemon
services:
signal-cli:
image: registry.gitlab.com/morph027/signal-cli-daemon:latest
volumes:
- signal_data:/home/.local/share/signal-cli
environment:
- MODE=json-rpc
- SIGNAL_NUMBER=+4917612345678
ports:
- "127.0.0.1:7583:7583"
restart: always
signal-bot:
build: ./bot
restart: always
depends_on: [signal-cli, ollama]
ollama:
image: ollama/ollama:latest
volumes: [ollama_data:/root/.ollama]
volumes:
signal_data:
ollama_data:
systemd sin Docker
[Unit]
Description=Bot de IA Signal
After=network-online.target
[Service]
Type=simple
User=signalbot
WorkingDirectory=/opt/signal-bot
ExecStart=/usr/bin/python3 bot.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Privacidad, la verdadera razón para elegir Signal
- E2EE completo: Los mensajes se cifran de extremo a extremo entre el remitente y el servidor del bot. Los servidores de Signal solo ven metadatos y además los minimizan.
- Sin publicidad ni rastreo: Signal es una asociación sin ánimo de lucro.
- Código abierto: El cliente, el servidor y signal-cli son de código abierto.
- Límite importante: El bot descifra los mensajes en tu servidor, así que aplicas tus propias reglas. De todas formas, Signal sigue viendo los metadatos (quién escribe y cuándo).
Problemas comunes
- Captcha en el registro: Signal exige captchas durante el registro. Solución: registra la cuenta primero en un teléfono, luego vincula el bot como dispositivo asociado.
- Número bloqueado: Si Signal bloquea el número (raro), ejecuta
signal-cli ... registerde nuevo. - El daemon falla: signal-cli está hecho en Java; si se queda sin memoria, establece
JAVA_OPTS="-Xmx512m". - Recepción se ralentiza: En el bucle
receive, las respuestas lentas bloquean el flujo. Traslade las llamadas a Ollama a un hilo o async. - Sealed Sender: Los mensajes de contactos desconocidos requieren confianza. Use
signal-cli trust -a <número>para añadir contactos.
Enlaces relacionados
- IRC-Coding.de: Tutoriales de programación en profundidad sobre JSON-RPC, manejo de subprocesos y arquitecturas de bots.
- Matrix-Bots: Alternativa con API oficial para bots y E2EE.
- Telegram-Bots: La plataforma de bots más sencilla.
- Comparativa de plataformas: Cuál usar para cada caso.
- Privacidad: Fundamentos legales.
- Ollama: Servidor de modelos.
Puntos clave:
- Los bots de Signal se ejecutan sobre signal-cli (daemon + JSON-RPC), no mediante una API oficial.
- Es la única plataforma con E2EE completo, perfecta para bots confidenciales.
- Configuración: registra el número o vincula como dispositivo asociado, luego inicia el bucle de recepción.
- Extensiones como en cualquier otra plataforma: grupos, RAG, visión, Whisper.
- Para bots públicos es engorroso. Telegram es más simple, Signal es más privado.
FAQ
¿Existe una API oficial de bots para Signal?
¿Necesito un número de teléfono propio?
¿Están realmente cifrados los mensajes del bot?
El registro falla por captcha, ¿qué hago?
¿Funciona el bot en grupos?
¿Es signal-cli lo suficientemente rápido?
¿Signal o Matrix para bots privados?
Fuentes y lecturas recomendadas
- signal-cli: Documentación de CLI y Daemon.
- signal-cli JSON-RPC: Referencia de API.
- Signal: Sitio web oficial.
- IRC-Coding.de: Tutoriales de programación.


