From vercel
Provides expert guidance on Vercel AI SDK's Chat SDK for building multi-platform chatbots—Slack, Telegram, Discord, Teams, Google Chat, GitHub, Linear—with one codebase. Covers Chat class, adapters, threads, messages, cards, modals, streaming, state, webhooks.
npx claudepluginhub vercel/vercel-plugin --plugin vercel-pluginThis skill uses the workspace's default tool permissions.
Unified TypeScript SDK for building chat bots across Slack, Teams, Google Chat, Discord, Telegram, GitHub, Linear, and WhatsApp. Write bot logic once, deploy everywhere.
Implements production Next.js web chatbots with AI SDK 6 + ai-elements, including HITL tool approval, PostgreSQL/Drizzle persistence, GDPR consent, SQL search, per-tool UI, popup embedding, feedback, and evals.
Builds Slack apps using Bolt framework in Python, JavaScript, and Java. Covers Block Kit UIs, interactive components, slash commands, event handling, OAuth, and Workflow Builder integration.
Guides setup of messaging channels (WhatsApp, Telegram, Discord, iMessage, Slack) for external access to Claude Code agents via plugin installs. Shows exact commands, prerequisites, and relaunch steps.
Share bugs, ideas, or general feedback.
Unified TypeScript SDK for building chat bots across Slack, Teams, Google Chat, Discord, Telegram, GitHub, Linear, and WhatsApp. Write bot logic once, deploy everywhere.
When Chat SDK is installed in a user project, inspect the published files that ship in node_modules:
node_modules/chat/docs/ # bundled docs
node_modules/chat/dist/index.d.ts # core API types
node_modules/chat/dist/jsx-runtime.d.ts # JSX runtime types
node_modules/chat/docs/contributing/ # adapter-authoring docs
node_modules/chat/docs/guides/ # framework/platform guides
If one of the paths below does not exist, that package is not installed in the project yet.
Read these before writing code:
node_modules/chat/docs/getting-started.mdx — install and setupnode_modules/chat/docs/usage.mdx — Chat config and lifecyclenode_modules/chat/docs/handling-events.mdx — event routing and handlersnode_modules/chat/docs/threads-messages-channels.mdx — thread/channel/message modelnode_modules/chat/docs/posting-messages.mdx — post, edit, delete, schedulenode_modules/chat/docs/streaming.mdx — AI SDK integration and streaming semanticsnode_modules/chat/docs/cards.mdx — JSX cardsnode_modules/chat/docs/actions.mdx — button/select interactionsnode_modules/chat/docs/modals.mdx — modal submit/close flowsnode_modules/chat/docs/slash-commands.mdx — slash command routingnode_modules/chat/docs/direct-messages.mdx — DM behavior and openDM()node_modules/chat/docs/files.mdx — attachments/uploadsnode_modules/chat/docs/state.mdx — persistence, locking, dedupenode_modules/chat/docs/adapters.mdx — cross-platform feature matrixnode_modules/chat/docs/api/chat.mdx — exact Chat APInode_modules/chat/docs/api/thread.mdx — exact Thread APInode_modules/chat/docs/api/message.mdx — exact Message APInode_modules/chat/docs/api/modals.mdx — modal element and event detailsFor the specific adapter or state package you are using, inspect that installed package's dist/index.d.ts export surface in node_modules.
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(),
dedupeTtlMs: 600_000,
});
bot.onNewMention(async (thread) => {
await thread.subscribe();
await thread.post("Hello! I'm listening to this thread.");
});
bot.onSubscribedMessage(async (thread, message) => {
await thread.post(`You said: ${message.text}`);
});
post(), stream(), subscribe(), setState(), startTyping()text, formatted, attachments, author info, and platform raw| Handler | Trigger |
|---|---|
onNewMention | Bot @-mentioned in an unsubscribed thread |
onDirectMessage | New DM in an unsubscribed DM thread |
onSubscribedMessage | Any message in a subscribed thread |
onNewMessage(regex) | Regex match in an unsubscribed thread |
onReaction(emojis?) | Emoji added or removed |
onAction(actionIds?) | Button clicks and select/radio interactions |
onModalSubmit(callbackId?) | Modal form submitted |
onModalClose(callbackId?) | Modal dismissed/cancelled |
onSlashCommand(commands?) | Slash command invocation |
onAssistantThreadStarted | Slack assistant thread opened |
onAssistantContextChanged | Slack assistant context changed |
onAppHomeOpened | Slack App Home opened |
onMemberJoinedChannel | Slack member joined channel event |
Read node_modules/chat/docs/handling-events.mdx, node_modules/chat/docs/actions.mdx, node_modules/chat/docs/modals.mdx, and node_modules/chat/docs/slash-commands.mdx before wiring handlers. onDirectMessage behavior is documented in node_modules/chat/docs/direct-messages.mdx.
Pass any AsyncIterable<string> to thread.post() or thread.stream(). For AI SDK, prefer result.fullStream over result.textStream when available so step boundaries are preserved.
import { ToolLoopAgent } from "ai";
const agent = new ToolLoopAgent({ model: "anthropic/claude-4.5-sonnet" });
bot.onNewMention(async (thread, message) => {
const result = await agent.stream({ prompt: message.text });
await thread.post(result.fullStream);
});
Key details:
streamingUpdateIntervalMs controls post+edit fallback cadencefallbackStreamingPlaceholderText defaults to "..."; set null to disableStreamChunk support is Slack-only; other adapters ignore non-text chunksSet jsxImportSource: "chat" in tsconfig.json.
Card components:
Card, CardText, Section, Fields, Field, Button, CardLink, LinkButton, Actions, Select, SelectOption, RadioSelect, Table, Image, DividerModal components:
Modal, TextInput, Select, SelectOption, RadioSelectawait thread.post(
<Card title="Order #1234">
<CardText>Your order has been received.</CardText>
<Actions>
<Button id="approve" style="primary">Approve</Button>
<Button id="reject" style="danger">Reject</Button>
</Actions>
</Card>
);
| Platform | Package | Factory |
|---|---|---|
| Slack | @chat-adapter/slack | createSlackAdapter |
| Microsoft Teams | @chat-adapter/teams | createTeamsAdapter |
| Google Chat | @chat-adapter/gchat | createGoogleChatAdapter |
| Discord | @chat-adapter/discord | createDiscordAdapter |
| GitHub | @chat-adapter/github | createGitHubAdapter |
| Linear | @chat-adapter/linear | createLinearAdapter |
| Telegram | @chat-adapter/telegram | createTelegramAdapter |
| WhatsApp Business Cloud | @chat-adapter/whatsapp | createWhatsAppAdapter |
| State backend | Package | Factory |
|---|---|---|
| Redis | @chat-adapter/state-redis | createRedisState |
| ioredis | @chat-adapter/state-ioredis | createIoRedisState |
| PostgreSQL | @chat-adapter/state-pg | createPostgresState |
| Memory | @chat-adapter/state-memory | createMemoryState |
chat-state-cloudflare-do@beeper/chat-adapter-matrixchat-adapter-imessage@bitbasti/chat-adapter-webex@resend/chat-sdk-adapterchat-adapter-baileysRead these published docs first:
node_modules/chat/docs/contributing/building.mdxnode_modules/chat/docs/contributing/testing.mdxnode_modules/chat/docs/contributing/publishing.mdxAlso inspect:
node_modules/chat/dist/index.d.ts — Adapter and related interfacesnode_modules/@chat-adapter/shared/dist/index.d.ts — shared errors and utilitiesdist/index.d.ts files — reference implementations for config and APIsA custom adapter needs request verification, webhook parsing, message/thread/channel operations, ID encoding/decoding, and a format converter. Use BaseFormatConverter from chat and shared utilities from @chat-adapter/shared.
Each registered adapter exposes bot.webhooks.<name>. Wire those directly to your HTTP framework routes. See node_modules/chat/docs/guides/slack-nextjs.mdx and node_modules/chat/docs/guides/discord-nuxt.mdx for framework-specific route patterns.