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. + +<Callout type="warning"> +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). +</Callout> + +### 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). + +<Callout type="warning"> +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). +</Callout> + +### Chat and `/issue` + +- **In a channel** — the bot is not auto-joined. Run `/invite @your-bot` once, then `@your-bot <your message>`. +- **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. + +<Callout type="info"> +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. +</Callout> + +## 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=<base64-encoded 32-byte 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. + +<Callout type="info"> +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. +</Callout> + +## 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