Mainstream messaging
Signal
Stato: integrazione CLI esterna. Gateway comunica con signal-cli tramite HTTP: demone nativo (JSON-RPC + SSE) oppure container bbernhard/signal-cli-rest-api (REST + WebSocket).
Prerequisiti
- OpenClaw installato sul tuo server (il flusso Linux sotto è stato testato su Ubuntu 24).
- Uno tra:
signal-clidisponibile sull'host (modalità nativa), oppure- container Docker
bbernhard/signal-cli-rest-api(modalità container).
- Un numero di telefono che possa ricevere un SMS di verifica (per il percorso di registrazione via SMS).
- Accesso al browser per il captcha di Signal (
signalcaptchas.org) durante la registrazione.
Configurazione rapida (principianti)
- Usa un numero Signal separato per il bot (consigliato).
- Installa il Plugin OpenClaw:
openclaw plugins install @openclaw/signal- Installa
signal-cli(Java è richiesto se usi la build JVM). - Scegli un percorso di configurazione:
- Percorso A (collegamento QR):
signal-cli link -n "OpenClaw"e scansiona con Signal. - Percorso B (registrazione SMS): registra un numero dedicato con captcha + verifica SMS.
- Percorso A (collegamento QR):
- Configura OpenClaw e riavvia il Gateway.
- Invia un primo DM e approva l'abbinamento (
openclaw pairing approve signal <CODE>).
Configurazione minima:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}Riferimento dei campi:
| Campo | Descrizione |
|---|---|
account |
Numero di telefono del bot in formato E.164 (+15551234567) |
cliPath |
Percorso di signal-cli (signal-cli se è nel PATH) |
configPath |
Directory di configurazione di signal-cli passata come --config |
dmPolicy |
Criterio di accesso ai DM (pairing consigliato) |
allowFrom |
Numeri di telefono o valori uuid:<id> autorizzati a inviare DM |
Che cos'è
- Canale Signal tramite
signal-cli(non libsignal incorporato). - Routing deterministico: le risposte tornano sempre a Signal.
- I DM condividono la sessione principale dell'agente; i gruppi sono isolati (
agent:<agentId>:signal:group:<groupId>).
Scritture di configurazione
Per impostazione predefinita, Signal può scrivere aggiornamenti di configurazione attivati da /config set|unset (richiede commands.config: true).
Disabilita con:
{ channels: { signal: { configWrites: false } },}Il modello dei numeri (importante)
- Il Gateway si connette a un dispositivo Signal (l'account
signal-cli). - Se esegui il bot sul tuo account Signal personale, ignorerà i tuoi messaggi (protezione dai loop).
- Per "scrivo al bot e lui risponde", usa un numero bot separato.
Percorso di configurazione A: collega un account Signal esistente (QR)
- Installa
signal-cli(build JVM o nativa). - Collega un account bot:
signal-cli link -n "OpenClaw"quindi scansiona il QR in Signal.
- Configura Signal e avvia il Gateway.
Esempio:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}Supporto multi-account: usa channels.signal.accounts con configurazione per account e name opzionale. Vedi gateway/configuration per il modello condiviso.
Percorso di configurazione B: registra un numero bot dedicato (SMS, Linux)
Usa questo percorso quando vuoi un numero bot dedicato invece di collegare un account dell'app Signal esistente.
- Procurati un numero che possa ricevere SMS (o verifica vocale per linee fisse).
- Usa un numero bot dedicato per evitare conflitti di account/sessione.
- Installa
signal-clisull'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 /optsudo ln -sf /opt/signal-cli /usr/local/bin/signal-cli --versionSe usi la build JVM (signal-cli-${VERSION}.tar.gz), installa prima JRE 25+.
Mantieni signal-cli aggiornato; upstream segnala che le vecchie release possono smettere di funzionare quando le API server di Signal cambiano.
- Registra e verifica il numero:
signal-cli -a +<BOT_PHONE_NUMBER> registerSe il captcha è richiesto:
- Apri
https://signalcaptchas.org/registration/generate.html. - Completa il captcha, copia la destinazione del link
signalcaptcha://...da "Open Signal". - Esegui dal medesimo IP esterno della sessione del browser quando possibile.
- Esegui di nuovo la registrazione immediatamente (i token captcha scadono rapidamente):
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>- Configura OpenClaw, riavvia il Gateway, verifica il canale:
# If you run the gateway as a user systemd service:systemctl --user restart openclaw-gateway.service # Then verify:openclaw doctoropenclaw channels status --probe- Abbina il mittente DM:
- Invia qualsiasi messaggio al numero del bot.
- Approva il codice sul server:
openclaw pairing approve signal <PAIRING_CODE>. - Salva il numero del bot come contatto sul telefono per evitare "Unknown contact".
Riferimenti upstream:
- README di
signal-cli:https://github.com/AsamK/signal-cli - Flusso captcha:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - Flusso di collegamento:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
Modalità demone esterno (httpUrl)
Se vuoi gestire signal-cli autonomamente (avvii JVM a freddo lenti, inizializzazione container o CPU condivise), esegui il demone separatamente e indirizza OpenClaw a esso:
{ channels: { signal: { httpUrl: "http://127.0.0.1:8080", autoStart: false, }, },}Questo salta l'avvio automatico e l'attesa di startup dentro OpenClaw. Per avvii lenti durante l'avvio automatico, imposta channels.signal.startupTimeoutMs.
Modalità container (bbernhard/signal-cli-rest-api)
Invece di eseguire signal-cli nativamente, puoi usare il container Docker bbernhard/signal-cli-rest-api. Questo incapsula signal-cli dietro un'API REST e un'interfaccia WebSocket.
Requisiti:
- Il container deve essere eseguito con
MODE=json-rpcper la ricezione dei messaggi in tempo reale. - Registra o collega il tuo account Signal dentro il container prima di connettere OpenClaw.
Servizio docker-compose.yml di esempio:
signal-cli: image: bbernhard/signal-cli-rest-api:latest environment: MODE: json-rpc ports: - "8080:8080" volumes: - signal-cli-data:/home/.local/share/signal-cliConfigurazione OpenClaw:
{ channels: { signal: { enabled: true, account: "+15551234567", httpUrl: "http://signal-cli:8080", autoStart: false, apiMode: "container", // or "auto" to detect automatically }, },}Il campo apiMode controlla quale protocollo usa OpenClaw:
| Valore | Comportamento |
|---|---|
"auto" |
(Predefinito) Sonda entrambi i trasporti; lo streaming valida la ricezione WebSocket del container |
"native" |
Forza signal-cli nativo (JSON-RPC su /api/v1/rpc, SSE su /api/v1/events) |
"container" |
Forza il container bbernhard (REST su /v2/send, WebSocket su /v1/receive/{account}) |
Quando apiMode è "auto", OpenClaw memorizza nella cache la modalità rilevata per 30 secondi per evitare sonde ripetute. La ricezione container viene selezionata per lo streaming solo dopo che /v1/receive/{account} effettua l'upgrade a WebSocket, cosa che richiede MODE=json-rpc.
La modalità container supporta le stesse operazioni del canale Signal della modalità nativa quando il container espone API corrispondenti: invii, ricezioni, allegati, indicatori di digitazione, conferme di lettura/visualizzazione, reazioni, gruppi e testo con stile. OpenClaw traduce le sue chiamate RPC Signal native nei payload REST del container, inclusi gli ID gruppo group.{base64(internal_id)} e text_mode: "styled" per il testo formattato.
Note operative:
- Usa
autoStart: falsecon la modalità container. OpenClaw non dovrebbe avviare un demone nativo quandoapiMode: "container"è selezionato. - Usa
MODE=json-rpcper la ricezione.MODE=normalpuò far apparire sano/v1/about, ma/v1/receive/{account}non effettua l'upgrade a WebSocket, quindi OpenClaw non selezionerà lo streaming di ricezione container in modalitàauto. - Imposta
apiMode: "container"quando sai chehttpUrlpunta all'API REST di bbernhard. ImpostaapiMode: "native"quando sai che punta a JSON-RPC/SSE disignal-clinativo. Usa"auto"quando il deployment può variare. - I download degli allegati container rispettano gli stessi limiti di byte per i media della modalità nativa. Le risposte troppo grandi vengono rifiutate prima di essere bufferizzate completamente quando il server invia
Content-Length, e altrimenti durante lo streaming.
Controllo degli accessi (DM + gruppi)
DM:
- Predefinito:
channels.signal.dmPolicy = "pairing". - I mittenti sconosciuti ricevono un codice di abbinamento; i messaggi vengono ignorati finché non sono approvati (i codici scadono dopo 1 ora).
- Approva tramite:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- L'abbinamento è lo scambio di token predefinito per i DM Signal. Dettagli: Abbinamento
- I mittenti solo UUID (da
sourceUuid) sono memorizzati comeuuid:<id>inchannels.signal.allowFrom.
Gruppi:
channels.signal.groupPolicy = open | allowlist | disabled.channels.signal.groupAllowFromcontrolla quali gruppi o mittenti possono attivare risposte di gruppo quandoallowlistè impostato; le voci possono essere ID gruppo Signal (grezzi,group:<id>osignal:group:<id>), numeri di telefono dei mittenti, valoriuuid:<id>o*.channels.signal.groups["<group-id>" | "*"]può sovrascrivere il comportamento del gruppo conrequireMention,toolsetoolsBySender.- Usa
channels.signal.accounts.<id>.groupsper override per account nelle configurazioni multi-account. - L'inserimento di un gruppo Signal nell'allowlist tramite
groupAllowFromnon disabilita di per sé il vincolo della menzione. Una vocechannels.signal.groups["<group-id>"]configurata specificamente elabora ogni messaggio del gruppo a meno cherequireMention=truesia impostato. - Nota di runtime: se
channels.signalmanca completamente, il runtime ripiega sugroupPolicy="allowlist"per i controlli di gruppo (anche sechannels.defaults.groupPolicyè impostato).
Come funziona (comportamento)
- Modalità nativa:
signal-cliviene eseguito come demone; il Gateway legge gli eventi tramite SSE. - Modalità container: il Gateway invia tramite API REST e riceve tramite WebSocket.
- I messaggi in ingresso vengono normalizzati nell'envelope del canale condiviso.
- Le risposte vengono sempre instradate allo stesso numero o gruppo.
Media + limiti
- Il testo in uscita viene suddiviso in blocchi secondo
channels.signal.textChunkLimit(predefinito 4000). - Suddivisione opzionale per righe vuote: imposta
channels.signal.chunkMode="newline"per dividere sulle righe vuote (confini di paragrafo) prima della suddivisione per lunghezza. - Allegati supportati (base64 recuperato da
signal-cli). - Gli allegati nota vocale usano il nome file di
signal-clicome fallback MIME quandocontentTypemanca, così la trascrizione audio può comunque classificare i promemoria vocali AAC. - Limite media predefinito:
channels.signal.mediaMaxMb(predefinito 8). - Usa
channels.signal.ignoreAttachmentsper saltare il download dei media. - Il contesto della cronologia di gruppo usa
channels.signal.historyLimit(ochannels.signal.accounts.*.historyLimit), con fallback amessages.groupChat.historyLimit. Imposta0per disabilitare (predefinito 50).
Digitazione + conferme di lettura
- Indicatori di digitazione: OpenClaw invia segnali di digitazione tramite
signal-cli sendTypinge li aggiorna mentre è in corso una risposta. - Conferme di lettura: quando
channels.signal.sendReadReceiptsè true, OpenClaw inoltra le conferme di lettura per i DM consentiti. - Signal-cli non espone le conferme di lettura per i gruppi.
Reazioni di stato del ciclo di vita
Imposta messages.statusReactions.enabled: true per consentire a Signal di mostrare il ciclo di vita condiviso delle reazioni
queued/thinking/tool/compaction/done/error sui turni in ingresso.
Signal usa il timestamp del messaggio in ingresso come destinazione della reazione; le reazioni
di gruppo vengono inviate con l'id del gruppo Signal più il mittente originale come
autore di destinazione.
Le reazioni di stato richiedono anche una reazione di conferma e un
messages.ackReactionScope corrispondente (direct, group-all, group-mentions o all).
Imposta channels.signal.reactionLevel: "off" per disabilitare le reazioni di stato di Signal.
L'azione react dello strumento messaggio rimane più restrittiva: richiede
reactionLevel: "minimal" o "extensive".
messages.removeAckAfterReply: true rimuove la reazione di stato finale dopo il
tempo di mantenimento configurato. In caso contrario, Signal ripristina la reazione di conferma iniziale dopo
lo stato finale done/error.
Reazioni (strumento messaggio)
- Usa
message action=reactconchannel=signal. - Destinazioni: mittente E.164 o UUID (usa
uuid:<id>dall'output di associazione; funziona anche un UUID semplice). messageIdè il timestamp Signal del messaggio a cui stai reagendo.- Le reazioni di gruppo richiedono
targetAuthorotargetAuthorUuid.
Esempi:
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=truemessage action=react channel=signal target=signal:group:<groupId> targetAuthor=uuid:<sender-uuid> messageId=1737630212345 emoji=✅Configurazione:
channels.signal.actions.reactions: abilita/disabilita le azioni di reazione (predefinito true).channels.signal.reactionLevel:off | ack | minimal | extensive.off/ackdisabilita le reazioni dell'agente (lo strumento messaggioreactrestituirà un errore).minimal/extensiveabilita le reazioni dell'agente e imposta il livello di guida.
- Override per account:
channels.signal.accounts.<id>.actions.reactions,channels.signal.accounts.<id>.reactionLevel.
Reazioni di approvazione
I prompt di approvazione di esecuzione Signal e dei plugin usano i blocchi di instradamento di primo livello approvals.exec e
approvals.plugin. Signal non ha un blocco
channels.signal.execApprovals.
👍approva una volta.👎nega.- Usa
/approve <id> allow-alwaysquando una richiesta offre un'approvazione persistente.
La risoluzione delle reazioni di approvazione richiede approvatori Signal espliciti da
channels.signal.allowFrom, channels.signal.defaultTo o dai campi corrispondenti a livello di account.
I prompt di approvazione exec diretti nella stessa chat possono comunque sopprimere il fallback locale /approve duplicato
senza approvatori espliciti; le approvazioni di gruppo senza approvatore mantengono visibile il fallback locale.
Destinazioni di consegna (CLI/cron)
- DM:
signal:+15551234567(o E.164 semplice). - DM UUID:
uuid:<id>(o UUID semplice). - Gruppi:
signal:group:<groupId>. - Nomi utente:
username:<name>(se supportati dal tuo account Signal).
Alias
Configura gli alias quando vuoi nomi stabili per destinazioni Signal ricorrenti. Gli alias sono solo configurazione lato OpenClaw; non creano né modificano contatti Signal.
{ channels: { signal: { aliases: { me: "+15557654321", jane: "uuid:123e4567-e89b-12d3-a456-426614174000", ops: "group:<groupId>", }, defaultTo: "signal:me", }, },}Usa gli alias ovunque siano accettate destinazioni di consegna Signal:
openclaw message send --channel signal --target signal:ops --message "Deployment is complete"Gli alias per account ereditano gli alias di primo livello e possono aggiungere o sovrascrivere nomi:
{ channels: { signal: { aliases: { me: "+15557654321", }, accounts: { work: { aliases: { ops: "group:<workGroupId>", }, }, }, }, },}openclaw directory peers list --channel signal e
openclaw directory groups list --channel signal elencano gli alias configurati. La
directory Signal è basata sulla configurazione; non interroga in tempo reale i contatti Signal né
modifica l'account Signal.
Risoluzione dei problemi
Esegui prima questa sequenza:
openclaw statusopenclaw gateway statusopenclaw logs --followopenclaw doctoropenclaw channels status --probePoi conferma lo stato di associazione dei DM, se necessario:
openclaw pairing list signalErrori comuni:
- Demone raggiungibile ma nessuna risposta: verifica le impostazioni account/demone (
httpUrl,account) e la modalità di ricezione. - DM ignorati: il mittente è in attesa di approvazione dell'associazione.
- Messaggi di gruppo ignorati: il gating per mittente/menzione del gruppo blocca la consegna.
- Errori di validazione della configurazione dopo modifiche: esegui
openclaw doctor --fix. - Signal assente dalla diagnostica: conferma
channels.signal.enabled: true.
Controlli aggiuntivi:
openclaw pairing list signalpgrep -af signal-cligrep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20Per il flusso di triage: /channels/troubleshooting.
Note sulla sicurezza
signal-cliarchivia localmente le chiavi dell'account (in genere~/.local/share/signal-cli/data/).- Esegui il backup dello stato dell'account Signal prima di una migrazione o ricostruzione del server.
- Mantieni
channels.signal.dmPolicy: "pairing"salvo che tu voglia esplicitamente un accesso DM più ampio. - La verifica via SMS è necessaria solo per i flussi di registrazione o recupero, ma perdere il controllo del numero/account può complicare la nuova registrazione.
Riferimento di configurazione (Signal)
Configurazione completa: Configurazione
Opzioni del provider:
channels.signal.enabled: abilita/disabilita l'avvio del canale.channels.signal.apiMode:auto | native | container(predefinito: auto). Vedi Modalità container.channels.signal.account: E.164 per l'account del bot.channels.signal.cliPath: percorso disignal-cli.channels.signal.configPath: directory opzionalesignal-cli --config.channels.signal.httpUrl: URL completo del demone (sovrascrive host/porta).channels.signal.httpHost,channels.signal.httpPort: bind del demone (predefinito 127.0.0.1:8080).channels.signal.autoStart: avvia automaticamente il demone (predefinito true sehttpUrlnon è impostato).channels.signal.startupTimeoutMs: timeout di attesa dell'avvio in ms (limite 120000).channels.signal.receiveMode:on-start | manual.channels.signal.ignoreAttachments: salta il download degli allegati.channels.signal.ignoreStories: ignora le storie dal demone.channels.signal.sendReadReceipts: inoltra le conferme di lettura.channels.signal.dmPolicy:pairing | allowlist | open | disabled(predefinito: pairing).channels.signal.allowFrom: allowlist DM (E.164 ouuid:<id>).openrichiede"*". Signal non ha nomi utente; usa gli ID telefono/UUID.channels.signal.aliases: alias lato OpenClaw per destinazioni di consegna DM o di gruppo.channels.signal.groupPolicy:open | allowlist | disabled(predefinito: allowlist).channels.signal.groupAllowFrom: allowlist di gruppo; accetta ID di gruppo Signal (raw,group:<id>osignal:group:<id>), numeri E.164 dei mittenti o valoriuuid:<id>.channels.signal.groups: override per gruppo indicizzati per id del gruppo Signal (o"*"). Campi supportati:requireMention,tools,toolsBySender.channels.signal.accounts.<id>.groups: versione per account dichannels.signal.groupsper configurazioni multi-account.channels.signal.accounts.<id>.aliases: alias per account, uniti agli alias di primo livello.channels.signal.historyLimit: numero massimo di messaggi di gruppo da includere come contesto (0 disabilita).channels.signal.dmHistoryLimit: limite della cronologia DM nei turni utente. Override per utente:channels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: dimensione dei blocchi in uscita (caratteri).channels.signal.chunkMode:length(predefinito) onewlineper dividere sulle righe vuote (confini di paragrafo) prima della suddivisione per lunghezza.channels.signal.mediaMaxMb: limite dei media in ingresso/uscita (MB).
Opzioni globali correlate:
agents.list[].groupChat.mentionPatterns(Signal non supporta le menzioni native).messages.groupChat.mentionPatterns(fallback globale).messages.responsePrefix.
Correlati
- Panoramica dei canali — tutti i canali supportati
- Associazione — autenticazione DM e flusso di associazione
- Gruppi — comportamento delle chat di gruppo e gating delle menzioni
- Instradamento dei canali — instradamento delle sessioni per i messaggi
- Sicurezza — modello di accesso e hardening