chore(skills): rename add-*-v2 → add-* and drop dead v1 channel skills

Renamed 13 skill folders to drop the -v2 suffix (the v2/v1 distinction
isn't load-bearing anymore — there is no v1 runtime). Deleted the four
v1 channel skills that occupied the rename target paths (add-discord,
add-slack, add-telegram, add-whatsapp); they targeted src/v1 which is
reference-only per CLAUDE.md.

Skill content still says "v2" in places — that's a follow-up commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-04-17 14:38:19 +03:00
parent 4857512267
commit 00fb1bee4a
41 changed files with 289 additions and 1285 deletions

View File

@@ -1,80 +1,82 @@
---
name: add-slack
description: Add Slack as a channel. Can replace WhatsApp entirely or run alongside it. Uses Socket Mode (no public URL needed).
name: add-slack-v2
description: Add Slack channel integration to NanoClaw v2 via Chat SDK.
---
# Add Slack Channel
This skill adds Slack support to NanoClaw, then walks through interactive setup.
Adds Slack support to NanoClaw v2 using the Chat SDK bridge.
## Phase 1: Pre-flight
## Install
### Check if already applied
v2 trunk doesn't ship channels. This skill copies the Slack adapter in from the `channels` branch.
Check if `src/channels/slack.ts` exists. If it does, skip to Phase 3 (Setup). The code changes are already in place.
### Pre-flight (idempotent)
### Ask the user
Skip to **Credentials** if all of these are already in place:
**Do they already have a Slack app configured?** If yes, collect the Bot Token and App Token now. If no, we'll create one in Phase 3.
- `src/channels/slack.ts` exists
- `src/channels/index.ts` contains `import './slack.js';`
- `@chat-adapter/slack` is listed in `package.json` dependencies
## Phase 2: Apply Code Changes
Otherwise continue. Every step below is safe to re-run.
### Ensure channel remote
### 1. Fetch the channels branch
```bash
git remote -v
git fetch origin channels
```
If `slack` is missing, add it:
### 2. Copy the adapter
```bash
git remote add slack https://github.com/qwibitai/nanoclaw-slack.git
git show origin/channels:src/channels/slack.ts > src/channels/slack.ts
```
### Merge the skill branch
### 3. Append the self-registration import
```bash
git fetch slack main
git merge slack/main || {
git checkout --theirs pnpm-lock.yaml
git add pnpm-lock.yaml
git merge --continue
}
Append to `src/channels/index.ts` (skip if the line is already present):
```typescript
import './slack.js';
```
This merges in:
- `src/channels/slack.ts` (SlackChannel class with self-registration via `registerChannel`)
- `src/channels/slack.test.ts` (46 unit tests)
- `import './slack.js'` appended to the channel barrel file `src/channels/index.ts`
- `@slack/bolt` npm dependency in `package.json`
- `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` in `.env.example`
If the merge reports conflicts, resolve them by reading the conflicted files and understanding the intent of both sides.
### Validate code changes
### 4. Install the adapter package (pinned)
```bash
pnpm install @chat-adapter/slack@4.26.0
```
### 5. Build
```bash
pnpm install
pnpm run build
pnpm exec vitest run src/channels/slack.test.ts
```
All tests must pass (including the new Slack tests) and build must be clean before proceeding.
## Credentials
## Phase 3: Setup
### Create Slack App
### Create Slack App (if needed)
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**
If the user doesn't have a Slack app, share [SLACK_SETUP.md](SLACK_SETUP.md) which has step-by-step instructions with screenshots guidance, troubleshooting, and a token reference table.
### Enable DMs
Quick summary of what's needed:
1. Create a Slack app at [api.slack.com/apps](https://api.slack.com/apps)
2. Enable Socket Mode and generate an App-Level Token (`xapp-...`)
3. Subscribe to bot events: `message.channels`, `message.groups`, `message.im`
4. Add OAuth scopes: `chat:write`, `channels:history`, `groups:history`, `im:history`, `channels:read`, `groups:read`, `users:read`
5. Install to workspace and copy the Bot Token (`xoxb-...`)
6. Go to **App Home** and enable the **Messages Tab**
7. Check **"Allow users to send Slash commands and messages from the messages tab"**
Wait for the user to provide both tokens.
### Event Subscriptions
8. Go to **Event Subscriptions** and toggle **Enable Events**
9. Set the **Request URL** to `https://your-domain/webhook/slack` — Slack will send a verification challenge; it must pass before you can save
10. Under **Subscribe to bot events**, add:
- `message.channels`, `message.groups`, `message.im`, `app_mention`
11. Click **Save Changes**
12. Slack will show a banner asking you to **reinstall the app** — click it to apply the new event subscriptions
### Configure environment
@@ -82,126 +84,29 @@ Add to `.env`:
```bash
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_APP_TOKEN=xapp-your-app-token
SLACK_SIGNING_SECRET=your-signing-secret
```
Channels auto-enable when their credentials are present — no extra configuration needed.
Sync to container: `mkdir -p data/env && cp .env data/env/env`
Sync to container environment:
### Webhook server
```bash
mkdir -p data/env && cp .env data/env/env
```
The Chat SDK bridge automatically starts a shared webhook server on port 3000 (configurable via `WEBHOOK_PORT` env var). The server handles `/webhook/slack` for Slack and other webhook-based adapters. This port must be publicly reachable from the internet for Slack to deliver events.
The container reads environment from `data/env/env`, not `.env` directly.
If running locally, discuss options for exposing the server — e.g. ngrok (`ngrok http 3000`), Cloudflare Tunnel, or a reverse proxy on a VPS. The resulting public URL becomes the base for `https://your-domain/webhook/slack`.
### Build and restart
## Next Steps
```bash
pnpm run build
launchctl kickstart -k gui/$(id -u)/com.nanoclaw
```
If you're in the middle of `/setup`, return to the setup flow now.
## Phase 4: Registration
Otherwise, run `/manage-channels` to wire this channel to an agent group.
### Get Channel ID
## Channel Info
Tell the user:
> 1. Add the bot to a Slack channel (right-click channel → **View channel details** → **Integrations** → **Add apps**)
> 2. In that channel, the channel ID is in the URL when you open it in a browser: `https://app.slack.com/client/T.../C0123456789` — the `C...` part is the channel ID
> 3. Alternatively, right-click the channel name → **Copy link** — the channel ID is the last path segment
>
> The JID format for NanoClaw is: `slack:C0123456789`
Wait for the user to provide the channel ID.
### Register the channel
The channel ID, name, and folder name are needed. Use `pnpm exec tsx setup/index.ts --step register` with the appropriate flags.
For a main channel (responds to all messages):
```bash
pnpm exec tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_main" --trigger "@${ASSISTANT_NAME}" --channel slack --no-trigger-required --is-main
```
For additional channels (trigger-only):
```bash
pnpm exec tsx setup/index.ts --step register -- --jid "slack:<channel-id>" --name "<channel-name>" --folder "slack_<channel-name>" --trigger "@${ASSISTANT_NAME}" --channel slack
```
## Phase 5: Verify
### Test the connection
Tell the user:
> Send a message in your registered Slack channel:
> - For main channel: Any message works
> - For non-main: `@<assistant-name> hello` (using the configured trigger word)
>
> The bot should respond within a few seconds.
### Check logs if needed
```bash
tail -f logs/nanoclaw.log
```
## Troubleshooting
### Bot not responding
1. Check `SLACK_BOT_TOKEN` and `SLACK_APP_TOKEN` are set in `.env` AND synced to `data/env/env`
2. Check channel is registered: `sqlite3 store/messages.db "SELECT * FROM registered_groups WHERE jid LIKE 'slack:%'"`
3. For non-main channels: message must include trigger pattern
4. Service is running: `launchctl list | grep nanoclaw`
### Bot connected but not receiving messages
1. Verify Socket Mode is enabled in the Slack app settings
2. Verify the bot is subscribed to the correct events (`message.channels`, `message.groups`, `message.im`)
3. Verify the bot has been added to the channel
4. Check that the bot has the required OAuth scopes
### Bot not seeing messages in channels
By default, bots only see messages in channels they've been explicitly added to. Make sure to:
1. Add the bot to each channel you want it to monitor
2. Check the bot has `channels:history` and/or `groups:history` scopes
### "missing_scope" errors
If the bot logs `missing_scope` errors:
1. Go to **OAuth & Permissions** in your Slack app settings
2. Add the missing scope listed in the error message
3. **Reinstall the app** to your workspace — scope changes require reinstallation
4. Copy the new Bot Token (it changes on reinstall) and update `.env`
5. Sync: `mkdir -p data/env && cp .env data/env/env`
6. Restart: `launchctl kickstart -k gui/$(id -u)/com.nanoclaw`
### Getting channel ID
If the channel ID is hard to find:
- In Slack desktop: right-click channel → **Copy link** → extract the `C...` ID from the URL
- In Slack web: the URL shows `https://app.slack.com/client/TXXXXXXX/C0123456789`
- Via API: `curl -s -H "Authorization: Bearer $SLACK_BOT_TOKEN" "https://slack.com/api/conversations.list" | jq '.channels[] | {id, name}'`
## After Setup
The Slack channel supports:
- **Public channels** — Bot must be added to the channel
- **Private channels** — Bot must be invited to the channel
- **Direct messages** — Users can DM the bot directly
- **Multi-channel** — Can run alongside WhatsApp or other channels (auto-enabled by credentials)
## Known Limitations
- **Threads are flattened** — Threaded replies are delivered to the agent as regular channel messages. The agent sees them but has no awareness they originated in a thread. Responses always go to the channel, not back into the thread. Users in a thread will need to check the main channel for the bot's reply. Full thread-aware routing (respond in-thread) requires pipeline-wide changes: database schema, `NewMessage` type, `Channel.sendMessage` interface, and routing logic.
- **No typing indicator** — Slack's Bot API does not expose a typing indicator endpoint. The `setTyping()` method is a no-op. Users won't see "bot is typing..." while the agent works.
- **Message splitting is naive** — Long messages are split at a fixed 4000-character boundary, which may break mid-word or mid-sentence. A smarter split (on paragraph or sentence boundaries) would improve readability.
- **No file/image handling** — The bot only processes text content. File uploads, images, and rich message blocks are not forwarded to the agent.
- **Channel metadata sync is unbounded** — `syncChannelMetadata()` paginates through all channels the bot is a member of, but has no upper bound or timeout. Workspaces with thousands of channels may experience slow startup.
- **Workspace admin policies not detected** — If the Slack workspace restricts bot app installation, the setup will fail at the "Install to Workspace" step with no programmatic detection or guidance. See SLACK_SETUP.md troubleshooting section.
- **type**: `slack`
- **terminology**: Slack has "workspaces" containing "channels." Channels can be public (#general) or private. The bot can also receive direct messages.
- **platform-id-format**: `slack:{channelId}` for channels (e.g., `slack:C0123ABC`), `slack:{dmId}` for DMs (e.g., `slack:D0ARWEBLV63`)
- **how-to-find-id**: Right-click a channel name > "View channel details" — the Channel ID is at the bottom (starts with C). For DMs, the ID starts with D. Or copy the channel link — the ID is the last segment of the URL.
- **supports-threads**: yes
- **typical-use**: Interactive chat — team channels or direct messages
- **default-isolation**: Same agent group for channels where you're the primary user. Separate agent group for channels with different teams or sensitive contexts.