Skip to main content
ClaudeWave
Skill30.7k 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 support via a native adapter that speaks JSON-RPC to a
[signal-cli](https://github.com/AsamK/signal-cli) daemon — no Chat SDK bridge,
only Node.js builtins. NanoClaw links to Signal as a *secondary device* on your
existing phone: no new number, no bot API. Your assistant sends and receives as
the number on the phone that scans the link.

## Apply

### 1. Install signal-cli

NanoClaw talks to Signal through signal-cli, which has no bot API of its own.
Install it if it isn't on PATH yet — Homebrew on macOS, the native release binary
on Linux (neither needs Java). If it's already installed this is a no-op:

```nc:run effect:external
command -v signal-cli >/dev/null 2>&1 || bash setup/install-signal-cli.sh
```

### 2. Copy the adapter and its registration test

Fetch the `channels` branch and copy the Signal adapter and its registration test
into `src/channels/` (overwrite — the branch is canonical):

```nc:copy from-branch:channels
src/channels/signal.ts
src/channels/signal-registration.test.ts
```

### 3. Register the adapter

Append the self-registration import to the channel barrel (skipped if the line is
already present). This one line is the skill's only reach-in into core:

```nc:append to:src/channels/index.ts
import './signal.js';
```

### 4. Install the QR-rendering dependency

The device-link step renders the linking URL as a terminal QR via `qrcode`.
Pinned to exact versions — the supply-chain policy rejects ranges and `latest`:

```nc:dep
qrcode@1.5.4
@types/qrcode@1.5.6
```

The adapter itself consumes only Node.js builtins, so there is no adapter package
to install — `qrcode` is purely for rendering the link during setup.

### 5. Build and validate

Build first: it guards the adapter's typed core-API consumption. Then run the one
integration test.

```nc:run effect:build
pnpm run build
```
```nc:run effect:test
pnpm exec vitest run src/channels/signal-registration.test.ts
```

`signal-registration.test.ts` 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 has no npm dependency to guard; its typed
core-API consumption is covered by the build. End-to-end delivery against a real
Signal account is verified manually once the service runs.

## Link your Signal account

This is the whole credential step. signal-cli opens a device-link handshake,
prints a `sgnl://linkdevice…` URL, and renders it as a scannable QR. You scan it
once from the phone that already runs Signal; that phone's number becomes the
account NanoClaw sends and receives as — no number is registered.

The device-link runs signal-cli, so it must be reachable first — on `PATH`, or at
`$SIGNAL_CLI_PATH`. If step 1's install didn't land, the link step has nothing to
drive; confirm it's present before linking (re-run step 1 if this fails):

```nc:run effect:check
command -v signal-cli >/dev/null 2>&1 || [ -x "$SIGNAL_CLI_PATH" ]
```

Tell the user:

```nc:operator
Link NanoClaw to your Signal account:
1. On the phone that runs Signal, open Signal → Settings → Linked Devices → Link New Device.
2. Scan the QR code shown below — or open the `sgnl://linkdevice…` link printed under it on that phone.
3. Wait for confirmation. The linking URL expires after ~3 minutes; re-run this step for a fresh one.
```

Run the device-link. It blocks until you scan, then reports the linked phone
number back as the account — that number is both your owner handle and the
conversation address the wiring step needs:

```nc:run effect:step capture:platform_id=ACCOUNT,owner_handle=ACCOUNT
pnpm exec tsx setup/index.ts --step signal-auth
```

`owner_handle` and `platform_id` both come back as the bare phone number (e.g.
`+15551234567`). Your assistant reaches you through Signal's Note to Self, so the
owner conversation is addressed by your own number — not a per-contact UUID.

## Persist the account

Store the linked number so the adapter binds the right account on start, then sync
it into the container env:

```nc:env-set
SIGNAL_ACCOUNT={{platform_id}}
```
## Restart

Restart the service so it loads the Signal adapter and binds the account you just
linked, and wait for its CLI socket before wiring:

```nc:run effect:restart
bash setup/lib/restart.sh
```

## Wiring

### DMs

After the service starts, send any message to the Signal number from your
personal Signal app. The router auto-creates a `messaging_groups` row. Then:

```bash
pnpm exec tsx scripts/q.ts data/v2.db \
  "SELECT id, platform_id FROM messaging_groups WHERE channel_type='signal' ORDER BY created_at DESC LIMIT 5"
```

Pass the `id` to `/init-first-agent` or `/manage-channels` to wire it to an agent group.

### Groups

Add the Signal number to a group from your phone, send any message, then wire the resulting row the same way. Each group gets its own session with the default `shared` mode (one session per agent + messaging group). Create the wiring with `ncl` — **the host service must be running** (`ncl` connects to it over a Unix socket):

```bash
# Engage mode/pattern default to the Signal adapter's declared channel defaults
ncl wirings create --messaging-group-id mg-GROUPID --agent-group-id ag-AGENTID
```

### Grant user access

New Signal users (including the owner's Signal identity) are silently dropped with `not_member` until granted access. After the user's first message appears in `messaging_groups` (host service running):

```bash
ncl users create --id "signal:UUID" --kind signal --display-name "<name>"
ncl roles grant --user "signal:UUID" --role owner
ncl members add --user "signal:UUID" --group ag-AGENTID
```

Find the UUID from `messaging_groups.platform_id` or the `users` table.

## Next Steps

If you're in the middle of `/setup`, return to the setup flow now. Otherwise wire
this channel with `/init-first-agent` (or `/manage-channels`).

## Channel Info
add-atomic-chat-toolSkill

Add Atomic Chat MCP server so the container agent can call local models served by the Atomic Chat desktop app via its OpenAI-compatible API.

add-codexSkill

Use Codex (OpenAI's codex app-server) as a full agent provider — planning, tool orchestration, MCP tools, server-side history, session resume — alongside or instead of Claude. ChatGPT subscription or OpenAI API key, vault-only via OneCLI. Per-group via `ncl groups config update --provider codex`. Distinct from using OpenAI as an MCP tool (where Claude remains the planner).

add-dashboardSkill

Add a monitoring dashboard to NanoClaw. Installs @nanoco/nanoclaw-dashboard and a pusher that sends periodic JSON snapshots.

add-deltachatSkill

Add DeltaChat channel integration via @deltachat/stdio-rpc-server. Native adapter — no Chat SDK bridge. Email-based messaging with end-to-end encryption.

add-discordSkill

Add Discord bot channel integration via Chat SDK.

add-emacsSkill

Add Emacs as a channel. Opens an interactive chat buffer and org-mode integration so you can talk to NanoClaw from within Emacs (Doom, Spacemacs, or vanilla). Local HTTP bridge — no bot token or external service needed.

add-gcal-toolSkill

Add Google Calendar as an MCP tool (list calendars, list/search/create events, free/busy queries) using OneCLI-managed OAuth. Multi-calendar and multi-account supported. Mirrors /add-gmail-tool's stub pattern — no raw credentials ever reach the container; OneCLI injects real tokens at request time.

add-gchatSkill

Add Google Chat channel integration via Chat SDK.