Slack Integration¶
The Slack integration runs as a separate process alongside the agent-server. It listens for events via Slack's Socket Mode (no inbound ports) and routes them to the agent-server's /chat endpoint.
Setup¶
Add to .env:
SLACK_BOT_TOKEN=xoxb-... # Bot token (from OAuth)
SLACK_APP_TOKEN=xapp-... # App-level token (for Socket Mode)
AGENT_API_KEY=same-as-API_KEY # Auth key for the agent-server
AGENT_BASE_URL=http://localhost:8000 # Agent-server URL
SLACK_DEFAULT_BOT=default # Fallback bot when no channel mapping exists
When both Slack tokens are set, dev-server.sh starts the bot automatically. To run standalone:
Slack App Configuration¶
Required Bot token scopes: app_mentions:read, chat:write, channels:history, channels:read, commands, files:read, files:write
Optional (for custom display names per bot): chat:write.customize
Event subscriptions: message.channels, app_mention
Slash commands — register each at api.slack.com/apps → Slash Commands (Socket Mode; Request URL is ignored):
| Command | Description |
|---|---|
/ask <bot-id> <message> |
Route a message to a specific bot. Bot replies in the channel with its display name. /ask alone lists available bots. |
/bot [id] |
Show or switch the default bot for this channel. Session is unchanged. |
/bots |
List all available bots and their IDs. |
/context |
Show the current context window breakdown (chars per role). |
/plan [subcommand] |
View and manage agent plans (see plans documentation). |
/compact |
Force session compaction (summarize + memory write) now. |
Session Model¶
Each Slack channel has one shared session derived deterministically from the channel ID:
This session is shared across all bots operating in that channel. Switching the default bot with /bot keeps the same session and preserves full conversation history.
Child sessions (created via delegate_to_agent) maintain a parent/root link back to the channel session.
Message Routing¶
Each message in a channel is classified as either active or passive:
Active messages — agent runs and replies¶
A message is active when:
- The user @mentions the Slack app (app_mention event), OR
- The channel has require_mention = false (agent responds to all messages)
An app_mention with no text after the mention still runs the agent (so you can ping after passive-only channel activity).
Active messages go through the full agent pipeline: RAG retrieval, tool calls, LLM response. The response is posted to the channel attributed to the responding bot.
Passive messages — stored silently, no reply¶
A message is passive when it arrives without @mentioning the app and require_mention = true (the default). Passive messages are:
- Stored in the channel session as user-role messages with
metadata.passive = true - Not sent to the agent — no LLM call, no response
- Injected as context on the next active turn, as a system block:
[Channel context — ambient messages not directed at the bot] - Included in compaction (if
passive_memory = true) — when the memory/knowledge phase runs, passive messages are visible in the transcript with a[passive]prefix, so the bot can extract relevant facts into long-term knowledge
This lets the bot stay aware of conversations happening around it without interrupting them.
Channel Configuration¶
Configure per-channel behavior at /admin/slack. Each channel can have:
| Setting | Default | Description |
|---|---|---|
| Default Bot | SLACK_DEFAULT_BOT |
The bot that responds to @mentions in this channel. Other bots can be addressed with /ask <bot-id>. |
| Require @mention | true |
When checked, only @mentions trigger the agent. All other messages are stored passively as channel context. When unchecked, the bot replies to every message. |
| Passive memory | true |
When compaction runs, passive channel messages are included in the memory/knowledge phase transcript so the bot can extract channel activity into knowledge. |
The derived session ID for each channel is shown in the channel list (first 8 chars of the UUID).
Config is served at GET /integrations/slack/config (requires X-API-Key header) and cached for 60 seconds by the Slack integration process.
Multi-Bot Channels¶
A channel has one default bot (used for @mentions), but multiple bots can operate in the same channel:
Using /ask:
Routes a message to calculator-bot directly. The bot replies in the channel with its configured display name and icon. The channel's shared session ensures it has full context of prior conversations. /ask with no arguments lists available bots.
Using delegation: The default bot can delegate to other bots internally via delegate_to_agent. The delegated bot's response is posted to the channel attributed to its display name.
Important: In Slack, only one @mentionable user exists per app installation. To have multiple independently @mentionable bots, each needs its own Slack app installation.
Bot Display Names¶
When the Slack app has the chat:write.customize scope, each bot can post with a distinct username and icon:
# In admin → Bots → [bot] → Slack Display
slack_display_name: "Calculator"
slack_icon_emoji: ":abacus:"
These appear as custom usernames on messages posted by that bot, making it visually clear which bot is responding. This is a display-only override — it does not create a separate Slack user.
File Attachments¶
The bot downloads files shared in Slack automatically:
- Text files (plain text, markdown, CSV, JSON, Python, YAML): content is appended to the message
- Images: sent as vision attachments to the LLM
Requires the files:read scope. The files:write scope is needed for the generate_image tool to post generated images back to the channel.