Status: external CLI integration. Gateway talks to signal-cli over HTTP JSON-RPC + SSE.
signal-cli available on the host where the gateway runs.signalcaptchas.org) during registration.signal-cli (Java required if you use the JVM build).signal-cli link -n "CoderClaw" and scan with Signal.coderclaw pairing approve signal <CODE>).Minimal config:
{
channels: {
signal: {
enabled: true,
account: "+15551234567",
cliPath: "signal-cli",
dmPolicy: "pairing",
allowFrom: ["+15557654321"],
},
},
}
Field reference:
| Field | Description |
|---|---|
account |
Bot phone number in E.164 format (+15551234567) |
cliPath |
Path to signal-cli (signal-cli if on PATH) |
dmPolicy |
DM access policy (pairing recommended) |
allowFrom |
Phone numbers or uuid:<id> values allowed to DM |
signal-cli (not embedded libsignal).agent:<agentId>:signal:group:<groupId>).By default, Signal is allowed to write config updates triggered by /config set|unset (requires commands.config: true).
Disable with:
{
channels: { signal: { configWrites: false } },
}
signal-cli account).signal-cli (JVM or native build).signal-cli link -n "CoderClaw" then scan the QR in Signal.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. See gateway/configuration for the shared pattern.
Use this when you want a dedicated bot number instead of linking an existing Signal app account.
signal-cli on the gateway host: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
If you use the JVM build (signal-cli-${VERSION}.tar.gz), install JRE 25+ first.
Keep signal-cli updated; upstream notes that old releases can break as Signal server APIs change.
signal-cli -a +<BOT_PHONE_NUMBER> register
If captcha is required:
https://signalcaptchas.org/registration/generate.html.signalcaptcha://... link target from “Open Signal”.signal-cli -a +<BOT_PHONE_NUMBER> register --captcha '<SIGNALCAPTCHA_URL>'
signal-cli -a +<BOT_PHONE_NUMBER> verify <VERIFICATION_CODE>
# If you run the gateway as a user systemd service:
systemctl --user restart coderclaw-gateway
# Then verify:
coderclaw doctor
coderclaw channels status --probe
coderclaw pairing approve signal <PAIRING_CODE>.Important: registering a phone number account with signal-cli can de-authenticate the main Signal app session for that number. Prefer a dedicated bot number, or use QR link mode if you need to keep your existing phone app setup.
Upstream references:
signal-cli README: https://github.com/AsamK/signal-clihttps://github.com/AsamK/signal-cli/wiki/Registration-with-captchahttps://github.com/AsamK/signal-cli/wiki/Linking-other-devices-(Provisioning)If you want to manage signal-cli yourself (slow JVM cold starts, container init, or shared CPUs), run the daemon separately and point CoderClaw at it:
{
channels: {
signal: {
httpUrl: "http://127.0.0.1:8080",
autoStart: false,
},
},
}
This skips auto-spawn and the startup wait inside CoderClaw. For slow starts when auto-spawning, set channels.signal.startupTimeoutMs.
DMs:
channels.signal.dmPolicy = "pairing".coderclaw pairing list signalcoderclaw pairing approve signal <CODE>sourceUuid) are stored as uuid:<id> in channels.signal.allowFrom.Groups:
channels.signal.groupPolicy = open | allowlist | disabled.channels.signal.groupAllowFrom controls who can trigger in groups when allowlist is set.signal-cli runs as a daemon; the gateway reads events via SSE.channels.signal.textChunkLimit (default 4000).channels.signal.chunkMode="newline" to split on blank lines (paragraph boundaries) before length chunking.signal-cli).channels.signal.mediaMaxMb (default 8).channels.signal.ignoreAttachments to skip downloading media.channels.signal.historyLimit (or channels.signal.accounts.*.historyLimit), falling back to messages.groupChat.historyLimit. Set 0 to disable (default 50).signal-cli sendTyping and refreshes them while a reply is running.channels.signal.sendReadReceipts is true, CoderClaw forwards read receipts for allowed DMs.message action=react with channel=signal.uuid:<id> from pairing output; bare UUID works too).messageId is the Signal timestamp for the message you’re reacting to.targetAuthor or targetAuthorUuid.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 | extensive.
off/ack disables agent reactions (message tool react will error).minimal/extensive enables agent reactions and sets the guidance level.channels.signal.accounts.<id>.actions.reactions, channels.signal.accounts.<id>.reactionLevel.signal:+15551234567 (or plain E.164).uuid:<id> (or bare UUID).signal:group:<groupId>.username:<name> (if supported by your Signal account).Run this ladder first:
coderclaw status
coderclaw gateway status
coderclaw logs --follow
coderclaw doctor
coderclaw channels status --probe
Then confirm DM pairing state if needed:
coderclaw pairing list signal
Common failures:
httpUrl, account) and receive mode.coderclaw doctor --fix.channels.signal.enabled: true.Extra checks:
coderclaw pairing list signal
pgrep -af signal-cli
grep -i "signal" "/tmp/coderclaw/coderclaw-$(date +%Y-%m-%d).log" | tail -20
For triage flow: /channels/troubleshooting.
signal-cli stores account keys locally (typically ~/.local/share/signal-cli/data/).channels.signal.dmPolicy: "pairing" unless you explicitly want broader DM access.Full configuration: Configuration
Provider options:
channels.signal.enabled: enable/disable channel startup.channels.signal.account: E.164 for the bot account.channels.signal.cliPath: path to signal-cli.channels.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 if httpUrl unset).channels.signal.startupTimeoutMs: startup wait timeout in ms (cap 120000).channels.signal.receiveMode: on-start | manual.channels.signal.ignoreAttachments: skip attachment downloads.channels.signal.ignoreStories: ignore stories from the daemon.channels.signal.sendReadReceipts: forward read receipts.channels.signal.dmPolicy: pairing | allowlist | open | disabled (default: pairing).channels.signal.allowFrom: DM allowlist (E.164 or uuid:<id>). open requires "*". Signal has no usernames; use phone/UUID ids.channels.signal.groupPolicy: open | allowlist | disabled (default: allowlist).channels.signal.groupAllowFrom: group sender allowlist.channels.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>"].historyLimit.channels.signal.textChunkLimit: outbound chunk size (chars).channels.signal.chunkMode: length (default) or newline to split on blank lines (paragraph boundaries) before length chunking.channels.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.