diff --git a/apps/docs/content/docs/channels.mdx b/apps/docs/content/docs/channels.mdx
new file mode 100644
index 000000000..7bc07a856
--- /dev/null
+++ b/apps/docs/content/docs/channels.mdx
@@ -0,0 +1,94 @@
+---
+title: Chat integrations (channels)
+description: How Multica connects agents to chat platforms — one channel engine, per-platform adapters for Lark (飞书) and Slack — covering the inbound pipeline, sessions, and authorization.
+---
+
+import { Callout } from "fumadocs-ui/components/callout";
+import { Mermaid } from "@/components/mermaid";
+
+A **channel** connects a Multica [agent](/agents) to a chat platform so your team can work with it where they already talk. Today there are two channels — [Lark (飞书)](/lark-bot-integration) and [Slack](/slack-bot-integration) — and both run on the **same engine**: a platform-neutral core plus a thin per-platform adapter. Adding a platform is "implement the adapter," not "rebuild the pipeline."
+
+An **installation** is the unit that ties it together: one bot bound to one `(workspace, agent)`. Inbound messages are routed to an installation, then through a shared pipeline; the agent's reply is sent back to the same chat.
+
+## Architecture
+
+one live connection per installation"]
+ ROU["Router pipeline:
route → dedup → auth → session → trigger"]
+ end
+ LK -->|long connection| SUP
+ SL -->|Socket Mode| SUP
+ SUP -->|raw event| ADP["Per-platform adapter
translate + ResolverSet"]
+ ADP --> ROU
+ ROU -->|agent task| RUN["Daemon runs the agent"]
+ RUN -->|reply| OUT["Per-platform outbound
(bot token → platform API)"]
+ OUT --> P
+`} />
+
+## The inbound pipeline (generic)
+
+Every inbound message — Lark or Slack — runs through the same ordered steps in the engine `Router`. A platform adapter only supplies the per-platform pieces (the `ResolverSet`); the policy lives in the engine.
+
+1. **Route to installation** — map the event to a `channel_installation` (→ workspace + agent). Lark routes by `app_id`; Slack routes by the app id carried on the event.
+2. **Addressing filter** — in a group/channel, only messages that **@-mention the bot** continue; idle group chatter is dropped (not read).
+3. **Dedup** — a two-phase `(installation, message_id)` claim guarantees exactly-once processing, even across server replicas.
+4. **Identity + authorization** — resolve the sender's platform user id to a Multica user (the [account binding](#authorization)), then re-check workspace membership. Unbound senders get a "link your account" prompt; non-members are dropped.
+5. **Session** — find or create a [chat session](/chat) for this conversation and append the message (see [Sessions](#sessions-and-context)).
+6. **Trigger** — enqueue an agent [task](/tasks); a [daemon](/daemon-runtimes) runs the agent and the reply is sent back into the chat.
+
+## Sessions and context
+
+The agent's context is the **chat-session transcript** — the messages that have been ingested into that session over time. This transcript model is generic (shared by every channel). What differs per platform is the **session-isolation key** the adapter composes:
+
+| Platform | Isolation key | Effect |
+|---|---|---|
+| **Lark / 飞书** | the chat id | One session per chat/group — consecutive turns in the same chat accumulate into one transcript (multi-turn memory). |
+| **Slack** | DM: the channel; channel: `channel + thread root` | Each DM is one session; **each @bot thread is its own session**, so two threads in one channel don't mix. |
+
+
+In a group, only messages that **@-mention the bot** are ingested. Neither channel reads the channel's other (un-@'d) messages or scrollback today, so the agent won't see messages it wasn't addressed in. Fetching surrounding history as context is a planned enhancement.
+
+
+## Authorization
+
+Two independent gates protect a bot in a shared group — both enforced in the engine for every message, identically for Lark and Slack:
+
+- **Account binding (authentication)** — the sender's platform user id must be linked to a Multica user. The first time someone messages the bot they get a one-time link to bind their identity to **their own** Multica account; until then no agent runs.
+- **Workspace membership (authorization)** — the bound Multica user must be a member of the installation's workspace, re-checked on every message. Non-members are silently dropped.
+
+So adding a bot to a public channel is safe: only workspace members who have bound their identity can drive the agent, and each sender is checked independently. See the per-platform pages for the user-facing prompts.
+
+## The two channels
+
+
+**Lark (飞书) — scan to install.** A workspace admin binds an agent by scanning a QR with the Lark app; no developer console steps. One Bot per agent. See [Lark Bot integration](/lark-bot-integration).
+
+
+
+**Slack — bring your own app.** A workspace admin creates a Slack app, installs it to their Slack workspace, and pastes its bot token + app-level token into Multica. Each agent gets its own Slack app, so several agents can each have a distinct bot in one Slack workspace. See [Slack Bot integration](/slack-bot-integration) and [Create a Slack app](/create-slack-app).
+
+
+## Self-host
+
+Each channel is **off until you set its at-rest encryption key** (the key encrypts each bot's tokens before they touch the database):
+
+```dotenv
+MULTICA_LARK_SECRET_KEY=
+MULTICA_SLACK_SECRET_KEY=
+```
+
+On Multica Cloud both are already configured. See [Environment variables](/environment-variables) for the full reference.
+
+## Next
+
+- [Lark Bot integration](/lark-bot-integration) — scan-to-install, DM / @-mention / `/issue`
+- [Slack Bot integration](/slack-bot-integration) — bring-your-own-app, per-agent bots
+- [Create a Slack app](/create-slack-app) — the step-by-step app + token setup
+- [Agents](/agents) · [Chat](/chat) · [Tasks](/tasks)
diff --git a/apps/docs/content/docs/create-slack-app.mdx b/apps/docs/content/docs/create-slack-app.mdx
new file mode 100644
index 000000000..c9b31fec7
--- /dev/null
+++ b/apps/docs/content/docs/create-slack-app.mdx
@@ -0,0 +1,97 @@
+---
+title: Create a Slack app
+description: Step-by-step — create a Slack app from a manifest, install it to your workspace, and grab the bot token and app-level token to connect it to a Multica agent.
+---
+
+import { Callout } from "fumadocs-ui/components/callout";
+
+Multica's [Slack integration](/slack-bot-integration) is **bring-your-own-app**: you create a Slack app, install it to your Slack workspace, and paste two tokens into Multica. This page walks through that one-time setup. It takes about five minutes and needs no public URL.
+
+At the end you'll have two values to paste into the agent's **Connect Slack** dialog:
+
+- a **Bot token** — starts with `xoxb-`
+- an **App-level token** — starts with `xapp-`
+
+## 1. Create the app from a manifest
+
+1. Go to [https://api.slack.com/apps](https://api.slack.com/apps) and click **Create New App**.
+2. Choose **From a manifest**.
+3. Pick the Slack workspace to install the app into.
+4. Paste the manifest below (the **YAML** tab), review, and create the app.
+
+```yaml
+display_information:
+ name: Multica
+features:
+ app_home:
+ messages_tab_enabled: true
+ messages_tab_read_only_enabled: false
+ bot_user:
+ display_name: Multica
+ always_online: true
+oauth_config:
+ scopes:
+ bot:
+ - app_mentions:read
+ - channels:history
+ - chat:write
+ - groups:history
+ - im:history
+ - mpim:history
+ - users:read
+settings:
+ event_subscriptions:
+ bot_events:
+ - app_mention
+ - message.im
+ - message.channels
+ - message.groups
+ - message.mpim
+ interactivity:
+ is_enabled: false
+ socket_mode_enabled: true
+ org_deploy_enabled: false
+ token_rotation_enabled: false
+```
+
+The manifest already configures everything Multica needs — bot scopes, event subscriptions, Socket Mode, and the Messages tab — so you don't have to set them by hand. There is **no OAuth redirect URL** because BYO doesn't use OAuth.
+
+
+Want the bot to show up under a specific name in Slack? Change `display_information.name` and `features.bot_user.display_name` (e.g. to your agent's name) before creating, or edit it later under **App Home**. Slack shows the bot by its **bot display name**, which can differ from the app name.
+
+
+
+Keep `users:read` in the scopes. Multica calls `bots.info` to verify the bot token and app-level token belong to the same app, and that call needs `users:read`. Without it, **Connect** fails.
+
+
+## 2. Install the app and copy the Bot token
+
+1. In the app's left nav, open **Install App** (or **OAuth & Permissions**).
+2. Click **Install to Workspace** and approve.
+3. Copy the **Bot User OAuth Token** — it starts with `xoxb-`. This is your **Bot token**.
+
+## 3. Create the App-level token
+
+The app-level token authorizes the Socket Mode connection and can only be created in the console (it isn't available over OAuth).
+
+1. Open **Basic Information → App-Level Tokens**, click **Generate Token and Scopes**.
+2. Give it any name.
+3. Click **Add Scope** and select **`connections:write`** (it's a picker — select it from the list, don't type it).
+4. Click **Generate**, then copy the token — it starts with `xapp-`. This is your **App-level token**.
+
+## 4. Connect it in Multica
+
+1. In Multica, open the agent → **Integrations** tab → **Connect Slack**.
+2. Paste the **Bot token** (`xoxb-`) and the **App-level token** (`xapp-`).
+3. Click **Connect**.
+
+That's it. Now use the bot: `/invite @your-bot` into a channel and `@`-mention it, or DM it from the Slack sidebar's **Apps** section. See [Slack Bot integration](/slack-bot-integration) for usage and `/issue`.
+
+
+Doing this for **multiple agents**? Repeat the whole flow once per agent — each agent gets its own Slack app and its own pair of tokens, and they appear as separate bots in your workspace.
+
+
+## Next
+
+- [Slack Bot integration](/slack-bot-integration) — connect, use, and manage the bot
+- [Chat integrations](/channels) — how the channel engine works
diff --git a/apps/docs/content/docs/meta.json b/apps/docs/content/docs/meta.json
index f9e67d17e..880800835 100644
--- a/apps/docs/content/docs/meta.json
+++ b/apps/docs/content/docs/meta.json
@@ -30,8 +30,11 @@
"---Inbox---",
"inbox",
"---Integrations---",
+ "channels",
"github-integration",
"lark-bot-integration",
+ "slack-bot-integration",
+ "create-slack-app",
"---Self-hosting & ops---",
"environment-variables",
"auth-setup",
diff --git a/apps/docs/content/docs/slack-bot-integration.mdx b/apps/docs/content/docs/slack-bot-integration.mdx
new file mode 100644
index 000000000..b42339ca1
--- /dev/null
+++ b/apps/docs/content/docs/slack-bot-integration.mdx
@@ -0,0 +1,101 @@
+---
+title: Slack Bot integration
+description: Connect a Multica agent to your own Slack app, then talk to it from a DM or channel — @-mention it, chat naturally, or type /issue to file a Multica issue without leaving Slack.
+---
+
+import { Callout } from "fumadocs-ui/components/callout";
+
+Connect any [agent](/agents) to a Slack bot and your team can work with it from inside Slack — DM the bot, @-mention it in a channel, or type `/issue` to file a [Multica issue](/issues) without opening the app.
+
+Slack uses a **bring-your-own-app (BYO)** model: a workspace admin creates a Slack app, installs it to their Slack workspace, and pastes its tokens into Multica. Each agent gets **its own** Slack app — so several agents can each have a distinct, separately @-mentionable bot in the same Slack workspace. (This differs from [Lark](/lark-bot-integration), where binding is a scan-to-install flow.)
+
+
+First time setting one up? Follow [Create a Slack app](/create-slack-app) to get the two tokens, then come back here to paste them.
+
+
+## What the integration does
+
+| Surface | Behavior |
+|---|---|
+| **Agent → Integrations** | The agent detail page has an **Integrations** tab (and a matching section in the left sidebar). Owners and admins see **Connect Slack** there; once connected it flips to a **Connected to Slack** badge with a **Disconnect** control. |
+| **DM the bot** | A workspace member messages the bot directly in Slack. The conversation becomes a Multica [chat](/chat) session with the agent. |
+| **@-mention in a channel** | Invite the bot to a channel (`/invite @your-bot`) and @-mention it. Only the mentioning message is read — the bot does not listen to the whole channel. Each @bot thread is its own session. |
+| **`/issue` command** | Starting a message with `/issue ` (optionally with a body) creates a new Multica issue in the workspace, attributed to you. |
+| **Reply** | The agent's answer is posted back into the same DM or thread. |
+
+## Connect an agent (owner / admin)
+
+You need a Slack app's **bot token** (`xoxb-`) and **app-level token** (`xapp-`) — create them with [Create a Slack app](/create-slack-app).
+
+1. Open the agent in **Agents → _your agent_**.
+2. Go to the **Integrations** tab (or the **Integrations** section in the left sidebar) and click **Connect Slack**.
+3. In the dialog, paste the **Bot token** (`xoxb-`) and the **App-level token** (`xapp-`), then click **Connect**.
+4. The agent shows **Connected to Slack**. The bot is now listening over its own Socket Mode connection.
+
+
+The two tokens must come from the **same** Slack app — Multica verifies this at connect time (using the `users:read` scope via `bots.info`). If your app is missing `users:read`, or the tokens are from different apps, the connect is rejected. The required scopes are listed in [Create a Slack app](/create-slack-app).
+
+
+### One bot per agent
+
+Each Slack app maps to exactly one agent. Connecting an app that's already connected to a different agent or workspace is refused. To move an app to a different agent, disconnect it first. Re-connecting an agent with a **new** app (for example after disconnecting) updates that agent's bot in place.
+
+## Use the bot (members)
+
+### First message: bind your Slack identity
+
+The first time you @-mention or DM the bot, it replies asking you to **link your account** — tap the link, sign in to Multica, and your Slack identity is bound to your Multica membership. This is what lets the agent act as you (for example, `/issue` files the issue under your name).
+
+
+Only people who are **members of the workspace** can use the bot. If you aren't a member, or you skip the identity bind, the bot won't run — your message is dropped (recorded for audit, without its contents).
+
+
+### Chat and `/issue`
+
+- **In a channel** — the bot is not auto-joined. Run `/invite @your-bot` once, then `@your-bot `.
+- **In a DM** — open the bot from the Slack sidebar's **Apps** section and message it directly.
+- **File an issue** — send `/issue Fix the login redirect` and Multica creates that issue in the workspace. Add more lines after the title for a description.
+
+
+The bot shows under its **bot display name** (set in the Slack app's App Home), which may differ from the app name. Look for that name when inviting or DMing it.
+
+
+## Manage and disconnect
+
+Workspace-wide management lives in **Settings → Integrations**:
+
+- **Connected bots** lists every bot in the workspace and the agent each is bound to (visible to all members).
+- **Disconnect** is **owner / admin only**. It stops the bot from receiving Slack messages and tears down its connection; the installation record is kept for audit, and you can re-connect later.
+
+## Permissions
+
+- **Connect / disconnect** require workspace **owner** or **admin**.
+- **Talking to the bot** requires being a workspace member with a bound Slack identity. Everyone else is dropped.
+- Message bodies for dropped messages are never stored — only a drop reason, for audit.
+
+## Self-host setup
+
+On Multica Cloud the integration is already available — skip this section.
+
+For self-host, Slack is **off until you set an at-rest encryption key**. The key encrypts each app's bot + app-level tokens before they touch the database. Unlike a hosted-OAuth integration, BYO needs **no** OAuth client id/secret and **no** deployment-level app token — each installation uses the tokens the admin pastes.
+
+1. Generate a 32-byte key and set it on the API server:
+
+ ```dotenv
+ MULTICA_SLACK_SECRET_KEY=
+ ```
+
+ For example: `openssl rand -base64 32`.
+
+2. Restart the API. Until the key is set, **Settings → Integrations** shows a "Slack integration not enabled" notice and the **Connect Slack** entry points stay hidden.
+
+
+The key must decode to exactly 32 bytes — generate it with `openssl rand -base64 32`. Treat it as a long-lived secret: rotating or losing it makes already-stored tokens undecryptable, forcing every bot to reconnect.
+
+
+## Next
+
+- [Create a Slack app](/create-slack-app) — get the bot + app-level tokens
+- [Chat integrations](/channels) — how the channel engine, sessions, and authorization work
+- [Agents](/agents) · [Chat](/chat) · [Issues](/issues)
+- [Environment variables](/environment-variables) — full self-host configuration reference