Skip to main content

Signal

WednesdayAI connects to Signal via signal-cli, an external CLI tool that the gateway manages as a child process. You need a Signal-capable phone number (or a linked Signal account) to use this channel.

Prerequisites

  • signal-cli installed on the gateway host
  • A phone number that can receive SMS (or Signal QR linking to an existing account)
  • Java Runtime Environment (JRE 25+) if using the JVM build of signal-cli, or the native binary

Install 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 /opt
sudo ln -sf /opt/signal-cli /usr/local/bin/
signal-cli --version
Use this if you want to connect your existing Signal account to the bot without registering a new number.
signal-cli link -n "WednesdayAI"
# Scan the displayed QR code with your Signal app
Then configure OpenClaw with your Signal number:
{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",    // E.164 phone number
      cliPath: "signal-cli",
      dmPolicy: "pairing",
    },
  },
}
Use a separate phone number for the bot — this avoids de-authenticating your personal Signal account.
# Register the number
signal-cli -a +15551234567 register

# If captcha required:
# Open https://signalcaptchas.org/registration/generate.html
# Complete the captcha and copy the signalcaptcha:// URL
signal-cli -a +15551234567 register --captcha 'signalcaptcha://...'

# Verify with the SMS code
signal-cli -a +15551234567 verify 123456
Then configure and restart:
{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",
      cliPath: "signal-cli",
      dmPolicy: "pairing",
      allowFrom: ["+15557654321"],
    },
  },
}
systemctl --user restart openclaw-gateway
openclaw doctor
openclaw channels status --probe

Access control

{
  channels: {
    signal: {
      dmPolicy: "pairing",             // pairing | allowlist | open | disabled
      allowFrom: ["+15557654321"],     // E.164 or uuid:<signal-uuid>
      groupPolicy: "allowlist",        // open | allowlist | disabled
      groupAllowFrom: ["+15557654321"],
    },
  },
}
Approve DM pairing requests:
openclaw pairing list signal
openclaw pairing approve signal <CODE>

Using an external signal-cli daemon

If you prefer to manage signal-cli separately (not auto-spawned by the gateway):
{
  channels: {
    signal: {
      httpUrl: "http://127.0.0.1:8080",
      autoStart: false,
    },
  },
}

Receive mode

{ channels: { signal: { receiveMode: "on-start" } } }  // "on-start" | "manual"
on-start (default) begins consuming the signal-cli event stream at gateway startup. manual defers stream consumption — useful when running signal-cli as a separate long-lived daemon and managing start/stop externally.

Message behavior

Reaction handling

channels:
  signal:
    actions:
      reactions: true

Group message handling

channels:
  signal:
    groupPolicy: "allowlist"    # "open" | "allowlist" | "disabled"
    groupAllowFrom: []          # sender allowlist — E.164 phone numbers or Signal UUIDs of users permitted to trigger the bot inside allowed groups

Delivery receipts

channels:
  signal:
    sendReadReceipts: true

Safety number changes

Safety number changes (when a contact reinstalls Signal) cause message delivery failures. These are logged as signal.safety_number_changed events. Manual trust confirmation is required before messages resume.

Delivery settings

{
  channels: {
    signal: {
      textChunkLimit: 4000,           // chars per outbound chunk
      chunkMode: "length",            // length | newline (paragraph-aware)
      chunkNewlinePacking: true,      // pack multiple paragraphs up to limit (when chunkMode: "newline")
      historyLimit: 50,               // group context history injection (0 = disabled)
      dmHistoryLimit: 0,              // DM history injection
      reactionLevel: "minimal",       // off | ack | minimal | extensive
      ignoreAttachments: false,       // ignore inbound attachments
      ignoreStories: true,            // ignore inbound Signal story notifications (default: false)
      startupTimeoutMs: 30000,        // time to wait for signal-cli to start (ms)
      sendReadReceipts: true,         // send read receipts to senders (default: true)
    },
  },
}
KeyTypeDefaultDescription
textChunkLimitinteger4000Maximum characters per outbound message chunk
chunkModestring"length"length splits at character count; newline splits at paragraph boundaries
chunkNewlinePackingbooleantrueWhen chunkMode: "newline", packs multiple paragraphs into a single chunk up to the limit
historyLimitinteger50Number of prior messages injected as group context (0 = disabled)
dmHistoryLimitinteger0Number of prior messages injected as DM context (0 = disabled)
reactionLevelstring"minimal"off | ack | minimal | extensive — controls how much the bot reacts to messages
ignoreAttachmentsbooleanfalseWhen true, inbound attachments are ignored and not passed to the agent
ignoreStoriesbooleanfalseWhen true, ignores inbound Signal story notifications
startupTimeoutMsinteger30000Milliseconds to wait for signal-cli to start before treating it as a failure
sendReadReceiptsbooleantrueSend Signal read receipts to message senders
If startupTimeoutMs is exceeded, the channel will fail to start and log a timeout error. Increase this value on slow systems or when using the JVM build of signal-cli.

Troubleshooting

Check that signal-cli is in PATH: which signal-cliUpdate cliPath in config if installed to a non-standard location:
{ channels: { signal: { cliPath: "/opt/signal-cli/bin/signal-cli" } } }
  1. Check pairing: openclaw pairing list signal
  2. Verify the account is registered: signal-cli -a +15551234567 listIdentities
  3. Check logs: openclaw logs --follow | grep signal
Complete the captcha at https://signalcaptchas.org/registration/generate.html and pass the signalcaptcha:// URL to the register command.
signal-cli is taking longer than startupTimeoutMs (default 30 000 ms) to become ready. This is common on slow systems or when using the JVM build. Increase the timeout:
{ channels: { signal: { startupTimeoutMs: 60000 } } }