Skip to main content

Slack Bot Integration

The CAIPE Slack Bot brings AI-powered platform engineering assistance directly into Slack. It connects to the CAIPE supervisor via the A2A protocol, allowing users to interact with the full multi-agent system from any Slack channel or DM.

note

The Slack Bot is a client integration, not an agent. It does not expose an A2A server or MCP tools — it acts as an interface between Slack and the CAIPE supervisor, similar to how the CAIPE Web UI works.

Architecture

Request Flow

  1. User sends a message in Slack (via @mention or channel message)
  2. Bot extracts the message text and thread context
  3. Bot sends the message to the CAIPE supervisor via A2A message/stream
  4. Supervisor orchestrates sub-agents (Jira, GitHub, ArgoCD, etc.)
  5. Bot streams progress updates to Slack in real-time
  6. Final response is posted with feedback buttons

Features

  • Multi-agent per channel — Bind multiple agents to a single channel, each with independent trigger rules
  • Listen modes — Control when agents fire: mention (default for users), message (default for bots), or all
  • Bot message routing — Route messages from other bots (e.g. alerting tools) to specific agents via bot_list
  • Overthink mode — AI silently evaluates whether to respond, filtering out low-confidence answers
  • Escalation workflows — VictorOps on-call pings, user @-mentions, and emoji reactions on "Get help"
  • Conversation continuity — Thread-based context persistence across bot restarts (with MongoDB)
  • Human-in-the-Loop (HITL) — Interactive Slack forms when the agent needs user input
  • Feedback scoring — Thumbs up/down reactions tracked via Langfuse
  • Streaming responses — Real-time progress updates during processing
  • OAuth2 for A2A — Secure bot-to-supervisor communication with client credentials flow

Prerequisites

Create a Slack App

  1. Go to api.slack.com/apps and click Create New App
  2. Choose From scratch, name your app (e.g., "CAIPE"), and select your workspace

Bot Token Scopes

Under OAuth & Permissions > Scopes > Bot Token Scopes, add:

ScopePurpose
app_mentions:readDetect @mentions of the bot
channels:historyRead messages in public channels the bot is in
channels:readView basic channel information
chat:writeSend messages as the bot
chat:write.customizeSend messages with a customized username and avatar
commandsRegister slash commands (future use)
emoji:readView custom emoji in the workspace
groups:historyRead messages in private channels the bot is in
groups:readView basic private channel information
im:historyRead direct messages with the bot
im:readView basic DM information
incoming-webhookPost to specific channels via webhook
mpim:historyRead group DMs the bot is in
reactions:readView emoji reactions on messages
reactions:writeAdd and remove emoji reactions
users:readView people in the workspace
users:read.emailView email addresses of workspace members

Event Subscriptions

Under Event Subscriptions > Subscribe to bot events, add:

EventRequired ScopeDescription
app_mentionapp_mentions:readMessages that @mention the bot
message.channelschannels:historyMessages in public channels
message.groupsgroups:historyMessages in private channels
message.imim:historyDirect messages
message.mpimmpim:historyGroup direct messages
reaction_addedreactions:readEmoji reactions added
reaction_removedreactions:readEmoji reactions removed

Under Socket Mode, toggle it on and generate an App-Level Token with the connections:write scope. This gives you an xapp-... token.

Socket mode is recommended because it:

  • Requires no public URL or firewall rules
  • Uses a persistent WebSocket connection (more reliable)
  • Is simpler to set up for development

Alternatively, you can use HTTP mode with a signing secret (see Connection Modes).

Install the App

Under Install App, click Install to Workspace and authorize. Save the Bot User OAuth Token (xoxb-...).


Configuration

Environment Variables

Required

VariableDescription
CAIPE_URLCAIPE supervisor A2A endpoint
SLACK_INTEGRATION_BOT_TOKENBot User OAuth Token (starts with xoxb-)
SLACK_INTEGRATION_APP_TOKENApp-Level Token for Socket mode (starts with xapp-)

Optional

VariableDefaultDescription
SLACK_INTEGRATION_APP_NAMECAIPEDisplay name used in bot responses
SLACK_INTEGRATION_BOT_MODEsocketConnection mode: socket or http
SLACK_INTEGRATION_SIGNING_SECRETRequired only for HTTP mode
SLACK_INTEGRATION_SILENCE_ENVfalseSuppress environment info in bot responses
SLACK_INTEGRATION_BOT_CONFIGYAML channel config (file path or inline YAML; see Channel Config)
SLACK_INTEGRATION_DEFAULT_AGENT_IDFallback agent for channels with no agent bindings
SLACK_INTEGRATION_DM_AGENT_IDAgent used for DM conversations (falls back to default)
SLACK_INTEGRATION_VICTOROPS_AGENT_IDAgent used for VictorOps on-call lookups during escalation
MONGODB_URIMongoDB connection string for session persistence
MONGODB_DATABASEcaipeMongoDB database name
CAIPE_CONNECT_RETRIES10Max connection attempts to supervisor on startup
CAIPE_CONNECT_RETRY_DELAY6Seconds between connection retries

Langfuse Feedback Scoring

VariableDefaultDescription
SLACK_INTEGRATION_LANGFUSE_ENABLEDfalseEnable feedback tracking via Langfuse
LANGFUSE_PUBLIC_KEYLangfuse project public key
LANGFUSE_SECRET_KEYLangfuse project secret key
LANGFUSE_HOSTLangfuse server URL

OAuth2 Authentication (Bot → Supervisor)

VariableDefaultDescription
SLACK_INTEGRATION_ENABLE_AUTHfalseEnable OAuth2 for A2A requests
SLACK_INTEGRATION_AUTH_TOKEN_URLOAuth2 token endpoint
SLACK_INTEGRATION_AUTH_CLIENT_IDOAuth2 client ID
SLACK_INTEGRATION_AUTH_CLIENT_SECRETOAuth2 client secret (store in K8s Secret)
SLACK_INTEGRATION_AUTH_SCOPEOAuth2 scope (optional)
SLACK_INTEGRATION_AUTH_AUDIENCEOAuth2 audience (optional)

Channel Configuration

Per-channel behavior is controlled via SLACK_INTEGRATION_BOT_CONFIG, which accepts a file path or inline YAML string. Each channel maps to a list of agent bindings that control who triggers which agent.

C012345678:
name: "#platform-eng"
agents:
- agent_id: "my-agent"
users:
enabled: true
listen: "mention" # "mention" (default) | "message" | "all"
overthink:
enabled: false
bots:
enabled: true
listen: "message" # "message" (default) | "mention" | "all"
bot_list: ["AlertBot"] # null = all bots
escalation:
victorops:
enabled: true
team: "platform"
users: ["U_ONCALL1"]
emoji: { enabled: true, name: "eyes" }
delete_admins: ["U_ADMIN1"]

Listen Modes

Each agent binding has independent listen settings for users and bots:

ModeFires onDefault for
mention@bot mentions onlyusers
messageChannel messages (non-mention)bots
allBoth mentions and messages

Multiple agents can match the same message — each fires independently.

Agent Binding Fields

FieldTypeDefaultDescription
agent_idstringrequiredAgent to route messages to
users.enabledbooltrueRespond to human messages
users.listenstringrequired when enabledWhen to fire for users: "mention", "message", or "all"
users.overthink.enabledboolfalseFilter low-confidence responses (see below)
users.user_listlistnullAllowlist of Slack user IDs (null = all users)
bots.enabledbooltrueRespond to bot messages
bots.listenstringrequired when enabledWhen to fire for bots: "mention", "message", or "all"
bots.bot_listlistnullAllowlist of bot display names (null = all bots)
escalation.victoropsobject{}VictorOps on-call lookup (requires SLACK_INTEGRATION_VICTOROPS_AGENT_ID)
escalation.userslist[]Slack user IDs to @-mention on escalation
escalation.emojiobject{}Emoji reaction to add on escalation
escalation.delete_adminslist[]Users allowed to delete bot messages

Overthink Mode

When overthink.enabled: true, the bot silently evaluates each message before responding:

  1. The AI processes the message with a confidence-assessment prompt
  2. If the response contains DEFER or LOW_CONFIDENCE, the bot silently skips
  3. Otherwise the bot posts the response normally
  4. If the user later @mentions the bot in the same thread, it detects the earlier skip and responds with context

Useful for busy channels where the bot should only speak when it has something genuinely helpful to say.

Connection Modes

ModeToken RequiredUse Case
Socket (default)SLACK_INTEGRATION_APP_TOKEN (xapp-...)Recommended. No public URL needed. Persistent WebSocket connection.
HTTPSLACK_INTEGRATION_SIGNING_SECRETRequires a public URL. Bot listens on port 3000 for incoming webhooks.

Deployment

Docker Compose

The Slack bot is available as a Docker Compose profile:

# Start with the slack-bot profile
docker compose -f docker-compose.dev.yaml --profile slack-bot up

# Or combine with other profiles
docker compose -f docker-compose.dev.yaml --profile slack-bot --profile caipe-ui-with-mongodb up

Add the following to your .env:

# Required
SLACK_INTEGRATION_BOT_TOKEN=xoxb-your-bot-token
SLACK_INTEGRATION_APP_TOKEN=xapp-your-app-token
SLACK_INTEGRATION_BOT_MODE=socket
SLACK_INTEGRATION_DEFAULT_AGENT_ID=my-agent

# Channel configuration (file path or inline YAML)
SLACK_INTEGRATION_BOT_CONFIG='
C012345678:
name: "#your-channel"
agents:
- agent_id: "my-agent"
users: { enabled: true, listen: "mention" }
'

Helm Chart

The Slack bot ships as a subchart under charts/slack-bot/. It is enabled via the parent chart:

# charts/ai-platform-engineering/values.yaml
tags:
slack-bot: true

Helm Values

# charts/slack-bot/values.yaml

replicaCount: 1

image:
repository: ghcr.io/cnoe-io/caipe-slack-bot
tag: "" # Defaults to Chart.appVersion
pullPolicy: Always

# Flat env var map → ConfigMap → envFrom
config:
APP_NAME: "CAIPE"
SLACK_BOT_MODE: "socket"
CAIPE_API_URL: "http://ai-platform-engineering-caipe-ui:3000"
SLACK_INTEGRATION_SILENCE_ENV: "false"
# SLACK_INTEGRATION_DEFAULT_AGENT_ID: "my-agent"
# SLACK_INTEGRATION_DM_AGENT_ID: "dm-agent"
# SLACK_INTEGRATION_VICTOROPS_AGENT_ID: "victorops-agent"
# MONGODB_URI: "mongodb://admin:changeme@mongodb:27017"
# MONGODB_DATABASE: "caipe"

# Pre-existing K8s Secret containing Slack tokens
existingSecret: "slack-bot-secrets"

# Per-channel agent bindings (serialized as YAML into a ConfigMap)
botConfig: {}
# C012345678:
# name: "#my-channel"
# agents:
# - agent_id: "my-agent"
# users: { enabled: true, listen: "mention" }
# bots: { enabled: false }

Authentication

Bot → Supervisor (OAuth2 Client Credentials)

When auth.enabled: true, the bot obtains a Bearer token using the OAuth2 client credentials flow and injects it into all A2A requests to the supervisor.

Bot                          IDP                         Supervisor
| | |
|--- POST /oauth2/token ---->| |
| client_id + secret | |
|<--- access_token ----------| |
| | |
|--- A2A message/stream ---->| |
| Authorization: Bearer |--------------------------->|
| | |

This works with any OIDC-compliant provider (Okta, Keycloak, Auth0, Azure AD). Tokens are cached and automatically refreshed before expiry.

Configuration:

# Helm values
auth:
enabled: true
tokenUrl: "https://your-idp.example.com/oauth2/v1/token"
clientId: "slack-bot-client"
scope: "api://caipe" # Optional
audience: "caipe-supervisor" # Optional

The clientSecret must be stored in the Kubernetes Secret referenced by slack.tokenSecretRef.

Supervisor → Bot

The bot is a client only — it does not expose any HTTP endpoints (in Socket mode). There is no inbound authentication to configure.


Session Persistence

The bot automatically selects a session backend:

BackendWhen UsedPersistence
MongoDBMONGODB_URI is setSessions survive restarts. Recommended for production.
In-memoryMONGODB_URI not setSessions lost on restart. Fine for development.

What is Stored

DataCollectionPurpose
Thread → context_idslack_sessionsLinks Slack threads to A2A conversation contexts
Thread → trace_idslack_sessionsLinks threads to Langfuse traces for feedback
Thread → is_skippedslack_sessionsTracks overthink mode skip state
User info cacheslack_usersAvoids Slack API rate limits for user lookups

All data is stored permanently (no TTL), matching the UI's conversation lifecycle. Sessions are only removed when explicitly deleted.


Feedback & Scoring

When Langfuse is enabled, the bot attaches feedback buttons to every response:

  • Thumbs up — Records positive feedback
  • Thumbs down — Opens a refinement menu:
    • Wrong answer — Modal for correction details
    • Too verbose — Request concise response
    • More detail — Request additional search
    • Other — Generic feedback modal

Each feedback event is submitted to Langfuse as a score linked to the conversation trace, enabling quality analytics across channels.


Human-in-the-Loop (HITL)

When the CAIPE supervisor's agents need user input (e.g., confirming a Jira ticket creation, selecting from options), the bot renders interactive Slack forms:

  • Text inputs, dropdowns, multi-selects
  • Action buttons (confirm, cancel, etc.)
  • Form responses are sent back to the supervisor to continue the workflow

This enables workflows like: "Create a Jira ticket for this alert" → bot shows a form with pre-filled fields → user confirms → ticket is created.


Local Development

# Navigate to the slack bot directory
cd ai_platform_engineering/integrations/slack_bot

# Run tests
make test

# Run linting
make lint

# Auto-fix linting issues
make lint-fix

To run the bot locally against a Docker Compose supervisor:

# Start the supervisor and MongoDB
docker compose -f docker-compose.dev.yaml --profile slack-bot up

The bot mounts the source code as a volume in development, so changes to the Python files take effect on restart.