Skip to main content
The Slack interface lets you deploy agents, teams, or workflows as interactive Slack bots.

Setup

Follow the Slack deploy guide to create a Slack App and configure OAuth scopes, event subscriptions, and App Home.
Install the Slack dependencies: uv pip install 'agno[slack]'
Required configuration:
  • SLACK_TOKEN (Bot User OAuth Token)
  • SLACK_SIGNING_SECRET (App Signing Secret)
  • Webhook URL set to {prefix}/events (use ngrok for local development)
  • Agents & AI Apps enabled under App Home in your Slack App settings (required for streaming UI)

Example Usage

basic.py
from agno.agent import Agent
from agno.db.sqlite import SqliteDb
from agno.models.openai import OpenAIChat
from agno.os.app import AgentOS
from agno.os.interfaces.slack import Slack

agent_db = SqliteDb(session_table="agent_sessions", db_file="tmp/persistent_memory.db")

basic_agent = Agent(
    name="Basic Agent",
    model=OpenAIChat(id="gpt-4o"),
    db=agent_db,
    add_history_to_context=True,
    num_history_runs=3,
    add_datetime_to_context=True,
)

agent_os = AgentOS(
    agents=[basic_agent],
    interfaces=[Slack(agent=basic_agent)],
)
app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="basic:app", reload=True)

Sessions

Each Slack thread is a separate conversation. When running multiple bots on the same server, session IDs include the agent name to keep them separate.
Session format: {entity_id}:{thread_ts}. For example, an agent named “Basic Agent” produces session IDs like Basic Agent:1719000000.000100.
When a database is configured on the agent or team, conversation history persists across server restarts. Without a database, conversations reset when the server restarts.

Threads and Channels

How the bot responds depends on reply_to_mentions_only:
ValueBehavior
True (default)Responds to @mentions in channels and all direct messages. Ignores unprompted channel messages.
FalseResponds to all messages in channels where it’s a member. The app_mention event is skipped in channels to avoid duplicate responses.
All responses are sent as thread replies to the original message, keeping channel conversations organized.

Files and Media

Users can send files to the bot, and agents can upload files back. Use SlackTools for file operations:
from agno.tools.slack import SlackTools

agent = Agent(
    tools=[SlackTools(enable_upload_file=True, enable_download_file=True)],
)
See the file analyst example for a complete file processing agent.

SlackTools

SlackTools lets your agents interact with Slack: send messages, search history, and manage files. It works separately from the Slack interface.
from agno.tools.slack import SlackTools

agent = Agent(
    tools=[SlackTools(all=True)],
)
search_messages supports Slack search modifiers: from:@user, in:#channel, has:link, before:2024-01-01, after:2024-01-01. Combine them to narrow results.
search_messages requires a user token, not a bot token. Using a bot token returns not_allowed_token_type. See the Slack API docs for details.
For parameters and methods, see the SlackTools reference.

Multi-Instance

Run multiple bots on the same server with different prefix values:
agent_os = AgentOS(
    agents=[research_bot, analyst_bot],
    interfaces=[
        Slack(agent=research_bot, prefix="/research", token=RESEARCH_TOKEN, signing_secret=RESEARCH_SECRET),
        Slack(agent=analyst_bot, prefix="/analyst", token=ANALYST_TOKEN, signing_secret=ANALYST_SECRET),
    ],
)
Each instance gets its own route prefix, session namespace, and Slack app credentials.
Each Slack App can only have one Request URL, so multi-instance setups require separate Slack Apps (one per bot).

User Identity

Enable with resolve_user_identity=True to pass email-based user IDs to your agent instead of Slack user IDs like U0123ABC.
The bot looks up each user’s profile:
  • Canonical user ID: The user’s email address (falls back to Slack user ID if email is unavailable)
  • Display name: Resolved via fallback chain: display_namereal_nameusername
Both values are passed to the agent in metadata:
{
    "user_name": "Jane Doe",
    "user_email": "jane@company.com"
}
Agents that use MemoryManager benefit from this. The same person gets the same memory whether they message via Slack, WhatsApp, or Telegram.

Security

Every incoming event is verified using HMAC-SHA256 signature verification:
  1. The X-Slack-Request-Timestamp and X-Slack-Signature headers are extracted
  2. Events older than 5 minutes are rejected (replay attack prevention)
  3. A signature is computed: HMAC-SHA256(signing_secret, "v0:{timestamp}:{body}")
  4. The computed signature is compared using constant-time comparison (hmac.compare_digest)
If SLACK_SIGNING_SECRET is not set, the server returns a 500 error. Always configure the signing secret before deploying.

Troubleshooting

Cause: Server not running or event subscription not configured.Fix: Check that the server is running, ngrok is active, and the Request URL in your Slack App settings matches your tunnel URL (e.g., https://your-tunnel.ngrok.io/slack/events).
Cause: Invalid signing secret.Fix: Verify SLACK_SIGNING_SECRET matches the value under Basic Information > App Credentials in your Slack App settings. The signing secret is different from the bot token.
Cause: reply_to_mentions_only=True (default).Fix: Mention the bot with @YourAppName or set reply_to_mentions_only=False to respond to all channel messages.
Cause: Slack events missing bot_id or misidentified bot user.Fix: The interface filters these automatically. If it still happens, verify your Slack app’s bot user has a bot_id in events. Reinstalling the app usually resolves this.
Cause: App not configured for “Agents & AI Apps”.Fix: In your Slack App settings, go to App Home and enable the Agents & AI Apps feature. This is required for task cards, streaming text, and suggested prompts.
Cause: Missing environment variable.Fix: Export SLACK_TOKEN with your Bot User OAuth Token before running the app. Find this under OAuth & Permissions in your Slack App settings.
Cause: macOS system Python missing root certificates.Fix: Set the SSL_CERT_FILE environment variable:
export SSL_CERT_FILE=$(python3 -c "import certifi; print(certifi.where())")
Or pass a custom ssl context to the Slack interface.
Cause: Message exceeds Slack’s 40K character limit, or recipient_user_id mismatch in streaming.Fix: Stream rotation handles the character limit automatically. If you see blank bubbles, this is a known edge case with Slack’s streaming API when the recipient user ID doesn’t match the human user. Verify your Slack App configuration.

Developer Resources

Interface Reference

All parameters, endpoints, and event handling details.

Deploy Guide

Create a Slack App, configure OAuth, and deploy step by step.

SlackTools Reference

Toolkit parameters and methods for messaging, search, and files.

Usage Examples

14 examples: agents, teams, workflows, streaming, multimodal, and more.