Mainstream messaging
Signal
ステータス: 外部 CLI 統合。Gateway は HTTP 経由で signal-cli と通信します。ネイティブデーモン (JSON-RPC + SSE) または bbernhard/signal-cli-rest-api コンテナ (REST + WebSocket) のいずれかです。
前提条件
- サーバーに OpenClaw がインストール済みであること (以下の Linux フローは Ubuntu 24 でテスト済み)。
- 次のいずれか:
- ホストで
signal-cliが利用可能であること (ネイティブモード)、または bbernhard/signal-cli-rest-apiDocker コンテナ (コンテナモード)。
- ホストで
- 検証 SMS を 1 通受信できる電話番号 (SMS 登録パス用)。
- 登録中に Signal captcha (
signalcaptchas.org) へアクセスできるブラウザ。
クイックセットアップ (初心者向け)
- ボットには 別の Signal 番号 を使用します (推奨)。
- OpenClaw Plugin をインストールします。
openclaw plugins install @openclaw/signalsignal-cliをインストールします (JVM ビルドを使う場合は Java が必要です)。- セットアップパスを 1 つ選びます。
- パス A (QR リンク):
signal-cli link -n "OpenClaw"を実行し、Signal でスキャンします。 - パス B (SMS 登録): captcha + SMS 検証で専用番号を登録します。
- パス A (QR リンク):
- OpenClaw を設定し、gateway を再起動します。
- 最初の DM を送信し、ペアリングを承認します (
openclaw pairing approve signal <CODE>)。
最小構成:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}フィールドリファレンス:
| フィールド | 説明 |
|---|---|
account |
E.164 形式のボット電話番号 (+15551234567) |
cliPath |
signal-cli へのパス (PATH 上にある場合は signal-cli) |
configPath |
--config として渡される signal-cli 設定ディレクトリ |
dmPolicy |
DM アクセスポリシー (pairing 推奨) |
allowFrom |
DM を許可する電話番号または uuid:<id> 値 |
概要
signal-cli経由の Signal チャネル (組み込み libsignal ではありません)。- 決定的ルーティング: 返信は常に Signal に戻ります。
- DM はエージェントのメインセッションを共有します。グループは分離されます (
agent:<agentId>:signal:group:<groupId>)。
設定の書き込み
デフォルトでは、Signal は /config set|unset によってトリガーされる設定更新の書き込みを許可されます (commands.config: true が必要)。
無効化するには:
{ channels: { signal: { configWrites: false } },}番号モデル (重要)
- gateway は Signal デバイス (
signal-cliアカウント) に接続します。 - ボットを 自分の個人 Signal アカウント で実行すると、自分自身のメッセージは無視されます (ループ保護)。
- 「自分がボットにテキストを送ると返信される」動作には、別のボット番号 を使用します。
セットアップパス A: 既存の Signal アカウントをリンクする (QR)
signal-cliをインストールします (JVM またはネイティブビルド)。- ボットアカウントをリンクします:
signal-cli link -n "OpenClaw"を実行し、Signal で QR をスキャンします。
- Signal を設定し、gateway を起動します。
例:
{ channels: { signal: { enabled: true, account: "+15551234567", cliPath: "signal-cli", dmPolicy: "pairing", allowFrom: ["+15557654321"], }, },}マルチアカウント対応: アカウントごとの設定と任意の name を指定して channels.signal.accounts を使用します。共有パターンについては gateway/configuration を参照してください。
セットアップパス B: 専用ボット番号を登録する (SMS、Linux)
既存の Signal アプリアカウントをリンクする代わりに、専用ボット番号を使いたい場合に使用します。
- SMS を受信できる番号を用意します (固定電話の場合は音声検証)。
- アカウント/セッションの競合を避けるため、専用ボット番号を使用します。
- gateway ホストに
signal-cliをインストールします。
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 --versionJVM ビルド (signal-cli-${VERSION}.tar.gz) を使う場合は、先に JRE 25+ をインストールしてください。
signal-cli は最新に保ってください。上流では、Signal サーバー API の変更により古いリリースが壊れる可能性があるとされています。
- 番号を登録して検証します。
signal-cli -a +<BOT_PHONE_NUMBER> registercaptcha が必要な場合:
https://signalcaptchas.org/registration/generate.htmlを開きます。- captcha を完了し、「Open Signal」から
signalcaptcha://...リンクターゲットをコピーします。 - 可能な場合は、ブラウザセッションと同じ外部 IP から実行します。
- すぐに登録を再実行します (captcha トークンはすぐに期限切れになります)。
signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>- OpenClaw を設定し、gateway を再起動して、チャネルを検証します。
# If you run the gateway as a user systemd service:systemctl --user restart openclaw-gateway.service # Then verify:openclaw doctoropenclaw channels status --probe- DM 送信者をペアリングします:
- ボット番号に任意のメッセージを送信します。
- サーバー上でコードを承認します:
openclaw pairing approve signal <PAIRING_CODE>。 - 「Unknown contact」を避けるため、ボット番号を電話の連絡先として保存します。
上流リファレンス:
signal-cliREADME:https://github.com/AsamK/signal-cli- Captcha フロー:
https://github.com/AsamK/signal-cli/wiki/Registration-with-captcha - リンクフロー:
https://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)
外部デーモンモード (httpUrl)
signal-cli を自分で管理したい場合 (遅い JVM コールドスタート、コンテナ初期化、または共有 CPU)、デーモンを別途実行し、OpenClaw からそこを指すようにします。
{ channels: { signal: { httpUrl: "http://127.0.0.1:8080", autoStart: false, }, },}これにより、OpenClaw 内の自動スポーンと起動待機をスキップします。自動スポーン時の起動が遅い場合は、channels.signal.startupTimeoutMs を設定します。
コンテナモード (bbernhard/signal-cli-rest-api)
signal-cli をネイティブに実行する代わりに、bbernhard/signal-cli-rest-api Docker コンテナを使用できます。これは signal-cli を REST API と WebSocket インターフェイスの背後にラップします。
要件:
- リアルタイムメッセージ受信のため、コンテナは 必ず
MODE=json-rpcで実行する必要があります。 - OpenClaw を接続する前に、コンテナ内で Signal アカウントを登録またはリンクしてください。
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-cliOpenClaw 設定:
{ channels: { signal: { enabled: true, account: "+15551234567", httpUrl: "http://signal-cli:8080", autoStart: false, apiMode: "container", // or "auto" to detect automatically }, },}apiMode フィールドは、OpenClaw が使用するプロトコルを制御します。
| 値 | 動作 |
|---|---|
"auto" |
(デフォルト) 両方のトランスポートをプローブします。ストリーミングではコンテナ WebSocket 受信を検証します |
"native" |
ネイティブ signal-cli を強制します (/api/v1/rpc の JSON-RPC、/api/v1/events の SSE) |
"container" |
bbernhard コンテナを強制します (/v2/send の REST、/v1/receive/{account} の WebSocket) |
apiMode が "auto" の場合、OpenClaw は検出されたモードを 30 秒間キャッシュし、プローブの繰り返しを避けます。コンテナ受信は、/v1/receive/{account} が WebSocket にアップグレードされた後にのみストリーミング用に選択されます。これには MODE=json-rpc が必要です。
コンテナモードは、コンテナが対応する API を公開している場合、ネイティブモードと同じ Signal チャネル操作をサポートします: 送信、受信、添付ファイル、入力インジケーター、既読/閲覧済みレシート、リアクション、グループ、スタイル付きテキスト。OpenClaw はネイティブ Signal RPC 呼び出しをコンテナの REST ペイロードへ変換します。これには group.{base64(internal_id)} グループ ID と、書式付きテキスト用の text_mode: "styled" が含まれます。
運用上の注意:
- コンテナモードでは
autoStart: falseを使用してください。apiMode: "container"が選択されている場合、OpenClaw はネイティブデーモンをスポーンすべきではありません。 - 受信には
MODE=json-rpcを使用してください。MODE=normalでは/v1/aboutが正常に見えることがありますが、/v1/receive/{account}は WebSocket にアップグレードされないため、OpenClaw はautoモードでコンテナ受信ストリーミングを選択しません。 httpUrlが bbernhard の REST API を指していると分かっている場合は、apiMode: "container"を設定します。ネイティブsignal-cliJSON-RPC/SSE を指していると分かっている場合は、apiMode: "native"を設定します。デプロイが変わる可能性がある場合は"auto"を使用します。- コンテナの添付ファイルダウンロードは、ネイティブモードと同じメディアバイト制限に従います。サーバーが
Content-Lengthを送信する場合、サイズ超過のレスポンスは完全にバッファリングされる前に拒否されます。それ以外の場合はストリーミング中に拒否されます。
アクセス制御 (DM + グループ)
DM:
- デフォルト:
channels.signal.dmPolicy = "pairing"。 - 不明な送信者はペアリングコードを受け取ります。承認されるまでメッセージは無視されます (コードは 1 時間後に期限切れ)。
- 承認方法:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- ペアリングは Signal DM のデフォルトのトークン交換です。詳細: ペアリング
- UUID のみの送信者 (
sourceUuid由来) は、channels.signal.allowFromにuuid:<id>として保存されます。
グループ:
channels.signal.groupPolicy = open | allowlist | disabled。channels.signal.groupAllowFromは、allowlistが設定されている場合にどのグループまたは送信者がグループ返信をトリガーできるかを制御します。エントリには Signal グループ ID (raw、group:<id>、またはsignal:group:<id>)、送信者の電話番号、uuid:<id>値、または*を指定できます。channels.signal.groups["<group-id>" | "*"]は、requireMention、tools、toolsBySenderでグループ動作を上書きできます。- マルチアカウント設定でアカウントごとの上書きを行うには、
channels.signal.accounts.<id>.groupsを使用します。 groupAllowFromを通じて Signal グループを allowlist に追加しても、それだけでメンションゲートは無効になりません。具体的に設定されたchannels.signal.groups["<group-id>"]エントリは、requireMention=trueが設定されていない限り、すべてのグループメッセージを処理します。- ランタイムメモ:
channels.signalが完全に欠落している場合、ランタイムはグループチェックでgroupPolicy="allowlist"にフォールバックします (channels.defaults.groupPolicyが設定されている場合でも)。
仕組み (動作)
- ネイティブモード:
signal-cliはデーモンとして実行され、gateway は SSE 経由でイベントを読み取ります。 - コンテナモード: gateway は REST API 経由で送信し、WebSocket 経由で受信します。
- 受信メッセージは共有チャネルエンベロープに正規化されます。
- 返信は常に同じ番号またはグループへルーティングされます。
メディア + 制限
- 送信テキストは
channels.signal.textChunkLimit(デフォルト 4000) に分割されます。 - 任意の改行分割: 長さによる分割の前に空行 (段落境界) で分割するには、
channels.signal.chunkMode="newline"を設定します。 - 添付ファイルをサポートします (
signal-cliから base64 を取得)。 - ボイスメモ添付では、
contentTypeが欠落している場合に MIME フォールバックとしてsignal-cliのファイル名を使用するため、音声文字起こしで AAC ボイスメモを分類できます。 - デフォルトのメディア上限:
channels.signal.mediaMaxMb(デフォルト 8)。 - メディアのダウンロードをスキップするには
channels.signal.ignoreAttachmentsを使用します。 - グループ履歴コンテキストは
channels.signal.historyLimit(またはchannels.signal.accounts.*.historyLimit) を使用し、messages.groupChat.historyLimitにフォールバックします。無効化するには0を設定します (デフォルト 50)。
入力中 + 既読レシート
- 入力中インジケーター: OpenClaw は
signal-cli sendTyping経由で入力中シグナルを送信し、返信の実行中はそれを更新します。 - 既読通知:
channels.signal.sendReadReceiptsが true の場合、OpenClaw は許可された DM の既読通知を転送します。 - signal-cli はグループの既読通知を公開しません。
ライフサイクルステータスリアクション
Signal で受信ターンに対して共有の queued/thinking/tool/compaction/done/error リアクションライフサイクルを表示するには、messages.statusReactions.enabled: true を設定します。
Signal は受信メッセージのタイムスタンプをリアクション対象として使用します。グループリアクションは、Signal グループ ID と元の送信者を対象の作成者として送信されます。
ステータスリアクションには、ack リアクションと一致する messages.ackReactionScope(direct、group-all、group-mentions、または all)も必要です。
Signal のステータスリアクションを無効にするには、channels.signal.reactionLevel: "off" を設定します。
メッセージツールの react アクションはより厳格で、reactionLevel: "minimal" または "extensive" が必要です。
messages.removeAckAfterReply: true は、設定された保持時間の後に最終ステータスリアクションをクリアします。それ以外の場合、Signal は最終的な done/error 状態の後に初期 ack リアクションを復元します。
リアクション(メッセージツール)
channel=signalでmessage action=reactを使用します。- 対象: 送信者の E.164 または UUID(ペアリング出力の
uuid:<id>を使用します。裸の UUID も動作します)。 messageIdは、リアクションするメッセージの Signal タイムスタンプです。- グループリアクションには
targetAuthorまたはtargetAuthorUuidが必要です。
例:
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=✅設定:
channels.signal.actions.reactions: リアクションアクションを有効化/無効化します(デフォルトは true)。channels.signal.reactionLevel:off | ack | minimal | extensive。off/ackはエージェントのリアクションを無効にします(メッセージツールのreactはエラーになります)。minimal/extensiveはエージェントのリアクションを有効にし、ガイダンスレベルを設定します。
- アカウントごとの上書き:
channels.signal.accounts.<id>.actions.reactions、channels.signal.accounts.<id>.reactionLevel。
承認リアクション
Signal の exec と Plugin 承認プロンプトは、トップレベルの approvals.exec と approvals.plugin ルーティングブロックを使用します。
Signal には channels.signal.execApprovals ブロックはありません。
👍は一度だけ承認します。👎は拒否します。- リクエストが永続的な承認を提示する場合は、
/approve <id> allow-alwaysを使用します。
承認リアクションの解決には、channels.signal.allowFrom、channels.signal.defaultTo、または一致するアカウントレベルのフィールドから明示的な Signal 承認者が必要です。
同じチャット内の直接 exec 承認プロンプトでは、明示的な承認者がなくても重複するローカルの /approve フォールバックを抑制できます。承認者のないグループ承認では、ローカルフォールバックが表示されたままになります。
配信対象(CLI/cron)
- DM:
signal:+15551234567(または通常の E.164)。 - UUID DM:
uuid:<id>(または裸の UUID)。 - グループ:
signal:group:<groupId>。 - ユーザー名:
username:<name>(Signal アカウントでサポートされている場合)。
エイリアス
繰り返し使う Signal 対象に安定した名前が必要な場合は、エイリアスを設定します。 エイリアスは OpenClaw 側の設定のみです。Signal の連絡先を作成または編集しません。
{ channels: { signal: { aliases: { me: "+15557654321", jane: "uuid:123e4567-e89b-12d3-a456-426614174000", ops: "group:<groupId>", }, defaultTo: "signal:me", }, },}Signal 配信対象を受け付ける場所ならどこでもエイリアスを使用できます。
openclaw message send --channel signal --target signal:ops --message "Deployment is complete"アカウントごとのエイリアスはトップレベルのエイリアスを継承し、名前を追加または上書きできます。
{ channels: { signal: { aliases: { me: "+15557654321", }, accounts: { work: { aliases: { ops: "group:<workGroupId>", }, }, }, }, },}openclaw directory peers list --channel signal と openclaw directory groups list --channel signal は、設定されたエイリアスを一覧表示します。
Signal ディレクトリは設定に基づきます。Signal の連絡先をライブクエリしたり、Signal アカウントを変更したりしません。
トラブルシューティング
まずこの手順を実行します。
openclaw statusopenclaw gateway statusopenclaw logs --followopenclaw doctoropenclaw channels status --probe必要に応じて、次に DM ペアリング状態を確認します。
openclaw pairing list signalよくある失敗:
- デーモンには到達できるが返信がない: アカウント/デーモン設定(
httpUrl、account)と受信モードを確認します。 - DM が無視される: 送信者がペアリング承認待ちです。
- グループメッセージが無視される: グループ送信者/メンションのゲートが配信をブロックしています。
- 編集後に設定検証エラーが出る:
openclaw doctor --fixを実行します。 - 診断に Signal が表示されない:
channels.signal.enabled: trueを確認します。
追加チェック:
openclaw pairing list signalpgrep -af signal-cligrep -i "signal" "/tmp/openclaw/openclaw-$(date +%Y-%m-%d).log" | tail -20トリアージフロー: /channels/troubleshooting。
セキュリティメモ
signal-cliはアカウントキーをローカルに保存します(通常は~/.local/share/signal-cli/data/)。- サーバー移行または再構築の前に、Signal アカウント状態をバックアップしてください。
- より広範な DM アクセスを明示的に必要としない限り、
channels.signal.dmPolicy: "pairing"のままにしてください。 - SMS 検証は登録または復旧フローでのみ必要ですが、番号/アカウントの制御を失うと再登録が複雑になる可能性があります。
設定リファレンス(Signal)
完全な設定: 設定
プロバイダーオプション:
channels.signal.enabled: チャンネル起動を有効化/無効化します。channels.signal.apiMode:auto | native | container(デフォルト: auto)。コンテナモード を参照してください。channels.signal.account: bot アカウントの E.164。channels.signal.cliPath:signal-cliへのパス。channels.signal.configPath: 任意のsignal-cli --configディレクトリ。channels.signal.httpUrl: 完全なデーモン URL(host/port を上書きします)。channels.signal.httpHost、channels.signal.httpPort: デーモンのバインド(デフォルト 127.0.0.1:8080)。channels.signal.autoStart: デーモンを自動起動します(httpUrlが未設定の場合のデフォルトは true)。channels.signal.startupTimeoutMs: 起動待機タイムアウト(ms、上限 120000)。channels.signal.receiveMode:on-start | manual。channels.signal.ignoreAttachments: 添付ファイルのダウンロードをスキップします。channels.signal.ignoreStories: デーモンからのストーリーを無視します。channels.signal.sendReadReceipts: 既読通知を転送します。channels.signal.dmPolicy:pairing | allowlist | open | disabled(デフォルト: pairing)。channels.signal.allowFrom: DM 許可リスト(E.164 またはuuid:<id>)。openには"*"が必要です。Signal にはユーザー名がないため、電話番号/UUID ID を使用します。channels.signal.aliases: DM またはグループ配信対象向けの OpenClaw 側エイリアス。channels.signal.groupPolicy:open | allowlist | disabled(デフォルト: allowlist)。channels.signal.groupAllowFrom: グループ許可リスト。Signal グループ ID(raw、group:<id>、またはsignal:group:<id>)、送信者の E.164 番号、またはuuid:<id>値を受け付けます。channels.signal.groups: Signal グループ ID(または"*")をキーにしたグループごとの上書き。対応フィールド:requireMention、tools、toolsBySender。channels.signal.accounts.<id>.groups: 複数アカウント設定向けのchannels.signal.groupsのアカウントごとの版。channels.signal.accounts.<id>.aliases: アカウントごとのエイリアス。トップレベルのエイリアスとマージされます。channels.signal.historyLimit: コンテキストとして含めるグループメッセージの最大数(0 で無効)。channels.signal.dmHistoryLimit: ユーザーターン単位の DM 履歴制限。ユーザーごとの上書き:channels.signal.dms["<phone_or_uuid>"].historyLimit。channels.signal.textChunkLimit: 送信チャンクサイズ(文字数)。channels.signal.chunkMode: 長さによるチャンク化の前に空行(段落境界)で分割するには、length(デフォルト)またはnewline。channels.signal.mediaMaxMb: 受信/送信メディアの上限(MB)。
関連するグローバルオプション:
agents.list[].groupChat.mentionPatterns(Signal はネイティブメンションをサポートしません)。messages.groupChat.mentionPatterns(グローバルフォールバック)。messages.responsePrefix。
関連
- チャンネル概要 — サポートされているすべてのチャンネル
- ペアリング — DM 認証とペアリングフロー
- グループ — グループチャットの動作とメンションゲート
- チャンネルルーティング — メッセージのセッションルーティング
- セキュリティ — アクセスモデルと強化