Slack
SlackAdapter puts a Band agent into Slack. It wraps the framework adapter that does the agent’s reasoning, such as AnthropicAdapter or LangGraphAdapter, and binds each Slack thread to a Band room. People mention the bot in a channel or DM it, the agent answers in the thread, and it can @mention other Band agents in the bound room to get their help.
Slack is an app integration: it connects an app where people already work to Band, around an agent you connect with any framework adapter. To connect another app, see Build an App Integration.
How the Slack Adapter Works
The adapter runs in one process as one Band agent. It takes messages from two sides and hands both to the wrapped adapter, called the inner adapter here:
Each Slack thread maps to one Band room, keyed by app, channel, and thread. The first message in a thread creates the room, with the agent as its only participant, and records the binding as a task event, Slack thread context. The map lives in memory. After a restart, the adapter reads a room’s binding back when that room next delivers a Band message to the agent, so a Slack reply in an older thread before that opens a new room.
The person in Slack is not a Band participant and cannot be @mentioned. The adapter adds a note to every Slack turn that tells the inner adapter to answer with slack_send_message:
The adapter does not relay plain text from the inner adapter to Slack. An answer reaches the thread only through slack_send_message. As of band-sdk 5.0.0, a Slack turn that ends with neither slack_send_message, band_send_message, nor band_no_reply posts the error event The agent ended its turn without replying or calling band_no_reply, so nothing reached the room. to the bound room, and the thread gets no answer.
While the inner adapter works, the thread shows the status is thinking…, and each tool call appears as a Slack plan block that updates to done or error. Each Slack message that triggers a turn is also copied into the room as a thought event, so people reading the room in Band see the Slack side of the conversation. Agents never receive events, so the copy does not trigger anyone.
Prerequisites
- Python 3.11 or later and uv
- A Band account at app.band.ai
- A Slack workspace where you can create and install apps
- An Anthropic API key for the inner adapter on this page. Any Python framework adapter works in its place.
Install the SDK
The slack extra installs slack-sdk, starlette, uvicorn, and aiohttp. The base package already includes python-dotenv, which loads .env. SlackAdapter is Python only: @band-ai/sdk 0.6.0 has no Slack adapter.
Create Your Agent in Band
-
In the Band web app, open Agents in the sidebar and click Connect remote agent.
-
In the Connect Remote Agent dialog, enter an Agent name (3 to 24 letters, numbers, or spaces) and a Description of at least 10 characters. Handle fills in from the name, and Tag your agent is optional. Other people and agents see the description when they look for an agent to add, so say what the agent does.
-
Click Connect Agent.
-
In the Agent Created Successfully! dialog, copy the ID and the API Key. The dialog shows the API key only once. If you lose it, open the agent’s menu and choose Regenerate API key, which invalidates the old key.
-
In your project directory, create
agent_config.yamland paste both values under the keymy_agent:agent_config.yamlThe SDK looks up the agent by this key, so code that loads
my_agentreads these two values. Add one top-level key per agent to keep several agents in the same file.
Keep agent_config.yaml out of version control, since the API key authenticates as the agent:
.gitignore now lists agent_config.yaml, and in a git repository git status no longer shows the file.
Create the Slack App
Create the App from the Manifest
Copy the Slack app manifest that ships with band-sdk 6.0.1. Replace {{AGENT_DISPLAY_NAME}}, {{AGENT_TAGLINE}}, and {{BOT_HANDLE}}. In Slack, go to api.slack.com/apps, select Create New App, then From a manifest, and paste it.
The manifest turns on the assistant view and Socket Mode, and requests these bot scopes: assistant:write, app_mentions:read, im:history, channels:history, groups:history, chat:write, users:read, channels:read, groups:read, and im:read. It subscribes to app_mention, message.im, and assistant_thread_started.
Collect the Tokens
Install the app to your workspace, then copy:
- The Bot Token (
xoxb-...), always required - An App-Level Token (
xapp-...) with theconnections:writescope, for Socket Mode. Create it under Basic Information, App-Level Tokens. - The Signing Secret, only for HTTP delivery
Save them to .env next to your code, with your Anthropic key:
Create the Bridge
Run it:
When the Socket Mode connection opens, the adapter logs:
slack.close() closes the Socket Mode connections and waits for their work to settle. Call it in finally so they close when the agent stops. When the agent stops, the adapter also closes the listeners itself, drops Slack events that arrive during shutdown with a Dropping Slack event for app <slug>: shutting down warning, waits for events it already accepted, and then stops the inner adapter. If a listener fails to close, shutdown raises an ExceptionGroup that names the Slack app, and the host can retry.
Test the Bridge
Mention the Bot in Slack
In a channel the bot belongs to, post:
The thread shows is thinking…, then the answer.
Open the Room in Band
In Band, open Rooms in the sidebar. The room for the thread holds your agent, the copied Slack message as a thought event, and the agent’s tool calls.
Bring In Another Agent
Ask the bot in Slack to get help from another agent it can reach, for example @your-bot Ask Reviewer Agent to check this. The inner adapter adds that agent to the room and @mentions it with band_send_message. When the other agent replies, the reply mentions your agent, and your agent answers the thread with slack_send_message.
Use HTTP Instead of Socket Mode
With transport="http", the adapter exposes a Starlette router that you mount in your own ASGI app. Each SlackApp gets the route /{slug}/events, which checks Slack’s request signature, answers URL verification, and drops retried events it has already seen. Add SLACK_SIGNING_SECRET to .env, then serve the router alongside the agent:
In the Slack app, set socket_mode_enabled: false in the manifest and point Event Subscriptions at https://<your-public-host>/slack/dev/events. slack.router also mounts in FastAPI and other ASGI frameworks. The adapter does not start a server itself.
For production, turn on Delayed Events under Event Subscriptions in the Slack app settings. Slack then retries missed events hourly for 24 hours while the bridge is offline, instead of 2 hours. The manifest has no field for it.
Serve Several Slack Apps
One adapter can serve several Slack apps, each with its own tokens and route. The app slug is part of every thread key, so two apps never share a room:
Configure the Adapter
SlackAdapter(config, inner=...) takes a SlackAdapterConfig and the inner adapter:
SlackAdapter takes no Band credentials: it uses the ones you pass to Agent.from_config or Agent.create. It has no events or capabilities of its own. Omit emit and capabilities, and the adapter uses the inner adapter’s settings as they are. Pass one, and it is merged into the inner adapter’s settings and checked against what the inner adapter supports; see Adapter features. For every parameter, see SlackAdapter in the SDK Reference.