v2: add Chat SDK channel adapters and skills for 11 platforms

Thin wrapper adapters + SKILL.md for Slack, Telegram, GitHub, Linear,
Google Chat, Teams, WhatsApp Cloud API, Resend, Matrix, Webex, iMessage.
All follow the same pattern as discord-v2.ts: readEnvFile → create*Adapter
→ createChatSdkBridge → registerChannelAdapter.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-09 11:26:33 +03:00
parent 8a06b01646
commit 12af451069
24 changed files with 1338 additions and 4 deletions
+78
View File
@@ -0,0 +1,78 @@
---
name: add-gchat-v2
description: Add Google Chat channel integration to NanoClaw v2 via Chat SDK.
---
# Add Google Chat Channel (v2)
This skill adds Google Chat support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/gchat-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/gchat
```
### Enable the channel
Uncomment the Google Chat import in `src/channels/index.ts`:
```typescript
import './gchat-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Google Chat App
> 1. Go to [Google Cloud Console](https://console.cloud.google.com)
> 2. Create or select a project
> 3. Enable the **Google Chat API**
> 4. Go to **Google Chat API** > **Configuration**:
> - App name and description
> - Connection settings: select **HTTP endpoint URL** and set to `https://your-domain/webhook/gchat`
> 5. Create a **Service Account**:
> - Go to **IAM & Admin** > **Service Accounts** > **Create Service Account**
> - Grant the Chat Bot role
> - Create a JSON key and download it
### Configure environment
Add the service account JSON as a single-line string to `.env`:
```bash
GCHAT_CREDENTIALS={"type":"service_account","project_id":"...","private_key":"...","client_email":"..."}
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Add the bot to a Google Chat space, then send a message or @mention the bot.
## Removal
1. Comment out `import './gchat-v2.js'` in `src/channels/index.ts`
2. Remove `GCHAT_CREDENTIALS` from `.env`
3. `npm uninstall @chat-adapter/gchat`
4. Rebuild and restart
+80
View File
@@ -0,0 +1,80 @@
---
name: add-github-v2
description: Add GitHub channel integration to NanoClaw v2 via Chat SDK. PR comment threads as conversations.
---
# Add GitHub Channel (v2)
This skill adds GitHub support to NanoClaw v2 using the Chat SDK bridge. The agent can participate in PR comment threads.
## Phase 1: Pre-flight
Check if `src/channels/github-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/github
```
### Enable the channel
Uncomment the GitHub import in `src/channels/index.ts`:
```typescript
import './github-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create GitHub credentials
> 1. Go to [GitHub Settings > Developer Settings > Personal Access Tokens](https://github.com/settings/tokens)
> 2. Create a **Fine-grained token** with:
> - Repository access: select the repos you want the bot to monitor
> - Permissions: **Pull requests** (Read & Write), **Issues** (Read & Write)
> 3. Copy the token
> 4. Set up a webhook on your repo(s):
> - Go to **Settings** > **Webhooks** > **Add webhook**
> - Payload URL: `https://your-domain/webhook/github`
> - Content type: `application/json`
> - Secret: generate a random string
> - Events: select **Issue comments**, **Pull request review comments**
### Configure environment
Add to `.env`:
```bash
GITHUB_TOKEN=github_pat_...
GITHUB_WEBHOOK_SECRET=your-webhook-secret
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> @mention the bot in a PR comment or issue comment. The bot should respond within a few seconds.
## Removal
1. Comment out `import './github-v2.js'` in `src/channels/index.ts`
2. Remove `GITHUB_TOKEN` and `GITHUB_WEBHOOK_SECRET` from `.env`
3. `npm uninstall @chat-adapter/github`
4. Rebuild and restart
+86
View File
@@ -0,0 +1,86 @@
---
name: add-imessage-v2
description: Add iMessage channel integration to NanoClaw v2 via Chat SDK. Local (macOS) or remote (Photon API) mode.
---
# Add iMessage Channel (v2)
This skill adds iMessage support to NanoClaw v2 using the Chat SDK bridge. Supports local mode (macOS with Full Disk Access) and remote mode (via Photon API).
## Phase 1: Pre-flight
Check if `src/channels/imessage-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install chat-adapter-imessage
```
### Enable the channel
Uncomment the iMessage import in `src/channels/index.ts`:
```typescript
import './imessage-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Local Mode (macOS)
> **Requirements**: macOS with Full Disk Access granted to your terminal/Node.js process.
>
> 1. Go to **System Settings** > **Privacy & Security** > **Full Disk Access**
> 2. Add your terminal app (Terminal, iTerm2, etc.) or the Node.js binary
> 3. The adapter reads directly from the iMessage database on disk
### Remote Mode (Photon API)
> 1. Set up a [Photon](https://photon.im) account
> 2. Get your server URL and API key
### Configure environment
**Local mode** — add to `.env`:
```bash
IMESSAGE_ENABLED=true
IMESSAGE_LOCAL=true
```
**Remote mode** — add to `.env`:
```bash
IMESSAGE_LOCAL=false
IMESSAGE_SERVER_URL=https://your-photon-server.com
IMESSAGE_API_KEY=your-api-key
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
```
## Phase 4: Verify
> Send an iMessage to the account running NanoClaw. The bot should respond within a few seconds.
## Removal
1. Comment out `import './imessage-v2.js'` in `src/channels/index.ts`
2. Remove iMessage env vars from `.env`
3. `npm uninstall chat-adapter-imessage`
4. Rebuild and restart
+77
View File
@@ -0,0 +1,77 @@
---
name: add-linear-v2
description: Add Linear channel integration to NanoClaw v2 via Chat SDK. Issue comment threads as conversations.
---
# Add Linear Channel (v2)
This skill adds Linear support to NanoClaw v2 using the Chat SDK bridge. The agent can participate in issue comment threads.
## Phase 1: Pre-flight
Check if `src/channels/linear-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/linear
```
### Enable the channel
Uncomment the Linear import in `src/channels/index.ts`:
```typescript
import './linear-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Linear credentials
> 1. Go to [Linear Settings > API](https://linear.app/settings/api)
> 2. Create a **Personal API Key** (or use an OAuth application for team-wide access)
> 3. Copy the API key
> 4. Set up a webhook:
> - Go to **Settings** > **API** > **Webhooks** > **New webhook**
> - URL: `https://your-domain/webhook/linear`
> - Select events: **Comment** (created, updated)
> - Copy the signing secret
### Configure environment
Add to `.env`:
```bash
LINEAR_API_KEY=lin_api_...
LINEAR_WEBHOOK_SECRET=your-webhook-secret
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> @mention the bot in a Linear issue comment. The bot should respond within a few seconds.
## Removal
1. Comment out `import './linear-v2.js'` in `src/channels/index.ts`
2. Remove `LINEAR_API_KEY` and `LINEAR_WEBHOOK_SECRET` from `.env`
3. `npm uninstall @chat-adapter/linear`
4. Rebuild and restart
+77
View File
@@ -0,0 +1,77 @@
---
name: add-matrix-v2
description: Add Matrix channel integration to NanoClaw v2 via Chat SDK. Works with any Matrix homeserver (Element, Beeper, etc.).
---
# Add Matrix Channel (v2)
This skill adds Matrix support to NanoClaw v2 using the Chat SDK bridge. Works with any Matrix homeserver.
## Phase 1: Pre-flight
Check if `src/channels/matrix-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @beeper/chat-adapter-matrix
```
### Enable the channel
Uncomment the Matrix import in `src/channels/index.ts`:
```typescript
import './matrix-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Matrix bot account
> 1. Register a bot account on your Matrix homeserver (e.g., via Element)
> 2. Get the homeserver URL (e.g., `https://matrix.org` or your self-hosted URL)
> 3. Get an access token:
> - In Element: **Settings** > **Help & About** > **Access Token** (advanced)
> - Or via API: `curl -XPOST 'https://matrix.org/_matrix/client/r0/login' -d '{"type":"m.login.password","user":"botuser","password":"..."}'`
> 4. Note the bot's user ID (e.g., `@botuser:matrix.org`)
### Configure environment
Add to `.env`:
```bash
MATRIX_BASE_URL=https://matrix.org
MATRIX_ACCESS_TOKEN=your-access-token
MATRIX_USER_ID=@botuser:matrix.org
MATRIX_BOT_USERNAME=botuser
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Invite the bot to a Matrix room and send a message. The bot should respond within a few seconds.
## Removal
1. Comment out `import './matrix-v2.js'` in `src/channels/index.ts`
2. Remove `MATRIX_BASE_URL`, `MATRIX_ACCESS_TOKEN`, `MATRIX_USER_ID`, `MATRIX_BOT_USERNAME` from `.env`
3. `npm uninstall @beeper/chat-adapter-matrix`
4. Rebuild and restart
+79
View File
@@ -0,0 +1,79 @@
---
name: add-resend-v2
description: Add Resend (email) channel integration to NanoClaw v2 via Chat SDK.
---
# Add Resend Email Channel (v2)
This skill adds email support via Resend to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/resend-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @resend/chat-sdk-adapter
```
### Enable the channel
Uncomment the Resend import in `src/channels/index.ts`:
```typescript
import './resend-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Resend credentials
> 1. Go to [resend.com](https://resend.com) and create an account
> 2. Add and verify your sending domain
> 3. Go to **API Keys** and create a new key
> 4. Set up a webhook:
> - Go to **Webhooks** > **Add webhook**
> - URL: `https://your-domain/webhook/resend`
> - Events: select **email.received** (for inbound email)
> - Copy the signing secret
### Configure environment
Add to `.env`:
```bash
RESEND_API_KEY=re_...
RESEND_FROM_ADDRESS=bot@yourdomain.com
RESEND_FROM_NAME=NanoClaw
RESEND_WEBHOOK_SECRET=your-webhook-secret
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Send an email to the configured from address. The bot should respond via email within a few seconds.
## Removal
1. Comment out `import './resend-v2.js'` in `src/channels/index.ts`
2. Remove `RESEND_API_KEY`, `RESEND_FROM_ADDRESS`, `RESEND_FROM_NAME`, `RESEND_WEBHOOK_SECRET` from `.env`
3. `npm uninstall @resend/chat-sdk-adapter`
4. Rebuild and restart
+81
View File
@@ -0,0 +1,81 @@
---
name: add-slack-v2
description: Add Slack channel integration to NanoClaw v2 via Chat SDK.
---
# Add Slack Channel (v2)
This skill adds Slack support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/slack-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/slack
```
### Enable the channel
Uncomment the Slack import in `src/channels/index.ts`:
```typescript
import './slack-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Slack App (if needed)
If the user doesn't have a Slack app:
> 1. Go to [api.slack.com/apps](https://api.slack.com/apps) and click **Create New App** > **From scratch**
> 2. Name it (e.g., "NanoClaw") and select your workspace
> 3. Go to **OAuth & Permissions** and add Bot Token Scopes:
> - `chat:write`, `channels:history`, `groups:history`, `im:history`, `channels:read`, `groups:read`, `users:read`, `reactions:write`
> 4. Click **Install to Workspace** and copy the **Bot User OAuth Token** (`xoxb-...`)
> 5. Go to **Basic Information** and copy the **Signing Secret**
> 6. Go to **Event Subscriptions**, enable events, and subscribe to:
> - `message.channels`, `message.groups`, `message.im`, `app_mention`
> 7. Set the Request URL to your webhook endpoint (e.g., `https://your-domain/webhook/slack`)
### Configure environment
Add to `.env`:
```bash
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_SIGNING_SECRET=your-signing-secret
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Add the bot to a Slack channel, then send a message or @mention the bot.
> The bot should respond within a few seconds.
## Removal
1. Comment out `import './slack-v2.js'` in `src/channels/index.ts`
2. Remove `SLACK_BOT_TOKEN` and `SLACK_SIGNING_SECRET` from `.env`
3. `npm uninstall @chat-adapter/slack`
4. Rebuild and restart
+75
View File
@@ -0,0 +1,75 @@
---
name: add-teams-v2
description: Add Microsoft Teams channel integration to NanoClaw v2 via Chat SDK.
---
# Add Microsoft Teams Channel (v2)
This skill adds Microsoft Teams support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/teams-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/teams
```
### Enable the channel
Uncomment the Teams import in `src/channels/index.ts`:
```typescript
import './teams-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Teams Bot
> 1. Go to [Azure Portal](https://portal.azure.com) > **Azure Bot** > **Create**
> 2. Fill in the bot details and create
> 3. Go to **Configuration**:
> - Messaging endpoint: `https://your-domain/webhook/teams`
> 4. Go to **Channels** > add **Microsoft Teams**
> 5. Note the **Microsoft App ID** and **Password** (from the bot's Azure AD app registration)
### Configure environment
Add to `.env`:
```bash
TEAMS_APP_ID=your-app-id
TEAMS_APP_PASSWORD=your-app-password
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Add the bot to a Teams channel or send it a direct message. The bot should respond within a few seconds.
## Removal
1. Comment out `import './teams-v2.js'` in `src/channels/index.ts`
2. Remove `TEAMS_APP_ID` and `TEAMS_APP_PASSWORD` from `.env`
3. `npm uninstall @chat-adapter/teams`
4. Rebuild and restart
+82
View File
@@ -0,0 +1,82 @@
---
name: add-telegram-v2
description: Add Telegram channel integration to NanoClaw v2 via Chat SDK.
---
# Add Telegram Channel (v2)
This skill adds Telegram support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/telegram-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/telegram
```
### Enable the channel
Uncomment the Telegram import in `src/channels/index.ts`:
```typescript
import './telegram-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Telegram Bot (if needed)
> 1. Open Telegram and search for `@BotFather`
> 2. Send `/newbot` and follow the prompts:
> - Bot name: Something friendly (e.g., "NanoClaw Assistant")
> - Bot username: Must end with "bot" (e.g., "nanoclaw_bot")
> 3. Copy the bot token (looks like `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`)
### Disable Group Privacy (for group chats)
> **Important for group chats**: By default, Telegram bots only see @mentions and commands in groups. To let the bot see all messages:
>
> 1. Open `@BotFather` > `/mybots` > select your bot
> 2. **Bot Settings** > **Group Privacy** > **Turn off**
### Configure environment
Add to `.env`:
```bash
TELEGRAM_BOT_TOKEN=your-bot-token
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Send a message to your bot in Telegram (search for its username).
> For groups: add the bot to a group and send a message.
> The bot should respond within a few seconds.
## Removal
1. Comment out `import './telegram-v2.js'` in `src/channels/index.ts`
2. Remove `TELEGRAM_BOT_TOKEN` from `.env`
3. `npm uninstall @chat-adapter/telegram`
4. Rebuild and restart
+75
View File
@@ -0,0 +1,75 @@
---
name: add-webex-v2
description: Add Webex channel integration to NanoClaw v2 via Chat SDK.
---
# Add Webex Channel (v2)
This skill adds Cisco Webex support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
Check if `src/channels/webex-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @bitbasti/chat-adapter-webex
```
### Enable the channel
Uncomment the Webex import in `src/channels/index.ts`:
```typescript
import './webex-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create Webex Bot
> 1. Go to [developer.webex.com](https://developer.webex.com/my-apps/new/bot)
> 2. Create a new bot and copy the **Bot Access Token**
> 3. Set up a webhook:
> - Use the Webex API to create a webhook pointing to `https://your-domain/webhook/webex`
> - Or use the Webex Developer Portal
> - Set a webhook secret for signature verification
### Configure environment
Add to `.env`:
```bash
WEBEX_BOT_TOKEN=your-bot-token
WEBEX_WEBHOOK_SECRET=your-webhook-secret
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Add the bot to a Webex space or send it a direct message. The bot should respond within a few seconds.
## Removal
1. Comment out `import './webex-v2.js'` in `src/channels/index.ts`
2. Remove `WEBEX_BOT_TOKEN` and `WEBEX_WEBHOOK_SECRET` from `.env`
3. `npm uninstall @bitbasti/chat-adapter-webex`
4. Rebuild and restart
@@ -0,0 +1,82 @@
---
name: add-whatsapp-cloud-v2
description: Add WhatsApp Business Cloud API channel to NanoClaw v2 via Chat SDK. Official Meta API (not Baileys).
---
# Add WhatsApp Cloud API Channel (v2)
This skill adds WhatsApp support via the official Meta WhatsApp Business Cloud API. This is different from the Baileys-based WhatsApp adapter (which uses WhatsApp Web protocol).
## Phase 1: Pre-flight
Check if `src/channels/whatsapp-cloud-v2.ts` exists and the import is uncommented in `src/channels/index.ts`. If both are in place, skip to Phase 3.
## Phase 2: Apply Code Changes
### Install the adapter package
```bash
npm install @chat-adapter/whatsapp
```
### Enable the channel
Uncomment the WhatsApp Cloud API import in `src/channels/index.ts`:
```typescript
import './whatsapp-cloud-v2.js';
```
### Build
```bash
npm run build
```
## Phase 3: Setup
### Create WhatsApp Business App
> 1. Go to [Meta for Developers](https://developers.facebook.com/apps/) and create an app (type: Business)
> 2. Add the **WhatsApp** product
> 3. Go to **WhatsApp** > **API Setup**:
> - Note the **Phone Number ID** (not the phone number itself)
> - Generate a **permanent System User access token** with `whatsapp_business_messaging` permission
> 4. Go to **WhatsApp** > **Configuration**:
> - Set webhook URL: `https://your-domain/webhook/whatsapp`
> - Set a **Verify Token** (any random string you choose)
> - Subscribe to webhook fields: `messages`
> 5. Copy the **App Secret** from **Settings** > **Basic**
### Configure environment
Add to `.env`:
```bash
WHATSAPP_ACCESS_TOKEN=your-system-user-access-token
WHATSAPP_PHONE_NUMBER_ID=your-phone-number-id
WHATSAPP_APP_SECRET=your-app-secret
WHATSAPP_VERIFY_TOKEN=your-verify-token
```
Sync to container: `mkdir -p data/env && cp .env data/env/env`
### Build and restart
```bash
npm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw # macOS
# systemctl --user restart nanoclaw # Linux
```
## Phase 4: Verify
> Send a message to your WhatsApp Business number. The bot should respond within a few seconds.
> Note: WhatsApp Cloud API only supports 1:1 DMs, not group chats.
## Removal
1. Comment out `import './whatsapp-cloud-v2.js'` in `src/channels/index.ts`
2. Remove `WHATSAPP_ACCESS_TOKEN`, `WHATSAPP_PHONE_NUMBER_ID`, `WHATSAPP_APP_SECRET`, `WHATSAPP_VERIFY_TOKEN` from `.env`
3. `npm uninstall @chat-adapter/whatsapp`
4. Rebuild and restart
+189
View File
@@ -0,0 +1,189 @@
# NanoClaw v2 Checklist
Status: [x] done, [~] partial, [ ] not started
---
## Core Architecture
- [x] Session DB replaces IPC (messages_in / messages_out as sole IO)
- [x] Central DB (agent groups, messaging groups, sessions, routing)
- [x] Host sweep (stale detection, retry with backoff, recurrence scheduling)
- [x] Active delivery polling (1s for running sessions)
- [x] Sweep delivery polling (60s across all sessions)
- [x] Container runner with session DB mounting
- [x] Per-session container lifecycle and idle timeout
- [x] Session resume (sessionId + resumeAt across queries)
- [x] Graceful shutdown (SIGTERM/SIGINT handlers)
- [x] Orphan container cleanup on startup
## Agent Runner (Container)
- [x] Poll loop (pending messages, status transitions, idle detection)
- [x] Concurrent follow-up polling while agent is thinking
- [x] Message formatter (chat, task, webhook, system kinds)
- [x] Command categorization (admin, filtered, passthrough)
- [x] Transcript archiving (pre-compact hook)
- [x] XML message formatting with sender, timestamp
- [~] Media handling inbound (formatter references attachments, no download-from-URL)
## Agent Providers
- [x] Claude provider (Agent SDK, tool allowlist, message stream, session resume)
- [x] Mock provider (testing)
- [x] Provider factory
- [ ] Codex provider
- [ ] OpenCode provider
## Channel Adapters
- [x] Channel adapter interface (setup, deliver, teardown, typing)
- [x] Chat SDK bridge (generic, works with any Chat SDK adapter)
- [x] Chat SDK SQLite state adapter (KV, subscriptions, locks, lists)
- [x] Discord via Chat SDK
- [~] Slack via Chat SDK (adapter + skill written, not tested)
- [~] Telegram via Chat SDK (adapter + skill written, not tested)
- [~] Microsoft Teams via Chat SDK (adapter + skill written, not tested)
- [~] Google Chat via Chat SDK (adapter + skill written, not tested)
- [~] Linear via Chat SDK (adapter + skill written, not tested)
- [~] GitHub via Chat SDK (adapter + skill written, not tested)
- [~] WhatsApp Cloud API via Chat SDK (adapter + skill written, not tested)
- [~] Resend (email) via Chat SDK (adapter + skill written, not tested)
- [~] Matrix via Chat SDK (adapter + skill written, not tested)
- [~] Webex via Chat SDK (adapter + skill written, not tested)
- [~] iMessage via Chat SDK (adapter + skill written, not tested)
- [x] Backward compatibility with native channels (old adapters still work)
- [ ] Setup flow wired to v2 channels
- [ ] Setup communicates each group is a different agent, distinct names
- [ ] Setup vs production channel separation
- [ ] Generate visual diagram of customized instance at end of setup
## Routing
- [x] Inbound routing (platform ID + thread ID -> agent group -> session)
- [x] Auto-create messaging group on first message
- [x] Session resolution (shared vs per-thread modes)
- [x] Message writing to session DB with seq numbering
- [x] Container waking on new message
- [~] Trigger rule matching (router picks highest-priority agent, regex/mention matching TODO)
## Rich Messaging
- [x] Interactive cards with buttons (ask_user_question)
- [x] Native platform rendering (Discord embeds, buttons)
- [x] Message editing
- [x] Emoji reactions
- [x] File sending from agent (outbox -> delivery)
- [x] File upload delivery (buffer-based via adapter)
- [x] Markdown formatting
- [~] Formatted /usage, /context, /cost output (commands pass through, no rich card formatting)
- [ ] Context window visibility: show position in context, approaching compaction, when compaction happens, post-compaction state
- [ ] Threading and replies support
## MCP Tools (Container)
- [x] send_message (text, optional cross-channel targeting)
- [x] send_file (copy to outbox, write messages_out)
- [x] edit_message
- [x] add_reaction
- [x] send_card
- [x] ask_user_question (blocking poll for response)
- [x] schedule_task (with process_after and recurrence)
- [x] list_tasks
- [x] cancel_task / pause_task / resume_task
- [x] send_to_agent (writes message, routing incomplete)
## Scheduling
- [x] One-shot scheduled messages (process_after / deliver_after)
- [x] Recurring tasks via cron expressions
- [x] Host sweep picks up due messages and advances recurrence
- [x] Scheduled outbound messages (no container wake needed)
- [~] Pre-agent scripts (task kind with script field, documented but not verified)
## Permissions and Approval Flows
- [x] Admin user ID per group
- [x] Admin-only command filtering in container
- [ ] Approval flow (sensitive action -> card to admin -> approve/reject -> execute)
- [ ] Role definitions beyond admin (custom roles, per-group permissions)
- [ ] Configurable sensitive action list
- [ ] Non-main groups requesting sensitive actions
- [ ] Agent requests dependency/package install (persists via Dockerfile change, requires approval)
- [ ] Agent self-modification flow:
- [ ] Agent requests code changes by delegating to a builder agent
- [ ] Builder agent has write access to the requesting agent's code and Dockerfile
- [ ] Approval modes: approve per-edit as builder works, or approve full diff at the end
- [ ] Diff review card sent to admin showing all proposed changes
- [ ] On approval: apply edits, rebuild container image, restart agent
- [ ] On rejection: discard changes, notify requesting agent
## Agent-to-Agent Communication
- [~] send_to_agent MCP tool (writes message, host-side routing TODO)
- [ ] Host delivery to target agent's session DB
- [ ] Agent spawning a new sub-agent
- [ ] Internal-only agents (no channel attached)
- [ ] Permission delegation from parent to child agent
- [ ] Specialist sub-agents (browser agent, dev agent — user's agent delegates with request/approval)
## In-Chat Agent Management
- [x] /clear (resets session)
- [x] /compact (triggers context compaction)
- [~] /context (passes through, no rich formatting)
- [~] /usage (passes through, no rich formatting)
- [~] /cost (passes through, no rich formatting)
- [ ] Smooth session transitions: load context into new sessions, solve cold start problem
- [ ] MCP/package installation from chat
- [ ] Browse MCP marketplace / skills repository from chat
## Webhook Ingestion
- [ ] Generic webhook endpoint for external events
- [ ] GitHub webhook handling
- [ ] CI/CD notification handling
- [ ] Webhook -> messages_in routing
## System Actions
- [ ] register_group from inside agent (stub exists)
- [ ] reset_session from inside agent (stub exists)
## Integrations
- [ ] Vercel CLI integration in setup process
- [ ] Skills for deploying and managing Vercel websites from chat
- [ ] Office 365 integration (create/edit documents with inline suggestions)
## Memory
- [ ] Shared memory with approval flow (write to global memory requires admin approval)
## Migration
- [ ] v1 -> v2 migration skill
- [ ] Database migration (v1 SQLite -> v2 central DB + session DBs)
- [ ] Channel credential preservation
- [ ] Custom skill/code porting
## Testing
- [x] DB layer tests (agent groups, messaging groups, sessions, pending questions)
- [x] Channel registry tests
- [x] Poll loop / formatter tests
- [x] Integration test (container agent-runner)
- [x] Host core tests
- [ ] End-to-end flow tests (message in -> agent -> message out -> delivery)
- [ ] Delivery polling tests
- [ ] Host sweep tests (stale detection, recurrence)
- [ ] Multi-channel integration tests
## Rollout
- [ ] Internal testing across all channels
- [ ] Migration skill built and tested
- [ ] PR factory migrated as validation
- [ ] Blog post / announcement
- [ ] Video demos of key flows
- [ ] Vercel coordination
+20
View File
@@ -0,0 +1,20 @@
/**
* Google Chat channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createGoogleChatAdapter } from '@chat-adapter/gchat';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('gchat', {
factory: () => {
const env = readEnvFile(['GCHAT_CREDENTIALS']);
if (!env.GCHAT_CREDENTIALS) return null;
const gchatAdapter = createGoogleChatAdapter({
credentials: JSON.parse(env.GCHAT_CREDENTIALS),
});
return createChatSdkBridge({ adapter: gchatAdapter, concurrency: 'concurrent' });
},
});
+22
View File
@@ -0,0 +1,22 @@
/**
* GitHub channel adapter (v2) — uses Chat SDK bridge.
* PR comment threads as conversations.
* Self-registers on import.
*/
import { createGitHubAdapter } from '@chat-adapter/github';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('github', {
factory: () => {
const env = readEnvFile(['GITHUB_TOKEN', 'GITHUB_WEBHOOK_SECRET']);
if (!env.GITHUB_TOKEN) return null;
const githubAdapter = createGitHubAdapter({
token: env.GITHUB_TOKEN,
webhookSecret: env.GITHUB_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: githubAdapter, concurrency: 'queue' });
},
});
+25
View File
@@ -0,0 +1,25 @@
/**
* iMessage channel adapter (v2) — uses Chat SDK bridge.
* Supports local mode (macOS Full Disk Access) and remote mode (Photon API).
* Self-registers on import.
*/
import { createiMessageAdapter } from 'chat-adapter-imessage';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('imessage', {
factory: () => {
const env = readEnvFile(['IMESSAGE_ENABLED', 'IMESSAGE_LOCAL', 'IMESSAGE_SERVER_URL', 'IMESSAGE_API_KEY']);
const isLocal = env.IMESSAGE_LOCAL !== 'false';
if (isLocal && !env.IMESSAGE_ENABLED) return null;
if (!isLocal && !env.IMESSAGE_SERVER_URL) return null;
const imessageAdapter = createiMessageAdapter({
local: isLocal,
serverUrl: env.IMESSAGE_SERVER_URL,
apiKey: env.IMESSAGE_API_KEY,
});
return createChatSdkBridge({ adapter: imessageAdapter, concurrency: 'concurrent' });
},
});
+34 -4
View File
@@ -1,12 +1,42 @@
// Channel self-registration barrel file.
// Each import triggers the channel module's registerChannel() call.
// Each import triggers the channel module's registerChannelAdapter() call.
// discord
// gmail
// import './discord-v2.js';
// slack
// import './slack-v2.js';
// telegram
// import './telegram-v2.js';
// whatsapp
// github
// import './github-v2.js';
// linear
// import './linear-v2.js';
// google chat
// import './gchat-v2.js';
// microsoft teams
// import './teams-v2.js';
// whatsapp cloud api
// import './whatsapp-cloud-v2.js';
// resend (email)
// import './resend-v2.js';
// matrix
// import './matrix-v2.js';
// webex
// import './webex-v2.js';
// imessage
// import './imessage-v2.js';
// gmail (native, no Chat SDK)
// whatsapp baileys (native, no Chat SDK)
+22
View File
@@ -0,0 +1,22 @@
/**
* Linear channel adapter (v2) — uses Chat SDK bridge.
* Issue comment threads as conversations.
* Self-registers on import.
*/
import { createLinearAdapter } from '@chat-adapter/linear';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('linear', {
factory: () => {
const env = readEnvFile(['LINEAR_API_KEY', 'LINEAR_WEBHOOK_SECRET']);
if (!env.LINEAR_API_KEY) return null;
const linearAdapter = createLinearAdapter({
apiKey: env.LINEAR_API_KEY,
webhookSecret: env.LINEAR_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: linearAdapter, concurrency: 'queue' });
},
});
+23
View File
@@ -0,0 +1,23 @@
/**
* Matrix channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createMatrixAdapter } from '@beeper/chat-adapter-matrix';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('matrix', {
factory: () => {
const env = readEnvFile(['MATRIX_BASE_URL', 'MATRIX_ACCESS_TOKEN', 'MATRIX_USER_ID', 'MATRIX_BOT_USERNAME']);
if (!env.MATRIX_BASE_URL) return null;
// Matrix adapter reads from process.env directly
process.env.MATRIX_BASE_URL = env.MATRIX_BASE_URL;
if (env.MATRIX_ACCESS_TOKEN) process.env.MATRIX_ACCESS_TOKEN = env.MATRIX_ACCESS_TOKEN;
if (env.MATRIX_USER_ID) process.env.MATRIX_USER_ID = env.MATRIX_USER_ID;
if (env.MATRIX_BOT_USERNAME) process.env.MATRIX_BOT_USERNAME = env.MATRIX_BOT_USERNAME;
const matrixAdapter = createMatrixAdapter();
return createChatSdkBridge({ adapter: matrixAdapter, concurrency: 'concurrent' });
},
});
+23
View File
@@ -0,0 +1,23 @@
/**
* Resend (email) channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createResendAdapter } from '@resend/chat-sdk-adapter';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('resend', {
factory: () => {
const env = readEnvFile(['RESEND_API_KEY', 'RESEND_FROM_ADDRESS', 'RESEND_FROM_NAME', 'RESEND_WEBHOOK_SECRET']);
if (!env.RESEND_API_KEY) return null;
const resendAdapter = createResendAdapter({
apiKey: env.RESEND_API_KEY,
fromAddress: env.RESEND_FROM_ADDRESS,
fromName: env.RESEND_FROM_NAME,
webhookSecret: env.RESEND_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: resendAdapter, concurrency: 'queue' });
},
});
+21
View File
@@ -0,0 +1,21 @@
/**
* Slack channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createSlackAdapter } from '@chat-adapter/slack';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('slack', {
factory: () => {
const env = readEnvFile(['SLACK_BOT_TOKEN', 'SLACK_SIGNING_SECRET']);
if (!env.SLACK_BOT_TOKEN) return null;
const slackAdapter = createSlackAdapter({
botToken: env.SLACK_BOT_TOKEN,
signingSecret: env.SLACK_SIGNING_SECRET,
});
return createChatSdkBridge({ adapter: slackAdapter, concurrency: 'concurrent' });
},
});
+21
View File
@@ -0,0 +1,21 @@
/**
* Microsoft Teams channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createTeamsAdapter } from '@chat-adapter/teams';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('teams', {
factory: () => {
const env = readEnvFile(['TEAMS_APP_ID', 'TEAMS_APP_PASSWORD']);
if (!env.TEAMS_APP_ID) return null;
const teamsAdapter = createTeamsAdapter({
appId: env.TEAMS_APP_ID,
appPassword: env.TEAMS_APP_PASSWORD,
});
return createChatSdkBridge({ adapter: teamsAdapter, concurrency: 'concurrent' });
},
});
+21
View File
@@ -0,0 +1,21 @@
/**
* Telegram channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createTelegramAdapter } from '@chat-adapter/telegram';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('telegram', {
factory: () => {
const env = readEnvFile(['TELEGRAM_BOT_TOKEN']);
if (!env.TELEGRAM_BOT_TOKEN) return null;
const telegramAdapter = createTelegramAdapter({
botToken: env.TELEGRAM_BOT_TOKEN,
mode: 'polling',
});
return createChatSdkBridge({ adapter: telegramAdapter, concurrency: 'concurrent' });
},
});
+21
View File
@@ -0,0 +1,21 @@
/**
* Webex channel adapter (v2) — uses Chat SDK bridge.
* Self-registers on import.
*/
import { createWebexAdapter } from '@bitbasti/chat-adapter-webex';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('webex', {
factory: () => {
const env = readEnvFile(['WEBEX_BOT_TOKEN', 'WEBEX_WEBHOOK_SECRET']);
if (!env.WEBEX_BOT_TOKEN) return null;
const webexAdapter = createWebexAdapter({
botToken: env.WEBEX_BOT_TOKEN,
webhookSecret: env.WEBEX_WEBHOOK_SECRET,
});
return createChatSdkBridge({ adapter: webexAdapter, concurrency: 'concurrent' });
},
});
+24
View File
@@ -0,0 +1,24 @@
/**
* WhatsApp Cloud API channel adapter (v2) — uses Chat SDK bridge.
* Uses the official Meta WhatsApp Business Cloud API (not Baileys).
* Self-registers on import.
*/
import { createWhatsAppAdapter } from '@chat-adapter/whatsapp';
import { readEnvFile } from '../env.js';
import { createChatSdkBridge } from './chat-sdk-bridge.js';
import { registerChannelAdapter } from './channel-registry.js';
registerChannelAdapter('whatsapp-cloud', {
factory: () => {
const env = readEnvFile(['WHATSAPP_ACCESS_TOKEN', 'WHATSAPP_PHONE_NUMBER_ID', 'WHATSAPP_APP_SECRET', 'WHATSAPP_VERIFY_TOKEN']);
if (!env.WHATSAPP_ACCESS_TOKEN) return null;
const whatsappAdapter = createWhatsAppAdapter({
accessToken: env.WHATSAPP_ACCESS_TOKEN,
phoneNumberId: env.WHATSAPP_PHONE_NUMBER_ID,
appSecret: env.WHATSAPP_APP_SECRET,
verifyToken: env.WHATSAPP_VERIFY_TOKEN,
});
return createChatSdkBridge({ adapter: whatsappAdapter, concurrency: 'concurrent' });
},
});