# OpenTag reference application

> The flagship Channels app vendored as a pinned git submodule: what it demonstrates (Python LangGraph agent over AG-UI, Slack and Teams surfaces, file-aware prompts, approval-gated Linear/Notion writes), how to fetch it with git submodule update --init, its prerequisites, and the deliberate one-line workflow for bumping the pin.

- Repository: CopilotKit/channels-sdk
- GitHub: https://github.com/CopilotKit/channels-sdk
- Human docs: https://grok-wiki.com/public/docs/copilotkit-channels-sdk-4c947e3e6161
- Complete Markdown: https://grok-wiki.com/public/docs/copilotkit-channels-sdk-4c947e3e6161/llms-full.txt

## Source Files

- `examples/README.md`
- `.gitmodules`
- `README.md`
- `AGENTS.md`

---

---
title: "OpenTag reference application"
description: "The flagship Channels app vendored as a pinned git submodule: what it demonstrates (Python LangGraph agent over AG-UI, Slack and Teams surfaces, file-aware prompts, approval-gated Linear/Notion writes), how to fetch it with git submodule update --init, its prerequisites, and the deliberate one-line workflow for bumping the pin."
---

[OpenTag](https://github.com/CopilotKit/OpenTag) is an open-source, self-hosted on-call triage assistant for Slack and Microsoft Teams, and the flagship application built on the Channels SDK. This repository vendors it at `examples/OpenTag` as a **git submodule** — a single pinned commit of OpenTag's `main` branch, declared in `.gitmodules` — rather than a copied source tree, so no duplicated code can drift out of sync. A plain `git clone` of this repository leaves `examples/OpenTag` empty until you initialize the submodule.

## What it demonstrates

OpenTag is the reference for how the pieces documented across this site fit together in one complete, production-shaped application:

| Capability | How OpenTag shows it |
| --- | --- |
| Agent backend | A Python LangGraph agent connected over AG-UI, running as its own agent service |
| Runtime wiring | One `CopilotKitIntelligence`, one `CopilotRuntime`, one adapter-free managed Channel |
| Surfaces | Native Slack and Microsoft Teams experiences from the same Channel code |
| Files and UI | File-aware prompts and generative UI rendered into the conversation |
| Human-in-the-loop | Human approval gates before Linear or Notion writes |
| Deployment shape | A production-shaped Node runtime process alongside the Python agent service |

The repository's `build-channels-agent` skill (`.agents/skills/build-channels-agent/SKILL.md`) names OpenTag as the reference app and instructs agents to mirror it whenever a task is close to "a full Slack agent app."

## Fetch the submodule

<Steps>
<Step title="Initialize after a plain clone">

A regular clone records only the submodule pointer. Populate `examples/OpenTag` with:

```sh
git submodule update --init examples/OpenTag
```

</Step>
<Step title="Or clone with submodules from the start">

```sh
git clone --recurse-submodules https://github.com/CopilotKit/ChannelsSDK.git
```

</Step>
<Step title="Verify">

`git submodule status` should show the pinned commit without a leading `-` (a leading `-` means uninitialized), and `examples/OpenTag` should contain OpenTag's source, including `README.md` and `setup.md`.

</Step>
</Steps>

<Note>
Once initialized, run and setup instructions live inside the submodule at `examples/OpenTag/README.md` and `examples/OpenTag/setup.md`. Those files are not present in this repository until the submodule is fetched.
</Note>

## Prerequisites

Running OpenTag requires both a Node.js side (the Channels listener) and a Python side (the LangGraph agent):

| Requirement | Purpose |
| --- | --- |
| Node.js 22+ | Long-running Channels runtime process |
| `pnpm` | Node package management |
| Python 3.12 | LangGraph agent service |
| [`uv`](https://docs.astral.sh/uv/) | Python environment and dependency management |
| CopilotKit Intelligence project, Channel, and runtime API key | Managed platform connection (no Slack/Teams tokens in your process) |
| OpenAI API key | Model credentials for the agent |

## Submodule pin model

The pin is defined in `.gitmodules`:

```ini title=".gitmodules"
[submodule "examples/OpenTag"]
	path = examples/OpenTag
	url = https://github.com/CopilotKit/OpenTag.git
	branch = main
```

`branch = main` matters: it makes `git submodule update --remote` follow OpenTag's `main` instead of git's `master` default. The superproject records the submodule as a `160000 commit` tree entry — one commit hash, not a live link — so updates to OpenTag's `main` never appear here automatically.

## Bump the pin

Moving the pin is a deliberate, reviewable one-line change:

```sh
git submodule update --remote examples/OpenTag
git add examples/OpenTag
git commit -m "chore(examples): bump OpenTag submodule"
```

The resulting diff is a single hash change on the `examples/OpenTag` gitlink, which makes the update easy to review and easy to revert.

<Tip>
This vendoring strategy is intentional. The repository previously vendored a full copy of another artifact (the `setup-slack-channel` skill), which drifted ~16 KB behind its upstream and ended up asserting incorrect behavior; `AGENTS.md` documents that failure and the resulting rule of one home per artifact. The submodule pin applies the same principle to OpenTag: one source of truth, fetched on demand, moved only by an explicit commit.
</Tip>

## Related pages

<CardGroup cols={2}>
<Card title="Architecture and the runtime boundary" href="/architecture">
The turn flow OpenTag implements at full scale: platform event → Intelligence → your Channels process → agent over AG-UI → native UI back.
</Card>
<Card title="Minimal Channel example" href="/minimal-channel-example">
The smallest complete listener in `examples/minimal-channel` — the stripped-down counterpart to OpenTag.
</Card>
<Card title="Human-in-the-loop approvals" href="/human-in-the-loop">
The approval-gate pattern OpenTag uses before Linear and Notion writes.
</Card>
<Card title="Managed Channels vs direct adapters" href="/managed-vs-direct">
Why OpenTag runs an adapter-free managed Channel with no platform tokens in the process.
</Card>
</CardGroup>
