Mainstream messaging
Signal
État : intégration CLI externe. Gateway communique avec signal-cli via HTTP — soit avec le démon natif (JSON-RPC + SSE), soit avec le conteneur bbernhard/signal-cli-rest-api (REST + WebSocket).
Prérequis
- OpenClaw installé sur votre serveur (le flux Linux ci-dessous a été testé sur Ubuntu 24).
- L’un des éléments suivants :
signal-clidisponible sur l’hôte (mode natif), ou- le conteneur Docker
bbernhard/signal-cli-rest-api(mode conteneur).
- Un numéro de téléphone pouvant recevoir un SMS de vérification (pour le parcours d’inscription par SMS).
- Accès au navigateur pour le captcha Signal (
signalcaptchas.org) pendant l’inscription.
Configuration rapide (débutant)
- Utilisez un numéro Signal distinct pour le bot (recommandé).
- Installez le Plugin OpenClaw :
openclaw plugins install @openclaw/signal- Installez
signal-cli(Java est requis si vous utilisez la version JVM). - Choisissez un parcours de configuration :
- Parcours A (lien QR) :
signal-cli link -n "OpenClaw"puis scannez avec Signal. - Parcours B (inscription par SMS) : inscrivez un numéro dédié avec captcha + vérification par SMS.
- Parcours A (lien QR) :
- Configurez OpenClaw et redémarrez le Gateway.
- Envoyez un premier MP et approuvez l’association (
openclaw pairing approve signal <CODE>).
Configuration minimale :
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}Référence des champs :
| Champ | Description |
|---|---|
account |
Numéro de téléphone du bot au format E.164 (+15551234567) |
cliPath |
Chemin vers signal-cli (signal-cli s’il est dans le PATH) |
configPath |
Répertoire de configuration signal-cli passé comme --config |
dmPolicy |
Politique d’accès aux MP (pairing recommandé) |
allowFrom |
Numéros de téléphone ou valeurs uuid:<id> autorisés à envoyer des MP |
Ce que c’est
- Canal Signal via
signal-cli(pas libsignal intégré). - Routage déterministe : les réponses retournent toujours vers Signal.
- Les MP partagent la session principale de l’agent ; les groupes sont isolés (
agent:<agentId>:signal:group:<groupId>).
Écritures de configuration
Par défaut, Signal est autorisé à écrire les mises à jour de configuration déclenchées par /config set|unset (nécessite commands.config: true).
Désactivez avec :
{ channels: { signal: { configWrites: false } },}Le modèle de numéro (important)
- Le Gateway se connecte à un appareil Signal (le compte
signal-cli). - Si vous exécutez le bot sur votre compte Signal personnel, il ignorera vos propres messages (protection contre les boucles).
- Pour « j’envoie un SMS au bot et il répond », utilisez un numéro de bot distinct.
Parcours de configuration A : lier un compte Signal existant (QR)
- Installez
signal-cli(version JVM ou native). - Liez un compte de bot :
signal-cli link -n "OpenClaw"puis scannez le QR dans Signal.
- Configurez Signal et démarrez le Gateway.
Exemple :
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}Prise en charge multi-comptes : utilisez channels.signal.accounts avec une configuration par compte et un name facultatif. Consultez gateway/configuration pour le modèle partagé.
Parcours de configuration B : inscrire un numéro de bot dédié (SMS, Linux)
Utilisez ceci lorsque vous voulez un numéro de bot dédié au lieu de lier un compte d’application Signal existant.
- Obtenez un numéro pouvant recevoir des SMS (ou une vérification vocale pour les lignes fixes).
- Utilisez un numéro de bot dédié pour éviter les conflits de compte/session.
- Installez
signal-clisur l’hôte du 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 --versionSi vous utilisez la version JVM (signal-cli-${VERSION}.tar.gz), installez d’abord JRE 25+.
Gardez signal-cli à jour ; le projet amont indique que les anciennes versions peuvent cesser de fonctionner lorsque les API serveur de Signal changent.
- Inscrivez et vérifiez le numéro :
signal-cli -a +<BOT_PHONE_NUMBER> registerSi un captcha est requis :
- Ouvrez
https://signalcaptchas.org/registration/generate.html. - Complétez le captcha, copiez la cible du lien
signalcaptcha://...depuis « Open Signal ». - Exécutez depuis la même IP externe que la session du navigateur lorsque c’est possible.
- Relancez immédiatement l’inscription (les jetons captcha expirent rapidement) :
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>- Configurez OpenClaw, redémarrez le Gateway, vérifiez le canal :
# If you run the gateway as a user systemd service:systemctl --user restart openclaw-gateway.service # Then verify:openclaw doctoropenclaw channels status --probe- Associez votre expéditeur de MP :
- Envoyez n’importe quel message au numéro du bot.
- Approuvez le code sur le serveur :
openclaw pairing approve signal <PAIRING_CODE>. - Enregistrez le numéro du bot comme contact sur votre téléphone pour éviter « Contact inconnu ».
Références amont :
- README de
signal-cli:https://github.com/AsamK/signal-cli - Flux captcha :
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - Flux de liaison :
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
Mode démon externe (httpUrl)
Si vous voulez gérer signal-cli vous-même (démarrages à froid lents de la JVM, initialisation de conteneur ou CPU partagés), exécutez le démon séparément et pointez OpenClaw vers lui :
{ channels: { signal: { httpUrl: "http://127.0.0.1:8080", autoStart: false, }, },}Cela ignore le lancement automatique et l’attente de démarrage à l’intérieur d’OpenClaw. Pour les démarrages lents lors du lancement automatique, définissez channels.signal.startupTimeoutMs.
Mode conteneur (bbernhard/signal-cli-rest-api)
Au lieu d’exécuter signal-cli nativement, vous pouvez utiliser le conteneur Docker bbernhard/signal-cli-rest-api. Celui-ci encapsule signal-cli derrière une API REST et une interface WebSocket.
Exigences :
- Le conteneur doit s’exécuter avec
MODE=json-rpcpour recevoir les messages en temps réel. - Inscrivez ou liez votre compte Signal à l’intérieur du conteneur avant de connecter OpenClaw.
Exemple de service docker-compose.yml :
signal-cli: image: bbernhard/signal-cli-rest-api:latest environment: MODE: json-rpc ports: - "8080:8080" volumes: - signal-cli-data:/home/.local/share/signal-cliConfiguration OpenClaw :
{ channels: { signal: { enabled: true, account: "+15551234567", httpUrl: "http://signal-cli:8080", autoStart: false, apiMode: "container", // or "auto" to detect automatically }, },}Le champ apiMode contrôle le protocole utilisé par OpenClaw :
| Valeur | Comportement |
|---|---|
"auto" |
(Par défaut) Sonde les deux transports ; le streaming valide la réception WebSocket du conteneur |
"native" |
Force signal-cli natif (JSON-RPC sur /api/v1/rpc, SSE sur /api/v1/events) |
"container" |
Force le conteneur bbernhard (REST sur /v2/send, WebSocket sur /v1/receive/{account}) |
Lorsque apiMode vaut "auto", OpenClaw met en cache le mode détecté pendant 30 secondes afin d’éviter les sondes répétées. La réception conteneur n’est sélectionnée pour le streaming qu’après que /v1/receive/{account} a été mis à niveau vers WebSocket, ce qui nécessite MODE=json-rpc.
Le mode conteneur prend en charge les mêmes opérations du canal Signal que le mode natif lorsque le conteneur expose les API correspondantes : envois, réceptions, pièces jointes, indicateurs de saisie, accusés de lecture/visualisation, réactions, groupes et texte stylisé. OpenClaw traduit ses appels RPC Signal natifs en charges utiles REST du conteneur, y compris les ID de groupe group.{base64(internal_id)} et text_mode: "styled" pour le texte mis en forme.
Notes opérationnelles :
- Utilisez
autoStart: falseavec le mode conteneur. OpenClaw ne doit pas lancer de démon natif lorsqueapiMode: "container"est sélectionné. - Utilisez
MODE=json-rpcpour la réception.MODE=normalpeut faire paraître/v1/aboutsain, mais/v1/receive/{account}ne passe pas en WebSocket ; OpenClaw ne sélectionnera donc pas le streaming de réception conteneur en modeauto. - Définissez
apiMode: "container"lorsque vous savez quehttpUrlpointe vers l’API REST de bbernhard. DéfinissezapiMode: "native"lorsque vous savez qu’il pointe vers JSON-RPC/SSE natif designal-cli. Utilisez"auto"lorsque le déploiement peut varier. - Les téléchargements de pièces jointes du conteneur respectent les mêmes limites d’octets de média que le mode natif. Les réponses trop volumineuses sont rejetées avant d’être entièrement mises en mémoire tampon lorsque le serveur envoie
Content-Length, et pendant le streaming dans les autres cas.
Contrôle d’accès (MP + groupes)
MP :
- Par défaut :
channels.signal.dmPolicy = "pairing". - Les expéditeurs inconnus reçoivent un code d’association ; les messages sont ignorés jusqu’à approbation (les codes expirent après 1 heure).
- Approuvez via :
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- L’association est l’échange de jetons par défaut pour les MP Signal. Détails : Association
- Les expéditeurs uniquement UUID (depuis
sourceUuid) sont stockés commeuuid:<id>danschannels.signal.allowFrom.
Groupes :
channels.signal.groupPolicy = open | allowlist | disabled.channels.signal.groupAllowFromcontrôle les groupes ou expéditeurs pouvant déclencher des réponses de groupe lorsqueallowlistest défini ; les entrées peuvent être des ID de groupe Signal (bruts,group:<id>ousignal:group:<id>), des numéros de téléphone d’expéditeur, des valeursuuid:<id>ou*.channels.signal.groups["<group-id>" | "*"]peut remplacer le comportement de groupe avecrequireMention,toolsettoolsBySender.- Utilisez
channels.signal.accounts.<id>.groupspour les remplacements par compte dans les configurations multi-comptes. - L’inscription d’un groupe Signal dans la liste d’autorisation via
groupAllowFromne désactive pas à elle seule le filtrage par mention. Une entréechannels.signal.groups["<group-id>"]configurée spécifiquement traite chaque message de groupe sauf sirequireMention=trueest défini. - Note d’exécution : si
channels.signalest complètement absent, l’exécution revient àgroupPolicy="allowlist"pour les vérifications de groupe (même sichannels.defaults.groupPolicyest défini).
Fonctionnement (comportement)
- Mode natif :
signal-clis’exécute comme démon ; le Gateway lit les événements via SSE. - Mode conteneur : le Gateway envoie via l’API REST et reçoit via WebSocket.
- Les messages entrants sont normalisés dans l’enveloppe de canal partagée.
- Les réponses sont toujours routées vers le même numéro ou groupe.
Médias + limites
- Le texte sortant est découpé selon
channels.signal.textChunkLimit(4000 par défaut). - Découpage facultatif par saut de ligne : définissez
channels.signal.chunkMode="newline"pour diviser sur les lignes vides (limites de paragraphes) avant le découpage par longueur. - Pièces jointes prises en charge (base64 récupéré depuis
signal-cli). - Les pièces jointes de note vocale utilisent le nom de fichier
signal-clicomme solution de repli MIME lorsquecontentTypeest absent, afin que la transcription audio puisse toujours classifier les mémos vocaux AAC. - Plafond média par défaut :
channels.signal.mediaMaxMb(8 par défaut). - Utilisez
channels.signal.ignoreAttachmentspour ignorer le téléchargement des médias. - Le contexte d’historique de groupe utilise
channels.signal.historyLimit(ouchannels.signal.accounts.*.historyLimit), avec repli surmessages.groupChat.historyLimit. Définissez0pour désactiver (50 par défaut).
Saisie + accusés de lecture
- Indicateurs de saisie : OpenClaw envoie des signaux de saisie via
signal-cli sendTypinget les actualise pendant qu’une réponse est en cours. - Accusés de lecture : lorsque
channels.signal.sendReadReceiptsvaut true, OpenClaw transmet les accusés de lecture pour les DMs autorisés. - Signal-cli n’expose pas les accusés de lecture pour les groupes.
Réactions d’état du cycle de vie
Définissez messages.statusReactions.enabled: true pour permettre à Signal d’afficher le cycle de vie partagé des réactions en file d’attente/réflexion/outil/compaction/terminé/erreur sur les tours entrants.
Signal utilise l’horodatage du message entrant comme cible de réaction ; les réactions de groupe sont envoyées avec l’identifiant de groupe Signal plus l’expéditeur d’origine comme auteur cible.
Les réactions d’état nécessitent aussi une réaction d’accusé et un messages.ackReactionScope correspondant (direct, group-all, group-mentions ou all).
Définissez channels.signal.reactionLevel: "off" pour désactiver les réactions d’état Signal.
L’action react de l’outil de message reste plus stricte : elle nécessite reactionLevel: "minimal" ou "extensive".
messages.removeAckAfterReply: true efface la réaction d’état finale après le délai de maintien configuré. Sinon, Signal restaure la réaction d’accusé initiale après l’état final terminé/erreur.
Réactions (outil de message)
- Utilisez
message action=reactavecchannel=signal. - Cibles : E.164 ou UUID de l’expéditeur (utilisez
uuid:<id>depuis la sortie d’appairage ; un UUID nu fonctionne aussi). messageIdest l’horodatage Signal du message auquel vous réagissez.- Les réactions de groupe nécessitent
targetAuthoroutargetAuthorUuid.
Exemples :
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=✅Configuration :
channels.signal.actions.reactions: activer/désactiver les actions de réaction (true par défaut).channels.signal.reactionLevel:off | ack | minimal | extensive.off/ackdésactive les réactions de l’agent (l’outil de messagereactrenverra une erreur).minimal/extensiveactive les réactions de l’agent et définit le niveau de guidage.
- Remplacements par compte :
channels.signal.accounts.<id>.actions.reactions,channels.signal.accounts.<id>.reactionLevel.
Réactions d’approbation
Les invites d’approbation d’exécution Signal et de plugin utilisent les blocs de routage de niveau supérieur approvals.exec et approvals.plugin. Signal n’a pas de bloc channels.signal.execApprovals.
👍approuve une fois.👎refuse.- Utilisez
/approve <id> allow-alwayslorsqu’une demande propose une approbation persistante.
La résolution des réactions d’approbation nécessite des approbateurs Signal explicites provenant de channels.signal.allowFrom, channels.signal.defaultTo ou des champs correspondants au niveau du compte.
Les invites d’approbation d’exécution directes dans la même discussion peuvent toujours supprimer le doublon de repli local /approve sans approbateurs explicites ; les approbations de groupe sans approbateur gardent le repli local visible.
Cibles de livraison (CLI/cron)
- DMs :
signal:+15551234567(ou E.164 simple). - DMs UUID :
uuid:<id>(ou UUID nu). - Groupes :
signal:group:<groupId>. - Noms d’utilisateur :
username:<name>(si pris en charge par votre compte Signal).
Alias
Configurez des alias lorsque vous voulez des noms stables pour les cibles Signal récurrentes. Les alias existent uniquement dans la configuration côté OpenClaw ; ils ne créent ni ne modifient les contacts Signal.
{ channels: { signal: { aliases: { me: "+15557654321", jane: "uuid:123e4567-e89b-12d3-a456-426614174000", ops: "group:<groupId>", }, defaultTo: "signal:me", }, },}Utilisez les alias partout où les cibles de livraison Signal sont acceptées :
openclaw message send --channel signal --target signal:ops --message "Deployment is complete"Les alias par compte héritent des alias de niveau supérieur et peuvent ajouter ou remplacer des noms :
{ channels: { signal: { aliases: { me: "+15557654321", }, accounts: { work: { aliases: { ops: "group:<workGroupId>", }, }, }, }, },}openclaw directory peers list --channel signal et openclaw directory groups list --channel signal listent les alias configurés. L’annuaire Signal est basé sur la configuration ; il n’interroge pas les contacts Signal en direct et ne modifie pas le compte Signal.
Dépannage
Exécutez d’abord cette séquence :
openclaw statusopenclaw gateway statusopenclaw logs --followopenclaw doctoropenclaw channels status --probeConfirmez ensuite l’état d’appairage DM si nécessaire :
openclaw pairing list signalÉchecs courants :
- Démon joignable mais aucune réponse : vérifiez les paramètres de compte/démon (
httpUrl,account) et le mode de réception. - DMs ignorés : l’expéditeur attend l’approbation d’appairage.
- Messages de groupe ignorés : le filtrage par expéditeur/mention du groupe bloque la livraison.
- Erreurs de validation de configuration après modifications : exécutez
openclaw doctor --fix. - Signal absent des diagnostics : confirmez
channels.signal.enabled: true.
Vérifications supplémentaires :
openclaw pairing list signalpgrep -af signal-cligrep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20Pour le flux de triage : /channels/troubleshooting.
Notes de sécurité
signal-clistocke les clés de compte localement (généralement dans~/.local/share/signal-cli/data/).- Sauvegardez l’état du compte Signal avant une migration ou reconstruction de serveur.
- Conservez
channels.signal.dmPolicy: "pairing"sauf si vous voulez explicitement un accès DM plus large. - La vérification par SMS n’est nécessaire que pour les flux d’inscription ou de récupération, mais perdre le contrôle du numéro/compte peut compliquer la réinscription.
Référence de configuration (Signal)
Configuration complète : Configuration
Options du fournisseur :
channels.signal.enabled: activer/désactiver le démarrage du canal.channels.signal.apiMode:auto | native | container(par défaut : auto). Voir Mode conteneur.channels.signal.account: E.164 pour le compte du bot.channels.signal.cliPath: chemin verssignal-cli.channels.signal.configPath: répertoiresignal-cli --configfacultatif.channels.signal.httpUrl: URL complète du démon (remplace l’hôte/le port).channels.signal.httpHost,channels.signal.httpPort: liaison du démon (par défaut 127.0.0.1:8080).channels.signal.autoStart: lancer automatiquement le démon (true par défaut sihttpUrln’est pas défini).channels.signal.startupTimeoutMs: délai d’attente du démarrage en ms (plafond 120000).channels.signal.receiveMode:on-start | manual.channels.signal.ignoreAttachments: ignorer les téléchargements de pièces jointes.channels.signal.ignoreStories: ignorer les stories du démon.channels.signal.sendReadReceipts: transmettre les accusés de lecture.channels.signal.dmPolicy:pairing | allowlist | open | disabled(par défaut : pairing).channels.signal.allowFrom: liste d’autorisation DM (E.164 ouuuid:<id>).opennécessite"*". Signal n’a pas de noms d’utilisateur ; utilisez des identifiants téléphone/UUID.channels.signal.aliases: alias côté OpenClaw pour les cibles de livraison DM ou de groupe.channels.signal.groupPolicy:open | allowlist | disabled(par défaut : allowlist).channels.signal.groupAllowFrom: liste d’autorisation de groupe ; accepte les identifiants de groupe Signal (bruts,group:<id>ousignal:group:<id>), les numéros E.164 des expéditeurs ou les valeursuuid:<id>.channels.signal.groups: remplacements par groupe indexés par identifiant de groupe Signal (ou"*"). Champs pris en charge :requireMention,tools,toolsBySender.channels.signal.accounts.<id>.groups: version par compte dechannels.signal.groupspour les configurations à plusieurs comptes.channels.signal.accounts.<id>.aliases: alias par compte, fusionnés avec les alias de niveau supérieur.channels.signal.historyLimit: nombre maximal de messages de groupe à inclure comme contexte (0 désactive).channels.signal.dmHistoryLimit: limite d’historique DM en tours utilisateur. Remplacements par utilisateur :channels.signal.dms["<phone_or_uuid>"].historyLimit.channels.signal.textChunkLimit: taille des segments sortants (caractères).channels.signal.chunkMode:length(par défaut) ounewlinepour diviser sur les lignes vides (limites de paragraphes) avant le découpage par longueur.channels.signal.mediaMaxMb: plafond des médias entrants/sortants (Mo).
Options globales associées :
agents.list[].groupChat.mentionPatterns(Signal ne prend pas en charge les mentions natives).messages.groupChat.mentionPatterns(repli global).messages.responsePrefix.
Associé
- Vue d’ensemble des canaux — tous les canaux pris en charge
- Appairage — authentification DM et flux d’appairage
- Groupes — comportement des discussions de groupe et filtrage par mention
- Routage des canaux — routage de session pour les messages
- Sécurité — modèle d’accès et renforcement