CopilotKit channels
The same Mastra agent that powers your in-app copilot can also run as a bot in messaging platforms. CopilotKit's Channels SDK connects your agent to Slack and other messaging platforms, with threads, tool calls, rich interactive messages, and human-in-the-loop approvals handled natively in the channel.
Full platform setup lives in the CopilotKit Channels documentation. This page shows how Channels fit together with a Mastra agent.
How it fits togetherDirect link to How it fits together
Your Mastra agent stays where it's deployed, exposed over AG-UI through registerCopilotKit() (see CopilotKit overview). A channel is a separate long-running process built with @copilotkit/channels: you attach one or more platform adapters and point the channel at your agent. createChannel takes an array of adapters, so a single process can serve several platforms at once.
Install the SDK (batteries-included, every adapter):
- npm
- pnpm
- Yarn
- Bun
npm install @copilotkit/channels
pnpm add @copilotkit/channels
yarn add @copilotkit/channels
bun add @copilotkit/channels
import { createChannel, Message, Section } from '@copilotkit/channels'
import { slack } from '@copilotkit/channels/slack'
import { mastraAgent } from './agent' // your AG-UI Mastra agent
const channel = createChannel({
// Point the channel at your Mastra agent (an AbstractAgent, or a per-thread factory).
agent: mastraAgent,
adapters: [
slack({
botToken: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
}),
],
})
channel.onMention(async ({ thread }) => {
await thread.runAgent()
})
await channel.start()
The agent receives ordinary AG-UI input and emits ordinary AG-UI events; the platform mechanics stay behind the adapter, so the same Mastra agent runs unchanged across every channel. Rich messages are written as JSX and rendered to each platform's native format (Block Kit on Slack, for example), so an interactive card degrades gracefully where a platform has no equivalent.
SlackDirect link to Slack
The Slack quickstart takes you from zero to a bot you can @-mention in a channel, then adds an interactive button card. Slack runs over Socket Mode, which opens an outbound WebSocket to Slack, so no public URL or tunnel is required during development.
Set the Slack credentials in your environment:
SLACK_BOT_TOKEN: Bot User OAuth token (xoxb-...)SLACK_APP_TOKEN: App-level token with theconnections:writescope (xapp-...)
Other platformsDirect link to Other platforms
The Channels SDK isn't limited to Slack. Other platforms like Microsoft Teams run through the same @copilotkit/channels API: add the matching adapter to the adapters array and the rest of your agent code stays the same. See the CopilotKit Channels documentation for the current platform list and per-platform setup.
Message pipeline and architectureDirect link to Message pipeline and architecture
Managed channels keep a deliberate credential split, which matters when your Mastra agent uses separate model keys and tools:
- You keep the agent logic, model credentials, tools, and the channel process.
- CopilotKit Intelligence holds the platform credentials, message delivery, registration, health, and reconnects.
A turn begins when a user messages the app. Intelligence receives the platform event, and the gateway delivers the turn to your running channel process. Your Mastra agent runs and renders a reply. Intelligence then returns the reply as native platform content. Platform credentials never enter the agent process, and enterprise Intelligence can be self-hosted for data residency.
By default, interactive actions live in memory and reset on restart. Back the channel with a durable action and state store (Redis or Postgres) so buttons and per-thread state survive restarts and span multiple instances.