> ## Documentation Index
> Fetch the complete documentation index at: https://speaker-weave.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack agent

> Run the same agent as in-app Ask from Slack mentions and DMs, including tools, MCP connectors, approvals, and shared thread history.

The Slack bot **is the SpeakerWeave agent**, not a separate assistant. A mention or DM enters the same `agent/service.run_turn` runtime as in-app Ask, with the same organization-scoped tool registry, connected MCP servers, provider, thread store, and permission gate.

That means you can start a conversation in Slack, approve a sensitive action without leaving Slack, and find the persisted thread later in the in-app Ask history.

The app registers as a **Slack Agent** (the `AGENT` badge): it gets Slack's split-pane chat surface with suggested prompts, a native *"is thinking…"* status line while a turn runs — in the pane and in channel threads — and a **New chat** control that starts a fresh agent conversation (`assistant_thread_started` resets the thread mapping).

## How the bridge works

```text theme={null}
Slack mention or DM
        ↓ signed event
/api/slack/events
        ↓ Slack transport
agent/service.run_turn
        ↓
same provider runtime + tool registry + MCP connectors
        ↓
one final Slack reply + persisted Ask thread
```

Slack acknowledges Events API requests immediately and finishes the agent turn in the background. The bridge converts the final answer to Slack mrkdwn and posts it once. Slack delivery failures are logged without undoing the persisted agent turn.

The in-app Ask panel is an SSE adapter over `run_turn`; Slack is an Events API and Interactivity adapter over that same function. Neither transport owns a second prompt, model loop, or tool list.

## Approvals in Slack

When the agent reaches a permission-gated action—such as sending email, recording a decision, publishing, deleting data, or calling a mutating MCP tool—it posts an **Approval needed** card with **Approve** and **Deny** buttons.

The turn waits for up to **300 seconds**. Clicking either button resolves the same permission gate used by in-app Ask, then replaces the card with a terminal approved or denied state. If the request was already handled or expired, Slack says so and does not execute the action.

<Warning>
  The approval button value contains only an opaque request ID. Keep Interactivity pointed at the signed SpeakerWeave endpoint; do not put tool arguments or credentials in Slack action values.
</Warning>

## Threads and identity

SpeakerWeave stores the Slack-to-agent relationship in `slack_agent_threads`:

| Slack conversation        | Agent behavior                                                                                          |
| ------------------------- | ------------------------------------------------------------------------------------------------------- |
| Channel mention           | Creates or resumes the mapping for that channel thread and replies in the Slack thread                  |
| Reply in a channel thread | Resumes the same agent thread                                                                           |
| Top-level DM              | Resumes the most recent agent thread for that DM channel, or creates one; replies stay unthreaded       |
| Agent pane conversation   | Each pane chat is a threaded DM mapped to its own agent thread; replies stay inside the pane            |
| **New chat** in the pane  | `assistant_thread_started` inserts a fresh mapping, so the next message starts a new agent conversation |

Channel messages are attributed with the sender's Slack display name when `users.info` is available. Agent threads use `slack:<user_id>` as their user identity, remain organization-scoped, and appear in the in-app Ask thread history.

## Set up the Slack app

The manifest does almost all of the configuration. For a self-hosted deployment, first replace both `https://speakerweave.com` request URLs in the manifest with your public web origin.

1. In Slack, choose **Create New App → From an app manifest** and paste [`api/slack_manifest.json`](https://github.com/Brandonmchu/speakerweave/blob/main/api/slack_manifest.json) (or copy the manifest from **Settings → Integrations** in the app). The manifest configures:
   * Bot token scopes: `app_mentions:read`, `assistant:write`, `chat:write`, `im:history`, `im:read`, `im:write`, `users:read`
   * Bot events on `/api/slack/events`: `app_mention`, `assistant_thread_started`, `message.im`
   * **Interactivity** on that same URL (this is what delivers Approve/Deny clicks)
   * The **agent view** (AGENT badge + split-pane surface) with a description and suggested prompts
   * An unlocked **messages tab**, so the pane composer accepts messages
   * Socket Mode off — SpeakerWeave receives signed HTTPS events only
2. **Install the app to the workspace** and copy the **Bot User OAuth Token** (`xoxb-…`) from OAuth & Permissions and the **Signing Secret** from Basic Information.
3. Optional but recommended: upload the app icon from [`assets/slack-app-icon-1024.png`](https://github.com/Brandonmchu/speakerweave/blob/main/assets/slack-app-icon-1024.png) under **Basic Information → Display Information**.
4. Invite the bot to any channels where it should answer mentions (`/invite @SpeakerWeave`). DMs and the agent pane need no invite.
5. Configure the API environment (next section) and send the bot a DM.

<Note>
  If you change scopes or events later, Slack requires a **reinstall** before the new configuration takes effect; the token value survives reinstalls.
</Note>

## Configure the API environment

| Variable                                | Purpose                                                                            |
| --------------------------------------- | ---------------------------------------------------------------------------------- |
| `SLACK_SIGNING_SECRET`                  | Verifies the raw body of Events API and Interactivity requests                     |
| `SLACK_BOT_TOKEN`                       | Slack bot token (`xoxb-…`) used to read display names and post replies             |
| `SLACK_DEFAULT_ORG`                     | Organization that this Slack workspace is allowed to access; defaults to `org_dev` |
| `OPENAI_API_KEY` or `ANTHROPIC_API_KEY` | Enables the selected agent provider; `ASSISTANT_PROVIDER` can choose explicitly    |

You can verify the detected provider and key state under **Settings → Integrations → Slack bot**.

## Troubleshooting

| Symptom                                            | Cause and fix                                                                                                                                                                                      |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Sending messages to this app has been turned off" | The messages tab is locked. **App Home → Show Tabs → Chat/Messages Tab** must be on with *Allow users to send … messages* checked. Apps created from the current manifest have this preconfigured. |
| No `AGENT` badge / no split pane                   | The agent designation isn't active: check the **Agents** page in the Slack app config, then reinstall. Slack clients cache app metadata — fully reload Slack (`Cmd+R`) after changing it.          |
| Approve/Deny buttons do nothing                    | Interactivity is off or points at a different URL than Event Subscriptions. Both must be the same signed `/api/slack/events` endpoint.                                                             |
| No "is thinking…" status                           | The status renders only inside threads (the agent pane or a channel thread), requires the `assistant:write` scope, and the app must be reinstalled after adding it.                                |
| Bot never replies in a channel                     | The bot must be a member of that channel. Also confirm the events request URL shows **Verified** in Event Subscriptions.                                                                           |
| Replies lack sender names in shared channels       | `users:read` is missing or the app wasn't reinstalled after adding it.                                                                                                                             |

## Deployment boundary

The reference configuration intentionally binds one deployment to one Slack workspace and one `SLACK_DEFAULT_ORG`; there is no Slack OAuth installation flow. Before serving multiple workspaces from one deployment, add a workspace-to-organization installation table and resolve the organization from the verified Slack workspace instead of a global environment value.
