Slack Integration
Relevant source files
The following files were used as context for generating this wiki page:
The Slack Integration module provides the primary interface for users to interact with Digby. It leverages Slack's Socket Mode for real-time communication, allowing the bot to operate without requiring a public HTTP endpoint. The system manages event routing, message formatting, file transfers, and conversation state across DMs, public channels, and private threads.
The integration is architected into three main layers: a low-level client for API communication, a router for event classification and lifecycle management, and a "surface" implementation that manages the visual presentation of agent progress and responses within Slack.
Sources: CLAUDE.md:12-14, src/main.ts:153-157
Core Components
SlackClient
The SlackClient acts as the low-level wrapper for the @slack/socket-mode and @slack/web-api packages. It handles the lifecycle of the connection, authenticates the bot, and provides retry-resilient methods for interacting with Slack's Web API.
Key responsibilities include:
- Connection Management: Starting Socket Mode and handling auto-reconnection on socket errors.
- Data Lookups: Fetching and caching user and channel metadata.
- Retry Logic: Implementing exponential backoff for rate-limited or transient network failures.
- Thread Tracking: Identifying if a thread was initiated by or mentions the bot to ensure proper routing of replies.
Sources: src/slack/client.ts:50-101, src/slack/client.ts:161-196
SlackRouter
The setupRouter function classifies incoming Slack events into actionable types. It filters out bot-internal messages and manages "busy" states to prevent overlapping agent runs in the same channel.
The router distinguishes between several trigger types:
- App Mentions: Explicit
@digbymentions in channels. - Direct Messages (DMs): All messages sent in 1-on-1 conversations with the bot.
- Thread Replies: Messages in threads where the bot is a participant.
- Always-on Channels: Channels configured via
digby.jsonwhere every message triggers the bot.
Sources: src/slack/router.ts:22-124, src/config.ts:47-49
SlackSurface
The SlackSurface class implements the AgentSurface interface, owning the lifecycle of a single Slack message representing an agent's "run". It manages the transition from a "Thinking" placeholder to streaming progress updates and finally the terminal response.
Sources: src/surface/slack.ts:38-45
Data Flow and Architecture
The following diagram illustrates how a message from a user is received, classified, and processed into an agent run.
The system ensures that only one agent run is active per channel at a time. If a user sends a message while the bot is already thinking, the router responds with a busy message.
Sources: src/slack/router.ts:162-177, src/main.ts:56-72
Event Processing Sequence
The sequence below detailing the interaction between the Slack infrastructure and the agent during a typical request.
Message Formatting and Logic
Slack uses a specific "mrkdwn" format which differs from standard Markdown. The SlackSurface automatically converts standard markdown (like **bold**) to Slack-compatible markers (*bold*).
Truncation and Limits
To comply with Slack's message size limits, the system enforces maximum lengths:
| Parameter | Value | Description |
|---|---|---|
MAX_MESSAGE_LENGTH | 35,000 | Max characters for main responses |
MAX_THREAD_MESSAGE_LENGTH | 20,000 | Max characters for detail/thread messages |
Sources: src/surface/slack.ts:7-19, src/surface/slack.ts:88-91
Run Lifecycle Operations
Every agent run through the SlackSurface must end with exactly one terminal operation:
- resolve(): Finalizes the message and replaces the "streaming" status with the final cost.
- reject(error): Appends an error icon and message to the output.
- suppress(): Deletes the message entirely (used for
[SILENT]responses).
Sources: src/surface/slack.ts:182-212
Configuration
Slack-specific behavior is governed by digby.json (located in the working directory).
| Configuration Path | Type | Default | Description |
|---|---|---|---|
slack.processAllMessageChannels | string[] | [] | List of channel IDs where the bot responds to every message without a mention. |
debugThreading | boolean | false | If enabled, posts thinking/tool steps into a thread under the main response. |
runTimeout | number | 600 | Maximum seconds a run can last before auto-abortion. |
Sources: src/config.ts:4-12, src/config.ts:47-59
Technical Implementation Details
API Retry Logic
The withRetry helper wraps Slack API calls to handle transient errors.
function isRetryable(err: unknown): boolean {
if (!(err instanceof Error)) return false;
const msg = err.message.toLowerCase();
return (
msg.includes("rate_limited") ||
msg.includes("timeout") ||
msg.includes("econnreset") ||
msg.includes("socket hang up")
);
}
Sources: src/slack/client.ts:11-23
Event Data Model
The SlackEvent structure (aliased from BotEvent) serves as the normalized internal representation of a Slack trigger.
| Field | Type | Description |
|---|---|---|
type | "mention" | "dm" | "channel" | The trigger context. |
channel | string | The Slack Channel ID. |
ts | string | The unique timestamp/ID of the triggering message. |
user | string | The ID of the user who sent the message. |
text | string | The message content (cleaned of mentions). |
files | Attachment[] | Metadata for any files attached to the message. |
Sources: src/slack/router.ts:39-48, src/slack/types.ts:1-12
Summary
The Slack Integration provides a robust, state-managed bridge between the Slack workspace and the Pi-Digby agent. By combining real-time event routing via SlackRouter with consistent visual feedback via SlackSurface, it ensures that users have a clear understanding of the bot's status and results, while maintaining high reliability through automated retries and connection management in the SlackClient.