# Slack Integration

Connect TeamDay to your Slack workspace. Mention your agents from any channel, DM them directly, and give them live read/write access to Slack as a tool.

# Slack Integration

TeamDay works inside Slack in two complementary ways — and you can turn on either, both, or neither per Space.

| Mode | What it does | When to use |
|------|--------------|-------------|
| **Mention bot** (inbound) | `@TeamDay` in any channel, or DM the bot — your agent replies in-thread | You want a hands-free way to talk to your agent without leaving Slack |
| **Slack MCP** (outbound) | Agents can read channels, post messages, and search history as a tool | Your agents need to act on Slack content — summarise threads, post updates, pull context |

Each Space has its own Slack connection. Different Spaces in the same organisation can link to different workspaces or the same workspace with different bots.

---

## Part 1 — Mention Bot Setup

This gives you the `@TeamDay` experience: mention the bot in a channel and your agent picks up the message, runs its system prompt and tools, and replies in a thread.

### 1. Create a Slack App

Go to [api.slack.com/apps](https://api.slack.com/apps) → **Create New App** → **From scratch**. Pick the workspace you want to connect.

### 2. Enable Socket Mode

In the sidebar: **Socket Mode** → toggle **Enable Socket Mode** on. Slack will prompt you to create an **App-Level Token** with the `connections:write` scope. Give it a name (e.g. `teamday-socket`) and copy the `xapp-...` token — you'll paste it in step 6.

Socket Mode means Slack connects outbound to your App; you don't need a public URL, webhook forwarding, or HMAC verification.

### 3. Add Bot Scopes

In **OAuth & Permissions** → **Scopes** → **Bot Token Scopes**, add:

| Scope | Why |
|-------|-----|
| `app_mentions:read` | Receive `@TeamDay` mentions in channels |
| `chat:write` | Post replies in threads |
| `reactions:write` | Add the 👀 acknowledgement emoji |
| `im:history` | Read direct messages to the bot |
| `im:read` | List DM channels |
| `im:write` | Open DMs when needed |
| `channels:history` | Optional — read context before replying |
| `groups:history` | Optional — same for private channels |

### 4. Subscribe to Events

**Event Subscriptions** → toggle on. Under **Subscribe to bot events**, add:

- `app_mention`
- `message.im`

Save. No Request URL is needed (Socket Mode delivers events over WebSocket).

### 5. Install to Workspace

**Install App** → **Install to Workspace** → approve. Copy the **Bot User OAuth Token** (`xoxb-...`). Also copy the **Signing Secret** from **Basic Information** → **App Credentials**.

You now have three secrets:
- Bot token (`xoxb-...`)
- App token (`xapp-...`)
- Signing secret

### 6. Link the Space

```bash
curl -X POST https://cc.teamday.ai/api/messaging/slack/{spaceId}/link \
  -H "Authorization: Bearer $TEAMDAY_PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "botToken": "xoxb-...",
    "appToken": "xapp-...",
    "signingSecret": "...",
    "agentId": "agent-xyz"
  }'
```

TeamDay validates the tokens against Slack's `auth.test` API before storing them, so an invalid paste fails fast.

On success the response includes `teamName`, `teamId`, `botUserId`, and a `status.status` of `connected`. The bot is live.

### 7. Say Hi

Invite the bot to a channel (`/invite @TeamDay`), then mention it:

> `@TeamDay summarise what's pending from our last standup`

The bot adds a 👀 reaction while working, replies in-thread, and removes the reaction when done. Follow-up messages in the same thread resume the same agent session — the agent remembers the earlier turn.

### Optional: Allowlists

Restrict which channels or users the bot responds to:

```json
{
  "botToken": "xoxb-...",
  "appToken": "xapp-...",
  "signingSecret": "...",
  "allowChannels": ["C01234ABCDE", "C56789FGHIJ"],
  "allowUsers": ["U01234XYZAB"]
}
```

Empty arrays (the default) mean "respond anywhere the bot is invited to."

### Unlinking

```bash
curl -X POST https://cc.teamday.ai/api/messaging/slack/{spaceId}/unlink \
  -H "Authorization: Bearer $TEAMDAY_PAT"
```

The Bolt session stops immediately; tokens stay in Firestore (disabled) so you can re-enable without re-linking.

---

## Part 2 — Slack MCP Setup (Outbound)

The MCP lets an agent *use* Slack as a tool inside a conversation: read a channel, post a message, search history. This is independent from the mention bot — you can have both, or just one.

### 1. Create a Bot Token

Same Slack App as above works. Add these additional scopes if you haven't already:

- `channels:read`, `channels:history`
- `groups:read`, `groups:history` (private channels)
- `users:read`
- `search:read` (workspace search)

Reinstall the app to pick up new scopes.

### 2. Find your Team ID

```bash
curl -X POST https://slack.com/api/auth.test \
  -H "Authorization: Bearer xoxb-..."
```

Copy `team_id` (starts with `T`).

### 3. Add the MCP in TeamDay

Open your Space → **MCPs** tab → **Add MCP** → select **Slack** (under *Communication*). Paste:

- **Slack Bot Token** — `xoxb-...`
- **Slack Team ID** — `T01234ABCDE`
- **Channel IDs** (optional) — comma-separated list to sandbox which channels the agent can access

Save. The MCP is now available to every agent in the Space.

Ask your agent something like:

> "Check `#incidents` for any unresolved threads from the last 24 hours and post a summary to `#exec`."

---

## How it Works

### Per-Space Isolation

Each Space stores its own tokens at `spaces/{spaceId}/integrations/slack`. Organisation membership is checked on every API call, so one org can never see, use, or override another org's Slack connection.

### Thread-Scoped Memory

Each Slack thread maps to one agent session. First mention in a thread = fresh context. Every reply in that thread = `resume` the same Claude SDK session. Two parallel threads in the same channel have independent memory — mirroring how a human experiences a Slack thread.

### Restart Resilience

If the app or messaging service restarts, TeamDay walks `integrations/slack` for `enabled: true` docs and rehydrates every Bolt session automatically. Your bot reconnects without anyone having to re-link.

### Error Handling

If your agent fails mid-reply, the bot posts `⚠️ <error message>` in-thread instead of going silent. The 👀 reaction is always cleaned up so you never see a stuck "thinking" indicator.

---

## Troubleshooting

**Bot doesn't respond to mentions.** Check that:
1. The bot is actually invited to the channel (`/invite @TeamDay`)
2. `app_mention` is in your Event Subscriptions
3. `GET /api/messaging/slack/{spaceId}/status` returns `session.status: "connected"`

**`Slack bot token invalid` on link.** The bot token must start with `xoxb-` (bot token, not user token). Check **OAuth & Permissions** → **Bot User OAuth Token**.

**`appToken must start with xapp-`.** The App-Level Token from **Basic Information** → **App-Level Tokens**, not the Bot token. Make sure you created one with the `connections:write` scope.

**Session shows `connected` but mentions don't arrive.** Most common cause: you forgot to subscribe to `app_mention` in Event Subscriptions. Slack won't send events for unsubscribed types even if the bot is online.

**Duplicate replies.** Running both local dev and production against the same Slack App will cause events to fan out to both. Either use separate Slack Apps per environment, or set `enabled: false` on the Space you're not actively using.

---

## Related

- [MCP Servers — What and Why](https://docs.teamday.ai/en/docs/guides/mcp-servers/what-are-mcp-servers)
- [Installing MCP Servers](https://docs.teamday.ai/en/docs/guides/mcp-servers/installing)
- [Agent Configuration](https://docs.teamday.ai/en/docs/guides/agent-configuration)
