signal-channel
Claude Code channel plugin that talks to Signal via signal-cli.
What it is
Inbound Signal messages arrive in your Claude Code session as channel events; outbound goes through the reply tool. DMs, groups, attachments, edits, and reactions all flow through the same bridge. Read receipts, reaction events, group metadata changes, and linked-device contact-sync updates also surface as structured channel events, so Claude can reason about thread state ("read 3 minutes ago, still no reply") and not just message content. One Signal account, one bridge process.
Prereqs
-
signal-cli. Latest stable or later, on PATH.
Install
-
macOS: brew install signal-cli
-
Arch: pacman -S signal-cli
-
Debian/Ubuntu, RedHat/Fedora: no official package. Install the GraalVM native build system-wide from the upstream tarball (self-contained binary, skip the Java prereq):
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/
-
bun. Latest stable or later. Runs the MCP server.
Install
- Debian/Ubuntu, RedHat/Fedora, macOS:
curl -fsSL https://bun.sh/install | bash
- macOS (Homebrew):
brew install bun
- Arch:
pacman -S bun
-
Java 21+ JRE. Required by signal-cli (skip if you installed the GraalVM native build above).
Install
- Debian/Ubuntu:
apt install openjdk-21-jre
- RedHat/Fedora:
dnf install java-21-openjdk
- Arch:
pacman -S jre-openjdk
- macOS:
brew install openjdk@21 or adoptium.net
Account setup
The bridge does not register or link Signal accounts for you. Pick one of these paths:
Link as a secondary device (existing Signal account)
If you already use Signal on a phone, link the bridge as a secondary device:
signal-cli link -n "claude-bridge"
This prints a sgnl://linkdevice... URL. Render it as a QR code and scan with the Signal app on your phone (Settings → Linked devices → Link new device).
Once linked, the bridge auto-detects the account on first launch.
Headless registration (fresh number, no primary phone)
For a fresh, dedicated Signal account on a server or container, register signal-cli directly:
signal-cli -u +<PHONE_NUMBER> register
signal-cli -u +<PHONE_NUMBER> verify <CODE_FROM_SMS>
If register errors with Captcha required, Signal wants a one-time challenge:
-
Open https://signalcaptchas.org/registration/generate.html in a browser. signal-cli's docs recommend doing this from the same network/IP as the host.
-
Solve the captcha. When the "Open Signal" link appears, right-click and copy its URL; it starts with signalcaptcha://signal-recaptcha-v2....
-
Re-run register with the token, unquoted:
signal-cli -u +<PHONE_NUMBER> register --captcha signalcaptcha://...
The token expires within a few minutes, so paste it quickly.
Notes:
- Cryptographic entropy can be a problem on minimal containers and embedded systems. If
register hangs or fails, install haveged first.
- Verify with a test send before launching the bridge:
signal-cli -u +<PHONE_NUMBER> send -m "test" +<RECIPIENT>.
Install
Add the marketplace, install the plugin:
/plugin marketplace add bufothefrog/claude-signal
/plugin install signal@claude-signal
Then relaunch Claude Code with the channels flag:
claude --dangerously-load-development-channels plugin:signal@claude-signal
The scary-sounding flag is required because Claude Code's channel surface is still pre-GA; every channel plugin loads behind it for now, not just this one.
If exactly one signal-cli account is linked, the bridge auto-detects it. If multiple are linked, point it at the one you want:
/signal:configure account +15551234567
Run /signal:configure with no arguments to see all toggles and their current values, or copy .env.example to ~/.claude/channels/signal/.env for an annotated reference of every setting.
Profile name
Set a Signal display name via /signal:configure profile-name <name> or SIGNAL_PROFILE_NAME=<name> in .env. The bridge applies it on first boot and tracks the last-applied value at ~/.claude/channels/signal/.profile-set so it never overwrites a manually-changed profile on subsequent boots. Delete the marker if you ever need to force a re-apply. Empty by default (no auto-set).
Access control