6 custom skills (assign-task, dispatch-webhook, daily-briefing, task-capture, qmd-brain, tts-voice) with technical documentation. Compatible with Claude Code, OpenClaw, Codex CLI, and OpenCode.
7.1 KiB
7.1 KiB
Signal
Signal (signal-cli)
Status: External CLI integration. Gateway talks to signal-cli over HTTP JSON-RPC + SSE.
Quick Setup (Beginner)
- Use a separate Signal number for the bot (recommended)
- Install
signal-cli(Java required) - Link the bot device and start the daemon:
signal-cli link -n "OpenClaw"
- Configure OpenClaw and start the gateway
Minimal config:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
cliPath: "signal-cli",
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
What It Is
- Signal channel via
signal-cli(not embedded libsignal) - Deterministic routing: replies always go back to Signal
- DMs share the agent's main session; groups are isolated (
agent:<agentId>:signal:group:<groupId>)
Config Writes
By default, Signal is allowed to write config updates triggered by /config set|unset (requires commands.config: true).
Disable with:
{
channels: { signal: { configWrites: false } },
}
The Number Model (Important)
- The gateway connects to a Signal device (the
signal-cliaccount) - If you run the bot on your personal Signal account, it will ignore your own messages (loop protection)
- For "I text the bot and it replies," use a separate bot number
Setup (Fast Path)
- Install
signal-cli(Java required) - Link a bot account:
signal-cli link -n "OpenClaw"then scan the QR in Signal
- Configure Signal and start the gateway
Example:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
cliPath: "signal-cli",
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
Multi-account support: use channels.signal.accounts with per-account config and optional name.
External Daemon Mode (httpUrl)
If you want to manage signal-cli yourself (slow JVM cold starts, container init, or shared CPUs), run the daemon separately and point OpenClaw at it:
{
channels: {
signal: {
httpUrl: "http://127.0.0.1:8080",
autoStart: false,
},
},
}
This skips auto-spawn and the startup wait inside OpenClaw. For slow starts when auto-spawning, set channels.signal.startupTimeoutMs.
Access Control (DMs + Groups)
DMs
- Default:
channels.signal.dmPolicy = "pairing" - Unknown senders receive a pairing code; messages are ignored until approved (codes expire after 1 hour)
- Approve via:
openclaw pairing list signalopenclaw pairing approve signal <CODE>
- UUID-only senders (from
sourceUuid) are stored asuuid:<id>inchannels.signal.allowFrom
Groups
channels.signal.groupPolicy = open | allowlist | disabledchannels.signal.groupAllowFromcontrols who can trigger in groups whenallowlistis set
How It Works (Behavior)
signal-cliruns as a daemon; the gateway reads events via SSE- Inbound messages are normalized into the shared channel envelope
- Replies always route back to the same number or group
Media + Limits
- Outbound text is chunked to
channels.signal.textChunkLimit(default 4000) - Optional newline chunking: set
channels.signal.chunkMode="newline"to split on blank lines (paragraph boundaries) before length chunking - Attachments supported (base64 fetched from
signal-cli) - Default media cap:
channels.signal.mediaMaxMb(default 8) - Use
channels.signal.ignoreAttachmentsto skip downloading media - Group history context uses
channels.signal.historyLimit(orchannels.signal.accounts.*.historyLimit), falling back tomessages.groupChat.historyLimit. Set0to disable (default 50)
Typing + Read Receipts
- Typing indicators: OpenClaw sends typing signals via
signal-cli sendTypingand refreshes them while a reply is running - Read receipts: when
channels.signal.sendReadReceiptsis true, OpenClaw forwards read receipts for allowed DMs - Signal-cli does not expose read receipts for groups
Reactions (Message Tool)
Use message action=react with channel=signal.
- Targets: sender E.164 or UUID (use
uuid:<id>from pairing output; bare UUID works too) messageIdis the Signal timestamp for the message you're reacting to- Group reactions require
targetAuthorortargetAuthorUuid
Examples:
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=✅
Config:
channels.signal.actions.reactions: enable/disable reaction actions (default true)channels.signal.reactionLevel:off | ack | minimal | extensiveoff/ackdisables agent reactions (message toolreactwill error)minimal/extensiveenables agent reactions and sets the guidance level
- Per-account overrides:
channels.signal.accounts.<id>.actions.reactions,channels.signal.accounts.<id>.reactionLevel
Delivery Targets (CLI/cron)
- DMs:
signal:+15551234567(or plain E.164) - UUID DMs:
uuid:<id>(or bare UUID) - Groups:
signal:group:<groupId> - Usernames:
username:<name>(if supported by your Signal account)
Configuration Reference (Signal)
Provider Options
channels.signal.enabled: enable/disable channel startupchannels.signal.account: E.164 for the bot accountchannels.signal.cliPath: path tosignal-clichannels.signal.httpUrl: full daemon URL (overrides host/port)channels.signal.httpHost,channels.signal.httpPort: daemon bind (default 127.0.0.1:8080)channels.signal.autoStart: auto-spawn daemon (default true ifhttpUrlunset)channels.signal.startupTimeoutMs: startup wait timeout in ms (cap 120000)channels.signal.receiveMode:on-start | manualchannels.signal.ignoreAttachments: skip attachment downloadschannels.signal.ignoreStories: ignore stories from the daemonchannels.signal.sendReadReceipts: forward read receiptschannels.signal.dmPolicy:pairing | allowlist | open | disabled(default: pairing)channels.signal.allowFrom: DM allowlist (E.164 oruuid:<id>).openrequires"*". Signal has no usernames; use phone/UUID idschannels.signal.groupPolicy:open | allowlist | disabled(default: allowlist)channels.signal.groupAllowFrom: group sender allowlistchannels.signal.historyLimit: max group messages to include as context (0 disables)channels.signal.dmHistoryLimit: DM history limit in user turns. Per-user overrides:channels.signal.dms["<phone_or_uuid>"].historyLimitchannels.signal.textChunkLimit: outbound chunk size (chars)channels.signal.chunkMode:length(default) ornewlineto split on blank lines (paragraph boundaries) before length chunkingchannels.signal.mediaMaxMb: inbound/outbound media cap (MB)
Related Global Options
agents.list[].groupChat.mentionPatterns(Signal does not support native mentions)messages.groupChat.mentionPatterns(global fallback)messages.responsePrefix