@chat-adapter/slack 4.29.0, pinned) and supports two delivery modes:
- Socket Mode (the setup default) — the bot opens an outbound WebSocket to Slack, so events arrive over that connection and NanoClaw needs no public URL. Ideal for local dev or a host behind NAT. Setting
SLACK_APP_TOKEN(xapp-…) is what flips the adapter into this mode. - Webhook mode — Slack POSTs to
/webhook/slackon NanoClaw’s shared webhook server, which needs a public HTTPS URL that reaches your machine. The adapter uses this mode wheneverSLACK_APP_TOKENis unset.
Prerequisites
- A Slack workspace where you can install apps
- A working NanoClaw install (quickstart)
- A Slack app created From scratch at api.slack.com/apps with these Bot Token Scopes (under OAuth & Permissions):
chat:write,im:write,im:history,channels:read,channels:history,groups:read,groups:history,users:read,reactions:write,files:read,files:write - App Home → enable the Messages Tab and check “Allow users to send slash commands and messages from the messages tab” — without this you can’t DM the bot
- The Bot User OAuth Token (
xoxb-…, shown after Install to Workspace), plus the credential for your chosen mode: an App-Level Token (xapp-…with theconnections:writescope, under Basic Information → App-Level Tokens) for Socket Mode, or the Signing Secret (under Basic Information) for webhook mode. In Socket Mode the signing secret is optional — Slack signs socket frames separately. - Webhook mode only: a way to expose port 3000 publicly — ngrok, Cloudflare Tunnel, or a reverse proxy on a VPS. Socket Mode needs none of this.
Install
Slack is offered in the first-run setup wizard, or add it later by running/add-slack in Claude Code. The wizard flow:
1
Create the Slack app
The wizard opens api.slack.com/apps and walks you through the app creation checklist above: scopes, Messages Tab, signing secret, and workspace install.
2
Choose a delivery mode and paste credentials
The wizard first asks how Slack should deliver events — Socket Mode (default; no public URL) or Public webhook. Then it collects the Bot User OAuth Token plus the mode credential: an App-Level Token (
xapp-…) for Socket Mode, or the Signing Secret for webhook mode. All are password prompts, format-validated (xoxb-/xapp- prefixes, hex secret); the wizard then calls auth.test to confirm Slack accepts the token and resolve your workspace and bot identity. Existing values in .env are offered for reuse.3
Adapter install
The
/add-slack skill copies the adapter from the channels branch, installs the pinned package, builds, writes SLACK_BOT_TOKEN plus either SLACK_APP_TOKEN (Socket Mode) or SLACK_SIGNING_SECRET (webhook) to .env (synced to data/env/env), and restarts the service.4
Identify yourself
The wizard asks for your Slack member ID (
U… — in Slack, click your profile picture → Profile → ⋮ → Copy member ID), then calls conversations.open to get a DM channel with you.5
Name the agent and get the welcome DM
The wizard asks for your operator role and an agent name (default
Nano), wires the DM to your first agent group, and sends a welcome message. The DM is delivered outbound via chat.postMessage, so it arrives even before webhooks are configured — but the bot can’t hear your replies yet.6
Finish in Slack
Socket Mode: in your Slack app, go to Socket Mode → toggle Enable Socket Mode on. Keep Event Subscriptions enabled with the bot events below — under Socket Mode no Request URL is required. That’s it; just DM the bot.Webhook mode: make port 3000 publicly reachable (ngrok, Cloudflare Tunnel, or a reverse proxy), then:
- Event Subscriptions → enable, set the Request URL to
https://<your-public-host>/webhook/slack(Slack sends a verification challenge that must pass) - Interactivity & Shortcuts → enable, same Request URL
- Reinstall the app when Slack prompts you to apply the new settings
message.channels, message.groups, message.im, and app_mention./manage-channels. Channels are identified as slack:<channelId> (right-click the channel name → View channel details — the ID starts with C and sits at the bottom); DMs as slack:<dmId> (starts with D). Add the bot to a channel before wiring it.
Platform notes
- Event delivery — in Socket Mode the bot holds an outbound WebSocket to Slack, so nothing inbound needs to be reachable. In webhook mode the bridge registers Slack on the shared webhook server (port 3000, configurable via
WEBHOOK_PORT), routes/webhook/slackto the adapter, and authenticates requests with your signing secret — the public URL must stay reachable, or the bot silently stops hearing messages if your tunnel dies. - Threads — the adapter sets
supportsThreads: true, so in group channels the router forcesper-threadsessions: each Slack thread gets its own agent session (unless the wiring usesagent-shared, which keeps one session across all of an agent’s messaging groups). DMs collapse sub-threads into one session. See the entity model. - Mentions and engagement — @mentioning the bot in an unwired channel reaches the router as a platform-confirmed mention (the
app_mentionevent); in mention-sticky wirings the bot then sticks to that thread (plain mention wirings respond per mention without subscribing). DMs are always treated as addressed to the bot. - Interactive questions — when an agent asks a multiple-choice question, it renders as a card with buttons. Clicks arrive over the same channel as events — the socket in Socket Mode, the
/webhook/slackroute (via Interactivity & Shortcuts) in webhook mode — and the card updates in place to show the selection. If buttons do nothing in webhook mode, Interactivity isn’t configured. - Attachments and reactions — file uploads are downloaded and passed to the agent as data (
files:read), and the agent can react to messages (reactions:write). - Formatting — Slack uses mrkdwn, not standard Markdown (
*bold*not**bold**,<url|text>links, no headings). Theslack-formattingcontainer skill is mounted into agent containers with a full mrkdwn reference. - No outbound chunking — the adapter doesn’t set the bridge’s
maxTextLength, so long replies are posted as a single message. Slack’s message limit is high enough that this rarely matters.
Troubleshooting
- “Slack didn’t accept that token” —
auth.testrejected it (invalid_authortoken_revoked). Copy the token again from OAuth & Permissions and retry setup. “Couldn’t reach Slack” instead means a network problem. - Welcome DM arrived but the bot never replies — outbound works regardless; inbound depends on your mode. In Socket Mode, confirm
SLACK_APP_TOKENis set and Enable Socket Mode is toggled on in the app. In webhook mode, check that your public URL is up, Event Subscriptions is enabled with a verified Request URL, and the bot events are subscribed (URL verification fails if the signing secret in.envdoesn’t match the app). missing_scopewhen opening the DM — your app lacksim:write. Add it under OAuth & Permissions, reinstall the app to the workspace, then retry setup.- Webhook returns 404
Unknown adapter: slack— the adapter never registered, usually becauseSLACK_BOT_TOKENis missing from the environment the service reads (the factory returnsnullwithout it). Verify.envanddata/env/env, then restart the service.