Build a Slack bot powered by Claude using Python Bolt SDK. Mentions, DMs, thread-aware conversation history, slash commands, and streaming message updates — all with working code.
A Slack bot powered by Claude can handle support tickets, answer internal questions, review code snippets, and summarize threads — all within the tools your team already uses. This guide uses Slack Bolt for Python and the Anthropic SDK.
pip install slack-bolt anthropic
Create a Slack App at api.slack.com/apps. Enable:
app_mention and message.imapp_mentions:read, chat:write, im:history, channels:history# .env
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-... # only for Socket Mode
ANTHROPIC_API_KEY=sk-ant-...
import os
import anthropic
from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler
app = App(token=os.environ["SLACK_BOT_TOKEN"])
claude = anthropic.Anthropic()
@app.event("app_mention")
def handle_mention(event, say, client):
# Strip the @BotName mention from the text
text = event["text"]
# Remove <@BOTID> from the beginning
import re
user_message = re.sub(r"<@[A-Z0-9]+>", "", text).strip()
if not user_message:
say("Hi! Ask me anything.")
return
response = claude.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are a helpful Slack assistant. Keep replies concise and use Slack markdown formatting.",
messages=[{"role": "user", "content": user_message}],
)
say(response.content[0].text)
if __name__ == "__main__":
SocketModeHandler(app, os.environ["SLACK_APP_TOKEN"]).start()
@app.event("app_mention")
def handle_mention_with_history(event, say, client):
import re
channel = event["channel"]
thread_ts = event.get("thread_ts", event["ts"])
# Fetch thread history
result = client.conversations_replies(channel=channel, ts=thread_ts, limit=20)
bot_user_id = client.auth_test()["user_id"]
history = []
for msg in result["messages"]:
# Skip bot_message subtypes and system messages
if msg.get("subtype"):
continue
text = re.sub(r"<@[A-Z0-9]+>", "", msg.get("text", "")).strip()
if not text:
continue
role = "assistant" if msg.get("user") == bot_user_id else "user"
history.append({"role": role, "content": text})
# Ensure last message is the current user turn
if not history or history[-1]["role"] != "user":
return
response = claude.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are a helpful Slack assistant. Be concise. Use Slack markdown (*bold*, _italic_, `code`).",
messages=history,
)
say(text=response.content[0].text, thread_ts=thread_ts)
@app.command("/ask")
def handle_ask_command(ack, respond, command):
ack() # acknowledge within 3 seconds
user_question = command["text"].strip()
if not user_question:
respond("Usage: /ask ")
return
respond({"response_type": "in_channel", "text": "Thinking…"})
response = claude.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
system="You are a helpful assistant. Answer concisely.",
messages=[{"role": "user", "content": user_question}],
)
respond(response.content[0].text)
@app.event("message")
def handle_dm(event, say, client):
# Only handle DMs; ignore bot messages
if event.get("channel_type") != "im" or event.get("bot_id"):
return
user_message = event.get("text", "").strip()
if not user_message:
return
# Post a placeholder immediately so the user sees feedback
result = say("_Thinking…_")
placeholder_ts = result["ts"]
channel = event["channel"]
# Get full streamed response
full_reply = ""
with claude.messages.stream(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are a helpful Slack DM assistant. Be concise.",
messages=[{"role": "user", "content": user_message}],
) as stream:
for text in stream.text_stream:
full_reply += text
# Replace placeholder with full response
client.chat_update(channel=channel, ts=placeholder_ts, text=full_reply)
| Approach | Setup time | Customizability | Cost |
|---|---|---|---|
| Claude + Bolt (this guide) | ~30 min | Full — any system prompt, any tool | Claude API usage only |
| Slack AI (built-in) | Minutes | None — fixed features | $10/user/month |
| Zapier/Make automation | ~15 min | Low — template-based | Zapier subscription + Claude |
| OpenAI + Bolt | ~30 min | Full — same pattern | OpenAI API usage |
For cost estimates before deploying your Slack bot, use the Claude API Cost Calculator. For multi-turn conversation patterns, see the chatbot guide.