Slack

Search Slack conversations, read threads, and post messages.

Two tools: query_slack for searching and reading, update_slack for posting messages.

Complete Setup before running this example. Search needs a user token in addition to the bot token. Save as slack_context.py and run python slack_context.py:

slack_context.py
import asyncio

from agno.agent import Agent
from agno.context.slack import SlackContextProvider
from agno.models.openai import OpenAIResponses

async def main():
    slack = SlackContextProvider(write=False, model=OpenAIResponses(id="gpt-5.4-mini"))
    agent = Agent(
        model=OpenAIResponses(id="gpt-5.4"),
        tools=slack.get_tools(),
        instructions=slack.instructions(),
    )
    await agent.aprint_response("What did the team discuss about the auth migration?")

if __name__ == "__main__":
    asyncio.run(main())

The agent can call query_slack; its sub-agent searches and reads relevant threads. This example exposes no posting tool.

When to use this vs SlackTools

Use SlackContextProvider when...Use SlackTools directly when...
Slack is one of several context sourcesSlack is the primary task surface
You want a small source-level tool surfaceYou need fine control over individual API calls
The agent should ask questions, not orchestrate API callsYou're building a Slack-specific agent

Setup

In a virtual environment, install the SDKs and configure your Slack app tokens:

uv pip install -U agno openai slack-sdk aiohttp
export OPENAI_API_KEY="your-openai-api-key"
export SLACK_USER_TOKEN=xoxp-...
export SLACK_BOT_TOKEN=xoxb-...

Or pass directly: SlackContextProvider(token="xoxb-...").

Install the Slack app in your workspace with the scopes needed for search and channel/thread reads. Invite it to private channels it must read. With only a bot token, ask about a specific accessible channel or thread; full-text search is unavailable.

See SlackTools for OAuth scope requirements.

Example queries

Queries that work well give the provider a topic to search and context to narrow results:

QueryWhy it works
"What did the team decide about billing migration?"Topic-driven search with synthesis
"Summarize the thread where Alex discussed OAuth scopes"Combines search + thread reading
"What open questions came up in #launch this week?"Channel + time constraints
"Post a short update to #support saying the issue is resolved"Clear channel + action

Queries that are too vague:

Less effectiveBetter
"Search Slack""Search for recent discussion about webhook retries"
"What happened?""What happened in #incidents about the API outage?"
"Post it""Post this summary to #engineering"

Configuration

ParameterTypeDefaultDescription
idstr"slack"Changes tool names to query_<id> and update_<id>.
modelModelNoneModel for the sub-agents. Defaults to Agno's default model.
readboolTrueExpose query_slack.
writeboolTrueExpose update_slack.
enable_media_toolsboolFalseEnables download_file for read tools and upload_file for write tools.
modeContextModedefaultdefault exposes both tools. tools exposes read-only SlackTools.

Read/write modes

Control what the agent can do:

# Research agent: can search but not post
slack = SlackContextProvider(write=False)

# Notification agent: can post but not search
slack = SlackContextProvider(read=False)

Use write=False for research, triage, audit, and eval agents. The read sub-agent physically cannot post because send_message isn't in its toolkit.

Multi-provider example

After completing Google Drive setup too, replace the body of main() with this composition fragment. Add the imports at module scope:

from agno.context.slack import SlackContextProvider
from agno.context.gdrive import GoogleDriveContextProvider

slack = SlackContextProvider(write=False)
drive = GoogleDriveContextProvider()

agent = Agent(
    model=OpenAIResponses(id="gpt-5.4"),
    tools=[*slack.get_tools(), *drive.get_tools()],
    instructions="Use Slack for team discussion, Drive for docs. Note when they disagree.",
)

await agent.aprint_response("What's the current auth spec and did engineering raise concerns?")

The agent sees 2 tools (query_slack, query_gdrive) on the calling agent.

Tips

  • Token naming: SLACK_BOT_TOKEN is preferred; SLACK_TOKEN is a fallback.
  • Search: search_messages needs a user token. Set SLACK_USER_TOKEN or pass user_token=. With only a bot token, the read sub-agent uses channel history and threads.
  • Private channels: The bot must be invited to access private channel history.
  • Thread context: Ask for "the thread" or "the decision" to read replies rather than only the parent. The current get_thread call defaults to at most 20 messages and does not paginate.
  • Channel names: Natural names like #general work. The sub-agent resolves them to IDs.
  • Write clarity: "Post this to #team" is safer than vague "send it."

Resources