Creating a Chat Instance
Initialize the Chat class with adapters, state, and configuration options.
The Chat class is the main entry point for your bot. It coordinates adapters, routes events to your handlers, and manages thread state.
Basic setup
import { Chat } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createRedisState } from "@chat-adapter/state-redis";
const bot = new Chat({
userName: "mybot",
adapters: {
slack: createSlackAdapter(),
},
state: createRedisState(),
});
bot.onNewMention(async (thread) => {
await thread.subscribe();
await thread.post("Hello! I'm listening to this thread.");
});This example uses Redis. Chat SDK also supports PostgreSQL and ioredis as production state adapters. See State Adapters for all options.
Each adapter factory auto-detects credentials from environment variables (SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET, REDIS_URL, etc.), so you can get started with zero config. Pass explicit values to override.
Multiple adapters
Register multiple adapters to deploy your bot across platforms simultaneously:
import { Chat } from "chat";
import { createSlackAdapter } from "@chat-adapter/slack";
import { createTeamsAdapter } from "@chat-adapter/teams";
import { createDiscordAdapter } from "@chat-adapter/discord";
import { createRedisState } from "@chat-adapter/state-redis";
const bot = new Chat({
userName: "mybot",
adapters: {
slack: createSlackAdapter(),
teams: createTeamsAdapter(),
discord: createDiscordAdapter(),
},
state: createRedisState(),
});Your event handlers work identically across all registered adapters — the SDK normalizes messages, threads, and reactions into a consistent format.
Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
userName | string | required | Default bot username across all adapters |
adapters | Record<string, Adapter> | required | Map of adapter name to adapter instance |
state | StateAdapter | required | State adapter for subscriptions and locking |
logger | Logger | LogLevel | "info" | Logger instance or log level ("debug", "info", "warn", "error", "silent") |
dedupeTtlMs | number | 300000 | TTL in ms for message deduplication (5 minutes) |
streamingUpdateIntervalMs | number | 500 | Update interval in ms for post+edit streaming |
fallbackStreamingPlaceholderText | string | null | "..." | Placeholder text while streaming starts. Set to null to skip |
onLockConflict | 'drop' | 'force' | (threadId, message) => 'drop' | 'force' | "drop" | Behavior when a thread lock is already held. 'force' releases the existing lock and re-acquires it, enabling interrupt/steerability for long-running handlers |
Accessing adapters
Use getAdapter to access platform-specific APIs when you need functionality beyond the unified interface:
import type { SlackAdapter } from "@chat-adapter/slack";
const slack = bot.getAdapter("slack") as SlackAdapter;
await slack.setSuggestedPrompts(channelId, threadTs, [
{ title: "Get started", message: "What can you help me with?" },
]);Webhook routing
The webhooks property provides type-safe handlers for each registered adapter. Wire these up to your HTTP framework's routes:
import { bot } from "@/lib/bot";
export const POST = bot.webhooks.slack;import { bot } from "@/lib/bot";
export const POST = bot.webhooks.teams;Lifecycle
The Chat instance initializes lazily on the first webhook. You can also initialize manually:
await bot.initialize();For graceful shutdown (e.g. in serverless teardown), call shutdown:
await bot.shutdown();Singleton pattern
Register a singleton when you need to access the Chat instance from multiple files:
const bot = new Chat({ /* ...config */ }).registerSingleton();
export default bot;import { Chat } from "chat";
const bot = Chat.getSingleton();Direct messaging
Open a DM thread with a user by passing their platform user ID or an Author object:
const dm = await bot.openDM("slack:U123ABC");
await dm.post("Hey! Just wanted to follow up on your request.");Channel access
Get a channel directly by its ID:
const channel = bot.channel("slack:C123ABC");
await channel.post("Announcement: deploy complete!");