Run your own AI agent inside Slack: it reads a thread, answers, calls your tools, and renders rich results right in the conversation. Think of it as having Claude in your workspace, except open-source and self-hosted: you own the runtime, bring your own model, and wire it to your own tools. No per-seat pricing, no lock-in.
It's built on @copilotkit/channels —
CopilotKit's open SDK for chat-platform agents (Slack first; the same code also runs on
Discord, Telegram, and WhatsApp). Clone it, point it at your model and tools, and you own
the whole stack.
demo-slack-opentag.mp4
Two ways to run it: host it on your own with the open-source SDK below — or skip the ops and sign up for the managed service → coming soon from CopilotKit. The managed service will be part of our Enterprise Intelligence platform. You'll be able to use our cloud-hosting or enterprises can host it on their own infra.
Note: the Intelligence Gateway mode below is part of "host it on your own" — you run that process yourself and bring your own CopilotKit Intelligence project. It's distinct from the fully-hosted managed service above, which is still on the waitlist.
OpenTag's packages are published on npm — a standalone pnpm install in this repo pulls in
everything you need, no monorepo required.
You'll run two processes: the agent backend (pnpm runtime) and the bot. For the bot,
pick one of two modes:
- Intelligence Gateway — recommended.
pnpm channelruns the bot over the CopilotKit Intelligence Realtime Gateway. This process never holds a Slack token — Intelligence owns the Slack edge — so there's less for you to run and secure. You still run this process yourself and bring your own CopilotKit Intelligence project — it's not the fully-hosted managed service described below. - Self-hosted.
pnpm dev(orpnpm start) runs the bot locally and talks to Slack (and Discord/Telegram/WhatsApp) directly with your own platform tokens.
Both modes talk to the same agent backend over AG-UI.
OpenTag is a thin layer on top of a handful of CopilotKit packages. The pnpm install in step 3 installs all of them for you — this is what each one does, so you know what you're running and which ones are optional.
Required — every OpenTag install needs these four:
| Package | Role |
|---|---|
@copilotkit/channels |
The platform-agnostic bot engine — threading, tool calls, the human-in-the-loop gate. |
@copilotkit/runtime |
The AG-UI agent backend that runs your LLM and tools. |
@copilotkit/channels-ui |
Cross-platform JSX for rich messages (Block Kit on Slack, Components V2 on Discord, HTML on Telegram). |
@copilotkit/channels-slack |
The Slack adapter — or swap it for the platform you're targeting (below). |
Optional — add only what you use:
| Package | When you need it |
|---|---|
@copilotkit/channels-discord · -telegram · -whatsapp |
Running on a platform other than Slack — one adapter per platform. |
@copilotkit/channels-intelligence |
Runs the bot over the CopilotKit Intelligence Realtime Gateway instead of holding platform tokens — see app/managed.ts. Required for the recommended pnpm channel (Intelligence Gateway) mode; omit it only if you run self-hosted mode exclusively. |
1. Create a Slack app. At api.slack.com/apps →
From a manifest → paste slack-app-manifest.yaml. Install it,
then grab the Bot User OAuth Token (xoxb-…) and an App-Level Token (xapp-…, with the
connections:write scope) — needed for self-hosted mode, or to register the app with your
CopilotKit Intelligence project for Intelligence mode. Step-by-step in
setup.md.
2. Set your secrets in .env (cp .env.example .env):
OPENAI_API_KEY=sk-... # the TS runtime (runtime.ts) uses OpenAI's Responses API for web search;
# the Python agent/ uses Tavily instead (see "Deep research" below)
# Optional integrations (see setup.md):
LINEAR_API_KEY=lin_api_... # optional — lets the agent file Linear tickets
# Self-hosted mode:
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
# Intelligence Gateway mode — full list in .env.example:
INTELLIGENCE_GATEWAY_WS_URL=wss://...
INTELLIGENCE_API_KEY=cpk-...
INTELLIGENCE_ORG_ID=org_...
INTELLIGENCE_PROJECT_ID=...
INTELLIGENCE_CHANNEL_ID=channel_...3. Run it:
pnpm install
pnpm runtime # the agent backend, on :8200
pnpm channel # recommended — the bot over the Intelligence Gateway
# or
pnpm dev # alternative — the bot, self-hosted4. Talk to it. @mention the bot in any channel thread:
@KiteBot summarize this thread and file it as a bug
That's the whole loop. To wire up Linear, Notion, inline charts, or to run on Discord / Telegram / WhatsApp, see setup.md.
We won't lie to you, though. Setting up hosting for chat agents is not easy. To skip all of that heartache, go join the waitlist for the CopilotKit managed service as part of our Intelligence platform, both cloud-hosted or self-hosted.
OpenTag is deliberately small and hackable:
- Change what it does. The agent's behavior is steered by a single system prompt in
runtime.ts— rewrite it and you have a different agent. - Copy
app/to start your own bot. It's the platform-agnostic bot (tools, components, the human-in-the-loop gate).runtime.tsis the agent backend: one CopilotKitBuiltInAgent(an LLM + optional MCP tools — no Python, no LangGraph), served over AG-UI. - One platform, or all of them.
createBottakes an array of adapters; set the secrets for whichever platform(s) you want and the bot starts an adapter for each.
The full architecture, the file-by-file map, and every integration live in setup.md.
agent/ is an alternative agent backend to runtime.ts — a Python
deepagents (LangGraph) planner with a virtual
filesystem and OPTIONAL Tavily web research, served over AG-UI on :8123. Instead of a single
system-prompted LLM call, it plans with write_todos, reads/writes its own virtual files, and
(when configured) researches the web before synthesizing an answer — while still calling
KiteBot's forwarded generative-UI tools like the TS runtime does.
Only OPENAI_API_KEY is required. TAVILY_API_KEY is optional — without it, chat and UI
generation still work (the agent answers from its own knowledge); with it, live web research
turns on.
To run it:
cd agent && uv sync # requires uv: https://docs.astral.sh/uv/
pnpm agent # cd agent && uv run python main.py — serves over AG-UI on :8123
# (port from PORT/SERVER_PORT env, default 8123)Then point the bot at it instead of runtime.ts by setting in .env:
AGENT_URL=http://localhost:8123/With agent/ in the mix, the local setup is now three pieces: the deep-research agent
(pnpm agent, :8123), the bot (pnpm channel or pnpm dev), and whichever brain
AGENT_URL points at — the Python deep agent above, or the TS runtime.ts (pnpm runtime,
:8200) as before. agent and runtime are alternative brains for the same bot; run one or
the other depending on what AGENT_URL targets.
The whole KiteBot stack deploys to Railway as three services, all built from this one repo and wired together automatically over Railway's private networking:
| Service | What it is | Build |
|---|---|---|
agent |
the Python deep-research backend (agent/) |
nixpacks, uvicorn, /health (root dir agent/) |
notion-mcp |
the Notion MCP sidecar (pnpm notion-mcp) |
Node |
channel |
the KiteBot channel host (pnpm channel) |
Node |
channel reaches agent via AGENT_URL, and agent reaches notion-mcp via NOTION_MCP_URL
— both wired with Railway reference variables in .railway/railway.ts,
so you don't set them by hand.
Deploy via Infrastructure-as-Code (recommended):
pnpm install # installs the `railway` SDK the CLI uses to evaluate .railway/railway.ts
npm i -g @railway/cli # or: brew install railway
railway login
railway init # create a new Railway project (or `railway link` to select an existing one)
railway config apply # from the repo root: provisions agent + notion-mcp + channel from .railway/railway.tsSet the secrets (Railway → each service → Variables). The IaC declares them with
preserve() and never stores values — you fill them in:
agent—OPENAI_API_KEY(required);TAVILY_API_KEY(optional — enables web research);LINEAR_API_KEY(optional). (NOTION_MCP_AUTH_TOKENis not set here — the agent references it fromnotion-mcp, so you set it once, below.)notion-mcp—NOTION_TOKENandNOTION_MCP_AUTH_TOKEN(any strong string; the agent reads the same value via a reference variable). Both are required for this service to start — its launcher exits if either is missing. Don't want Notion? Remove thenotion-mcpservice fromresourcesin.railway/railway.tsand delete the agent'sNOTION_MCP_URL/NOTION_MCP_AUTH_TOKENlines; the agent still runs (chat, UI, and — withTAVILY_API_KEY— web research).channel—INTELLIGENCE_GATEWAY_WS_URL,INTELLIGENCE_API_KEY,INTELLIGENCE_ORG_ID,INTELLIGENCE_PROJECT_ID,INTELLIGENCE_CHANNEL_ID(from your CopilotKit Intelligence project + channel).
The inter-service URLs/ports are wired for you in .railway/railway.ts.
Two values are left unmanaged by the IaC so a UI override survives railway config apply: the
agent's OPENAI_MODEL (defaults to gpt-5.5) and the channel's INTELLIGENCE_CHANNEL_NAME
(defaults to kitebot). Set either in that service's Variables to change it — e.g. set
INTELLIGENCE_CHANNEL_NAME if your Intelligence channel isn't named kitebot.
Applying the config creates the services and their wiring; KiteBot goes live only once the
secrets are set and the channel service connects — that's when your Intelligence dashboard
flips Waiting for runtime → live.
Cold-start note (Notion): the
agentloads its Notion tools once, at startup. On a first cold deploy theagentcan finish booting beforenotion-mcpis accepting connections, in which case Notion research is unavailable for that deployment — the agent logs aWARNINGon its stderr (chat, UI, and Tavily web research still work). If KiteBot can't reach Notion after the first deploy, redeploy theagentservice oncenotion-mcpis up. (A lazy/retrying MCP load would remove this race — tracked as a follow-up.)
"Deploy on Railway" button (optional): to get a literal one-click button, publish this repo as a Railway template from your Railway account, then drop the generated button in:
[](https://railway.com/new/template/<your-template-id>)Self-hosting means you run and scale the runtime, persistence, and inspection tooling yourself. A managed CopilotKit service is on its way. It's the same agent, without the ops: durable threads, persistence, hosted inspection, and agents that improve from feedback (Continuous Learning from Human Feedback).
- Join the waitlist → — be first in when the managed service opens.
- Talk to an engineer → — building something real on this? We'd love to help you ship it.
The CopilotKit Slack quickstart is the canonical guide to building a Slack agent — read it alongside this starter. Detailed setup and configuration lives in setup.md.
MIT — see LICENSE.