Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4eaf0fd
docs(spec): KiteBot on CopilotKit Intelligence — Phase 1 foundation d…
jerelvelarde Jul 15, 2026
6c6ae0d
docs(plan): KiteBot on Intelligence — Phase 1 implementation plan
jerelvelarde Jul 15, 2026
a45b05d
build: migrate deps @copilotkit/bot* -> @copilotkit/channels* + add c…
jerelvelarde Jul 15, 2026
bebf5dc
chore: drop Redis persistence (demo-restart, docker-compose, env block)
jerelvelarde Jul 15, 2026
c54d209
refactor: rename @copilotkit/bot*->@copilotkit/channels* imports + de…
jerelvelarde Jul 15, 2026
1c18a16
feat: rename bot identity to KiteBot (Slack display name + persona)
jerelvelarde Jul 15, 2026
650b3ac
feat: add Intelligence channel host (createBot + startChannelsOverRea…
jerelvelarde Jul 15, 2026
96984c4
docs: channels rename, lead with Intelligence deploy, drop Redis, Kit…
jerelvelarde Jul 15, 2026
bd4809e
docs: disambiguate self-run Intelligence Gateway mode from the waitli…
jerelvelarde Jul 15, 2026
dce7cfe
fix(cr): address review findings — batch 1 (managed.ts, index.ts, com…
jerelvelarde Jul 15, 2026
b3d4172
fix(cr): address review findings — batch 2 (hitl, showcase, modal, ru…
jerelvelarde Jul 15, 2026
b4b3b86
fix(cr): final review cycle — port validation, docs accuracy, secret …
jerelvelarde Jul 15, 2026
169fd22
docs(spec): KiteBot deep-research agent (Phase 2) — Python deepagents…
jerelvelarde Jul 15, 2026
214adf0
docs(spec): lock Phase 2 model default to gpt-5.5
jerelvelarde Jul 15, 2026
c2dfd1e
docs(plan): KiteBot deep-research agent (Phase 2) implementation plan
jerelvelarde Jul 15, 2026
a044115
docs(plan): make Tavily optional (chat + UI generation require only O…
jerelvelarde Jul 15, 2026
6493978
feat(agent): scaffold Python deepagents deep-research service (AG-UI …
jerelvelarde Jul 15, 2026
f34404c
docs: document the deep-research agent (agent/) — run, env, AGENT_URL
jerelvelarde Jul 15, 2026
d2ad655
fix(agent): run 'pnpm agent' via python main.py so SERVER_HOST/SERVER…
jerelvelarde Jul 15, 2026
d7a0b87
test(agent): pytest for research tool + health/optional-Tavily/openai…
jerelvelarde Jul 15, 2026
4963636
feat(agent): optional Notion/Linear MCP internal research sources (en…
jerelvelarde Jul 15, 2026
e6c564f
test(agent): hermetic MCP env in health tests; doc Tavily as optional…
jerelvelarde Jul 15, 2026
2ba99b0
fix(cr): whole-PR review round 1 — agent deploy/config, render edge c…
jerelvelarde Jul 15, 2026
54c6e9b
fix(cr): review round 2 — regressions + robustness/edge cases
jerelvelarde Jul 15, 2026
ae51e58
fix(cr): review round 3 — error-handling hardening + test robustness
jerelvelarde Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 55 additions & 17 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Set SLACK_*, DISCORD_*, and/or TELEGRAM_BOT_TOKEN — the bot starts an adapter
# for each platform whose secrets are present (any one, or several at once).
# Set SLACK_*, DISCORD_*, TELEGRAM_BOT_TOKEN, and/or WHATSAPP_* — the bot starts
# an adapter for each platform whose secrets are present (any one, or several at once).

# ── Slack credentials (from api.slack.com/apps → your app) ──────────────
# Set both to run on Slack; leave blank to skip Slack.
Expand All @@ -25,27 +25,59 @@ SLACK_APP_TOKEN=xapp-...
# (no public URL or webhook setup needed).
# TELEGRAM_BOT_TOKEN=

# ── Persistence (optional) ──────────────────────────────────────────────
# Optional Redis-backed durable store. Used by `pnpm demo:restart` (and any
# bot that passes `store: { adapter: createRedisStore({ url }) }`). Leave blank
# for the in-memory default. With it set, interactive actions (e.g. an approval
# card's button) survive a bot restart — see `app/demo-restart.tsx`.
# Start a local one with `docker compose up -d`.
# REDIS_URL=redis://localhost:6379

# ── Agent backend (runtime.ts) ──────────────────────────────────────────
# The AG-UI endpoint the bridge POSTs to. Default points at the local
# CopilotKit runtime started by `pnpm runtime`.
# The AG-UI endpoint the bridge POSTs to. REQUIRED — the bridge exits at
# startup if this is unset; there is no code-level fallback. The value below
# is a template pointing at the local CopilotKit runtime started by
# `pnpm runtime`; change it if you deploy the runtime elsewhere.
AGENT_URL=http://localhost:8200/api/copilotkit/agent/triage/run
# Optional auth header forwarded to the agent (for a deployed runtime).
# AGENT_AUTH_HEADER=Bearer ...

# Model for the BuiltInAgent. provider/model — the runtime resolves the
# provider and reads the matching API key below. Defaults to openai/gpt-5.5.
# AGENT_MODEL=anthropic/claude-sonnet-4.5
# ── Intelligence channel mode — app/managed.ts (`pnpm channel`) ──────────
# Runs the SAME bot over the CopilotKit Intelligence Realtime Gateway instead
# of a native adapter — this process holds NO Slack tokens (Intelligence owns
# the Slack edge). The agent brain reuses AGENT_URL / AGENT_AUTH_HEADER above.
# All values come from your CopilotKit Intelligence project + channel setup.
# Gateway runner WebSocket URL (the /runner endpoint).
# INTELLIGENCE_GATEWAY_WS_URL=wss://dev.intelligence.copilotkit.ai/runner
# Project runtime API key (cpk-{projectId}_...), presented as the socket auth token.
# INTELLIGENCE_API_KEY=cpk-...
# Authoritative org/project/channel scope (from the Intelligence dashboard):
# INTELLIGENCE_ORG_ID=org_...
# INTELLIGENCE_PROJECT_ID=123
# INTELLIGENCE_CHANNEL_ID=channel_...
# The registered channel name (lowercase kebab). Defaults to "kitebot".
# INTELLIGENCE_CHANNEL_NAME=kitebot
# Optional stable runtime instance id; auto-generated (rti_...) if unset.
# INTELLIGENCE_RUNTIME_INSTANCE_ID=rti_...

# Model for the BuiltInAgent. The runtime is OpenAI-only (it uses OpenAI's
# Responses API via TanStack AI's `openaiText` adapter, needed for the
# `web_search` provider tool) — there is no multi-provider resolution.
# AGENT_MODEL only accepts an OpenAI model id, optionally prefixed with
# "openai/" (the prefix is stripped); defaults to openai/gpt-5.5.
# AGENT_MODEL=openai/gpt-5.5
OPENAI_API_KEY=sk-...
# ANTHROPIC_API_KEY=sk-ant-...
# GOOGLE_API_KEY=...
# ANTHROPIC_API_KEY / GOOGLE_API_KEY are NOT supported by this runtime today
# (runtime.ts never reads them) — do not set AGENT_MODEL to an anthropic/... or
# google/... value.

# ── Deep-research agent (agent/) — alternative brain to runtime.ts ──────
# A standalone Python (deepagents/LangGraph) service served over AG-UI on
# :8123. To use it instead of the TS runtime above, point the bridge at it:
# AGENT_URL=http://localhost:8123/
# Only OPENAI_API_KEY (above) is required to run it — it still chats and
# generates UI components without Tavily.
# OPTIONAL — web research for the agent/ service. Without it the `research`
# web tool is simply not loaded (chat + UI-component generation still work,
# answering from the model's own knowledge); with it, live web research
# turns on. Get a key at https://tavily.com. This is scoped to agent/, not
# to runtime.ts, which has no research tool.
# TAVILY_API_KEY=tvly-...
# Model used by the agent/ service (its own env, separate from AGENT_MODEL
# above which is read by runtime.ts). Defaults to gpt-5.5.
# OPENAI_MODEL=gpt-5.5

# ── Linear MCP ──────────────────────────────────────────────────────────
# The hosted Linear MCP accepts a raw API key as a bearer token (no OAuth
Expand All @@ -69,6 +101,12 @@ NOTION_TOKEN=ntn_...
NOTION_MCP_AUTH_TOKEN=choose-a-strong-shared-secret
# Override only if the sidecar runs elsewhere; default is the local sidecar.
# NOTION_MCP_URL=http://127.0.0.1:3001/mcp
# Port the `pnpm notion-mcp` sidecar listens on (scripts/start-notion-mcp.ts).
# Must agree with the port in NOTION_MCP_URL above. Defaults to 3001.
# NOTION_MCP_PORT=3001
# Notion-Version header the sidecar sends to the Notion API. Defaults to
# 2022-06-28; override only if you need a newer Notion API version.
# NOTION_VERSION=2022-06-28

# ── WhatsApp Cloud API (optional — omit to run Slack-only) ──────────────
# From your Meta App → WhatsApp → API Setup. Leave WHATSAPP_ACCESS_TOKEN blank
Expand Down
103 changes: 81 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ renders rich results right in the conversation. Think of it as having Claude in
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/bot`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot)** —
It's built on **[`@copilotkit/channels`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/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.
Expand All @@ -14,19 +14,31 @@ the whole stack.

https://github.com/user-attachments/assets/a74fa1cb-add0-463e-a23c-aa09b95d5135

▶️ **[Watch the demo](https://github.com/user-attachments/assets/a74fa1cb-add0-463e-a23c-aa09b95d5135)** (~50s) — an OpenTag agent working a Slack thread: it renders a breakdown, a table, and a bar chart inline (**generative UI**) and files a ticket only after an **Approve** gate (**human-in-the-loop**).
▶️ **[Watch the demo](https://github.com/user-attachments/assets/a74fa1cb-add0-463e-a23c-aa09b95d5135)** (~50s) — a KiteBot agent working a Slack thread: it renders a breakdown, a table, and a bar chart inline (**generative UI**) and files a ticket only after an **Approve** gate (**human-in-the-loop**).

> **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 →](https://go.copilotkit.ai/opentag-managed-gh)** 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.

## Quick start (self-hosted)
## Quick start

OpenTag ships inside the [CopilotKit monorepo](https://github.com/CopilotKit/CopilotKit) as a
first-class example (`examples/slack`). That's the dependable way to run it today while the
bot SDK packages finish publishing to npm. (A standalone `npm install` from this repo lights
up the moment they land — see [setup.md](./setup.md).)
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** (the LLM backend) and the **bot** (the Slack
connection) — and set three secrets.
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 channel` runs 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` (or `pnpm 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.

### The packages

Expand All @@ -36,44 +48,58 @@ OpenTag is a thin layer on top of a handful of CopilotKit packages. The `pnpm in

| Package | Role |
| --- | --- |
| [`@copilotkit/bot`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot) | The platform-agnostic bot engine — threading, tool calls, the human-in-the-loop gate. |
| [`@copilotkit/channels`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels) | The platform-agnostic bot engine — threading, tool calls, the human-in-the-loop gate. |
| [`@copilotkit/runtime`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/runtime) | The AG-UI agent backend that runs your LLM and tools. |
| [`@copilotkit/bot-ui`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-ui) | Cross-platform JSX for rich messages (Block Kit on Slack, Components V2 on Discord, HTML on Telegram). |
| [`@copilotkit/bot-slack`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-slack) | The Slack adapter — or swap it for the platform you're targeting (below). |
| [`@copilotkit/channels-ui`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels-ui) | Cross-platform JSX for rich messages (Block Kit on Slack, Components V2 on Discord, HTML on Telegram). |
| [`@copilotkit/channels-slack`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/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/bot-discord`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-discord) · [`-telegram`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-telegram) · [`-whatsapp`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-whatsapp) | Running on a platform other than Slack — one adapter per platform. |
| [`@copilotkit/bot-store-redis`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/bot-store-redis) | Durable thread persistence across restarts (defaults to in-memory without it). |
| [`@copilotkit/channels-discord`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels-discord) · [`-telegram`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels-telegram) · [`-whatsapp`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels-whatsapp) | Running on a platform other than Slack — one adapter per platform. |
| [`@copilotkit/channels-intelligence`](https://github.com/CopilotKit/CopilotKit/tree/main/packages/channels-intelligence) | Runs the bot over the CopilotKit Intelligence Realtime Gateway instead of holding platform tokens — see `app/managed.ts`. |

**1. Create a Slack app.** At [api.slack.com/apps](https://api.slack.com/apps?new_app=1) →
*From a manifest* → paste [`slack-app-manifest.yaml`](./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). Step-by-step in [setup.md](./setup.md#1-create-a-slack-app).
`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](./setup.md#1-create-a-slack-app).

**2. Set three secrets** in `.env` (`cp .env.example .env`):
**2. Set your secrets** in `.env` (`cp .env.example .env`):

```bash
OPENAI_API_KEY=sk-... # the agent runs on OpenAI's Responses API (required for web search)

# Self-hosted mode:
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY — bring your own model

# 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** from the CopilotKit monorepo root:
**3. Run it:**

```bash
pnpm install
pnpm --filter slack-example runtime # the agent backend, on :8200
pnpm --filter slack-example dev # the bot
pnpm runtime # the agent backend, on :8200

pnpm channel # recommended — the bot over the Intelligence Gateway
# or
pnpm dev # alternative — the bot, self-hosted
```

**4. Talk to it.** @mention the bot in any channel thread:

> @OpenTag summarize this thread and file it as a bug
> @KiteBot summarize this thread and file it as a bug

That's the whole loop. To wire up Linear, Notion, inline charts, Redis persistence, or to run
That's the whole loop. To wire up Linear, Notion, inline charts, or to run
on Discord / Telegram / WhatsApp, see **[setup.md](./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](https://go.copilotkit.ai/opentag-managed-gh) for the CopilotKit managed service as part of our Intelligence platform, both cloud-hosted or self-hosted.
Expand All @@ -93,6 +119,39 @@ OpenTag is deliberately small and hackable:
The full architecture, the file-by-file map, and every integration live in
**[setup.md](./setup.md)**.

## Deep research (LangGraph deep agent)

`agent/` is an alternative agent backend to `runtime.ts` — a Python
[`deepagents`](https://github.com/langchain-ai/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:

```bash
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 SERVER_PORT/PORT env, default 8123)
```

Then point the bot at it instead of `runtime.ts` by setting in `.env`:

```bash
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.

## Don't want to host it yourself?

Self-hosting means you run and scale the runtime, persistence, and inspection tooling yourself.
Expand Down
26 changes: 26 additions & 0 deletions agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# KiteBot deep-research agent (agent/) — served over AG-UI on SERVER_PORT.
# The channel host / self-hosted bot points AGENT_URL at http://localhost:8123/
# Only OPENAI_API_KEY is required; the agent chats + generates UI components without Tavily.
OPENAI_API_KEY=sk-...
# OPTIONAL — web research. Without it the agent still works (chat + UI components,
# answers from its own knowledge); with it, live web research turns on. https://tavily.com
# TAVILY_API_KEY=tvly-...
# OpenAI model (defaults to gpt-5.5, matching the rest of OpenTag).
# OPENAI_MODEL=gpt-5.5
# Server bind (defaults 0.0.0.0:8123).
# SERVER_HOST=0.0.0.0
# SERVER_PORT=8123

# ── Internal research sources (optional) ────────────────────────────────
# Setting LINEAR_API_KEY and/or NOTION_MCP_AUTH_TOKEN lets the agent research
# the team's Linear issues / Notion docs alongside (or instead of) the web —
# see internal_source_tools() in tools.py. Leave both blank to research the
# web only.
# Hosted Linear MCP bearer token (linear.app → Settings → API → Personal API
# keys). LINEAR_MCP_URL defaults to the hosted Linear MCP if unset.
# LINEAR_API_KEY=lin_api_...
# LINEAR_MCP_URL=https://mcp.linear.app/mcp
# Bearer token for the local Notion MCP sidecar (`pnpm notion-mcp`).
# NOTION_MCP_URL defaults to that local sidecar if unset.
# NOTION_MCP_AUTH_TOKEN=choose-a-strong-shared-secret
# NOTION_MCP_URL=http://127.0.0.1:3001/mcp
5 changes: 5 additions & 0 deletions agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.venv/
__pycache__/
*.pyc
.env
/reports/
Loading