Skip to main content
ClaudeWave
Skill29.8k repo starsupdated yesterday

add-signal

The add-signal skill integrates Signal messaging into NanoClaw through a native JSON-RPC adapter that communicates with signal-cli's TCP daemon, requiring only Node.js built-in modules. Use this when you need Signal channel support without relying on Chat SDK bridges, registering either a dedicated phone number or linking as a secondary device to an existing Signal account after installing Java 17+ and signal-cli.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/nanocoai/nanoclaw /tmp/add-signal && cp -r /tmp/add-signal/.claude/skills/add-signal ~/.claude/skills/add-signal
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Add Signal Channel

Adds Signal messaging support via a native adapter that speaks JSON-RPC to a [signal-cli](https://github.com/AsamK/signal-cli) TCP daemon. No Chat SDK bridge — only Node.js builtins (`node:net`, `node:child_process`, `node:fs`).

Unlike Telegram or Discord, Signal has no bot API. NanoClaw registers as a full Signal account on a dedicated phone number (recommended) or links as a secondary device on your existing number.

## Prerequisites

### Java

signal-cli requires Java 17+:

```bash
java -version
```

If missing:
- **macOS:** `brew install --cask temurin@17`
- **Debian/Ubuntu:** `sudo apt-get install -y default-jre`
- **RHEL/Fedora:** `sudo dnf install -y java-17-openjdk`

Java 17–25 all work.

### signal-cli

- **macOS:** `brew install signal-cli`
- **Linux:** download the native binary from [GitHub releases](https://github.com/AsamK/signal-cli/releases):

```bash
SIGNAL_CLI_VERSION=$(curl -fsSL https://api.github.com/repos/AsamK/signal-cli/releases/latest | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])")
curl -fsSL "https://github.com/AsamK/signal-cli/releases/download/v${SIGNAL_CLI_VERSION}/signal-cli-${SIGNAL_CLI_VERSION}-Linux-native.tar.gz" \
  | tar -xz -C ~/.local
ln -sf ~/.local/signal-cli ~/.local/bin/signal-cli
signal-cli --version
```

> The Linux native tarball extracts a single binary directly to `~/.local/signal-cli` (not into a subdirectory). The symlink above puts it on PATH.

## Registration

Two paths. The new-number path is recommended and battle-tested.

### Path A: Register a new number (recommended)

Use a dedicated SIM or VoIP number. NanoClaw owns it entirely.

> **VoIP numbers:** Signal requires SMS verification before voice. Some VoIP providers are blocked even for voice calls. If registration fails with an auth error, try a different provider or a physical SIM.

**Step 1: Solve the CAPTCHA**

Signal requires a CAPTCHA on first registration:

1. Open `https://signalcaptchas.org/registration/generate.html` in a browser
2. Solve the captcha
3. Right-click the **"Open Signal"** button → **Copy Link**
4. The link starts with `signalcaptcha://` — the token is everything after that prefix

**Step 2: Request SMS verification**

```bash
signal-cli -a +1YOURNUMBER register --captcha "PASTE_TOKEN_HERE"
```

**Step 3: Voice call fallback (if your number can't receive SMS)**

Wait ~60 seconds after the SMS request, then:

```bash
signal-cli -a +1YOURNUMBER register --voice --captcha "SAME_TOKEN"
```

Signal calls your number and reads a 6-digit code. The same captcha token is reusable — no need to solve a new one.

> You must request SMS first. Requesting voice immediately fails with `Invalid verification method: Before requesting voice verification…`

**Step 4: Verify**

```bash
signal-cli -a +1YOURNUMBER verify CODE
```

No output = success.

**Step 5: Set profile name (optional)**

> ⚠ Stop NanoClaw before running signal-cli commands — the daemon holds an exclusive lock on its data directory while running.

Run from your NanoClaw project root:

```bash
source setup/lib/install-slug.sh

# macOS
launchctl unload ~/Library/LaunchAgents/$(launchd_label).plist
signal-cli -a +1YOURNUMBER updateProfile --name "YourBotName"
# optionally: --avatar /path/to/avatar.jpg
launchctl load ~/Library/LaunchAgents/$(launchd_label).plist

# Linux
systemctl --user stop $(systemd_unit)
signal-cli -a +1YOURNUMBER updateProfile --name "YourBotName"
systemctl --user start $(systemd_unit)
```

### Path B: Link as secondary device

Joins an existing Signal account as a secondary device. Simpler, but NanoClaw shares your personal number.

```bash
signal-cli -a +1YOURNUMBER link --name "NanoClaw"
```

This prints a `tsdevice:` URI. Scan it as a QR code on your phone: **Settings → Linked Devices → Link New Device**. QR codes expire in ~30 seconds — re-run if it expires.

## Install

### Pre-flight (idempotent)

Skip to **Credentials** if all of these are already in place:

- `src/channels/signal.ts` exists
- `src/channels/signal.test.ts` exists
- `src/channels/signal-registration.test.ts` exists
- `src/channels/index.ts` contains `import './signal.js';`

Otherwise continue. Every step below is safe to re-run.

### 1. Fetch the channels branch

```bash
git fetch origin channels
```

### 2. Copy the adapter and tests

```bash
git show origin/channels:src/channels/signal.ts                   > src/channels/signal.ts
git show origin/channels:src/channels/signal.test.ts             > src/channels/signal.test.ts
git show origin/channels:src/channels/signal-registration.test.ts > src/channels/signal-registration.test.ts
```

### 3. Append the self-registration import

Append to `src/channels/index.ts` (skip if the line is already present):

```typescript
import './signal.js';
```

### 4. Build and validate

```bash
pnpm run build
pnpm exec vitest run src/channels/signal-registration.test.ts
```

Both must be clean before proceeding. `signal-registration.test.ts` is the one integration test: it imports the real channel barrel and asserts the registry contains `signal`. It goes red if the `import './signal.js';` line is deleted or drifts, or if the barrel fails to evaluate (so the channel genuinely would not register). The adapter consumes only Node.js builtins, so there is no npm dependency to guard for this channel. The adapter's typed core-API consumption is guarded by `pnpm run build`.

## Credentials

Add to `.env`:

```bash
SIGNAL_ACCOUNT=+1YOURNUMBER
```

### Optional settings

```bash
# TCP daemon host and port (default: 127.0.0.1:7583)
SIGNAL_TCP_HOST=127.0.0.1
SIGNAL_TCP_PORT=7583

# Path to the signal-cli binary (default: resolved on PATH)
SIGNAL_CLI_PATH=/usr/local/bin/signal-cli

# Whether NanoClaw manages the daemon lifecycle (default: true).
# Set to false if you run signal-cli daemon externally.
SIGNAL_MANAGE_DAEMON=true

# signal-cli data directory (default: ~/.local/share/signal-cli)
SIGNAL_DATA_DIR=~/.local/share/signal-cli
```

**Securi