> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wednesdayai.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Signal

> Connect Signal to WednesdayAI via signal-cli: registration, QR linking, and access control.

# Signal

WednesdayAI connects to Signal via [signal-cli](https://github.com/AsamK/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

```bash theme={"dark"}
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
```

## Setup path A: Link existing Signal account (QR)

Use this if you want to connect your existing Signal account to the bot without registering a new number.

```bash theme={"dark"}
signal-cli link -n "WednesdayAI"
# Scan the displayed QR code with your Signal app
```

Then configure OpenClaw with your Signal number:

```json5 theme={"dark"}
{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",    // E.164 phone number
      cliPath: "signal-cli",
      dmPolicy: "pairing",
    },
  },
}
```

## Setup path B: Register a dedicated bot number (recommended)

Use a separate phone number for the bot — this avoids de-authenticating your personal Signal account.

```bash theme={"dark"}
# 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:

```json5 theme={"dark"}
{
  channels: {
    signal: {
      enabled: true,
      account: "+15551234567",
      cliPath: "signal-cli",
      dmPolicy: "pairing",
      allowFrom: ["+15557654321"],
    },
  },
}
```

```bash theme={"dark"}
systemctl --user restart openclaw-gateway
openclaw doctor
openclaw channels status --probe
```

## Access control

```json5 theme={"dark"}
{
  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:

```bash theme={"dark"}
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):

```json5 theme={"dark"}
{
  channels: {
    signal: {
      httpUrl: "http://127.0.0.1:8080",
      autoStart: false,
    },
  },
}
```

### Receive mode

```json5 theme={"dark"}
{ 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

```yaml theme={"dark"}
channels:
  signal:
    actions:
      reactions: true
```

### Group message handling

```yaml theme={"dark"}
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

```yaml theme={"dark"}
channels:
  signal:
    sendReadReceipts: true
```

### Safety number changes

<Warning>
  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.
</Warning>

## Delivery settings

```json5 theme={"dark"}
{
  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)
    },
  },
}
```

| Key                   | Type    | Default     | Description                                                                                |
| --------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------ |
| `textChunkLimit`      | integer | `4000`      | Maximum characters per outbound message chunk                                              |
| `chunkMode`           | string  | `"length"`  | `length` splits at character count; `newline` splits at paragraph boundaries               |
| `chunkNewlinePacking` | boolean | `true`      | When `chunkMode: "newline"`, packs multiple paragraphs into a single chunk up to the limit |
| `historyLimit`        | integer | `50`        | Number of prior messages injected as group context (0 = disabled)                          |
| `dmHistoryLimit`      | integer | `0`         | Number of prior messages injected as DM context (0 = disabled)                             |
| `reactionLevel`       | string  | `"minimal"` | `off` \| `ack` \| `minimal` \| `extensive` — controls how much the bot reacts to messages  |
| `ignoreAttachments`   | boolean | `false`     | When `true`, inbound attachments are ignored and not passed to the agent                   |
| `ignoreStories`       | boolean | `false`     | When `true`, ignores inbound Signal story notifications                                    |
| `startupTimeoutMs`    | integer | `30000`     | Milliseconds to wait for signal-cli to start before treating it as a failure               |
| `sendReadReceipts`    | boolean | `true`      | Send Signal read receipts to message senders                                               |

<Note>
  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.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="signal-cli not found">
    Check that `signal-cli` is in PATH: `which signal-cli`

    Update `cliPath` in config if installed to a non-standard location:

    ```json5 theme={"dark"}
    { channels: { signal: { cliPath: "/opt/signal-cli/bin/signal-cli" } } }
    ```
  </Accordion>

  <Accordion title="DMs ignored / no reply">
    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`
  </Accordion>

  <Accordion title="Registration fails with captcha error">
    Complete the captcha at [https://signalcaptchas.org/registration/generate.html](https://signalcaptchas.org/registration/generate.html) and pass the `signalcaptcha://` URL to the register command.
  </Accordion>

  <Accordion title="Channel fails to start / timeout error in logs">
    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:

    ```json5 theme={"dark"}
    { channels: { signal: { startupTimeoutMs: 60000 } } }
    ```
  </Accordion>
</AccordionGroup>

## Related

* [Gateway configuration — Signal](/reference/config#signal)
* [signal-cli documentation](https://github.com/AsamK/signal-cli)
* [Channel troubleshooting](/admin/troubleshooting)
