> ## Documentation Index
> Fetch the complete documentation index at: https://opensre.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack

> Deliver investigation findings via webhook, and chat with the agent via Socket Mode.

The Slack integration covers two surfaces:

1. **Incoming webhook** — outbound delivery of investigation findings to a channel.
2. **Socket Mode bot** — two-way chat with the OpenSRE agent (mentions and DMs),
   managed the same way as the [Telegram gateway](/docs/messaging/telegram#two-way-chat-gateway-dm-text).

***

## Prerequisites

* A Slack workspace where you can create or install apps (workspace admin or app-install permissions).
* The channel you want findings posted to (webhook) and/or where the bot will be invited (Socket Mode).

***

## Step 1: Create a Slack incoming webhook

1. Visit [https://api.slack.com/apps](https://api.slack.com/apps) and click **Create New App → From scratch**.
2. Name the app (e.g. `OpenSRE`) and pick your workspace.
3. In the left sidebar, open **Incoming Webhooks** and toggle the feature **On**.
4. Click **Add New Webhook to Workspace**.
5. Pick the channel where findings should be posted and click **Allow**.
6. Copy the generated URL. It has three path segments — a workspace ID, a channel/app binding ID, and a per-webhook secret — for example:

   ```text theme={null}
   https://hooks.slack.com/services/<workspace-id>/<binding-id>/<secret>
   ```

<Note>
  Treat this URL like a password — anyone holding it can post to your channel. If your workspace already has a Slack app you want to reuse, you can add a new webhook to it instead of creating a fresh app; the URL format is the same.
</Note>

***

## Step 2: Configure the integration in OpenSRE

You have two equivalent paths:

<Tabs>
  <Tab title="Direct setup command (recommended)">
    ```bash theme={null}
    opensre integrations setup slack
    ```

    Choose **webhook**, **Socket Mode**, or **both**. Credentials are persisted to
    `~/.opensre/integrations.json` (and can be merged on re-run).
  </Tab>

  <Tab title="Manual env var">
    Add to `.env`:

    ```bash theme={null}
    SLACK_WEBHOOK_URL=https://hooks.slack.com/services/<workspace-id>/<binding-id>/<secret>
    # Optional Socket Mode gateway:
    SLACK_BOT_TOKEN=xoxb-…
    SLACK_APP_TOKEN=xapp-…
    SLACK_ALLOWED_USERS=U0123ABCD
    ```

    OpenSRE reads env as a fallback when no Slack entry exists in `~/.opensre/integrations.json`.
    Bot / app tokens use `resolve_env_credential` (process env, then OS keyring).
    `SLACK_WEBHOOK_URL` is store/env only — never keyring.
  </Tab>

  <Tab title="Onboarding wizard">
    ```bash theme={null}
    opensre onboard
    ```

    Select **Slack** and choose webhook / Socket Mode / both. The wizard validates
    the webhook when configured, then persists credentials to the integration store.
    Socket Mode tokens are dual-written to the OS keyring; the webhook URL is not.
  </Tab>
</Tabs>

<Note>
  **Credential resolution.** Store first when present. Then:
  `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` → env then keyring;
  `SLACK_WEBHOOK_URL` → plain env only (never keyring).
</Note>

***

## Step 3: Verify

```bash theme={null}
opensre integrations verify slack
```

A successful run reports the integration as `passed`. Webhook-only configs confirm
the URL is present; Socket Mode configs also run Slack `auth.test` on the bot token.
To also confirm webhook delivery, add the `--send-slack-test` flag:

```bash theme={null}
opensre integrations verify slack --send-slack-test
```

This posts a small test message to the configured channel. Expected failure modes are listed below.

You can also trigger a real investigation against a bundled fixture:

```bash theme={null}
opensre investigate --input tests/e2e/kubernetes/fixtures/datadog_k8s_alert.json
```

Findings should appear in the configured channel.

***

## Agent Slack tools

Teammate tools (bot token) plus webhook blast. Credentials resolve inside the
tools (never in tool-call traces). Shared client: `integrations/slack/web_client.py`.

| Tool                      | What it does                                   | Needs                            | Approval |
| ------------------------- | ---------------------------------------------- | -------------------------------- | -------- |
| `slack_send_message`      | Post to the webhook's fixed channel            | `SLACK_WEBHOOK_URL`              | Yes      |
| `slack_reply_message`     | Post to any channel/thread (`C…` or `#name`)   | bot token, `chat:write`          | Yes      |
| `slack_read_messages`     | Read channel history or a thread (`thread_ts`) | bot token, history + list scopes | No       |
| `slack_search_messages`   | Workspace message search                       | bot token, `search:read`         | No       |
| `slack_list_team_members` | List workspace members                         | bot token, `users:read`          | No       |
| `slack_join_channel`      | Join a public channel                          | bot token, `channels:join`       | Yes      |
| `slack_add_reaction`      | React to a message ts                          | bot token, `reactions:write`     | No       |

Prefer `slack_reply_message` / `slack_read_messages` when the bot token is
configured and the user names a channel or thread. Use `slack_send_message` only
for the fixed webhook channel.

For "add task", "remind me", and "what should we focus on next" requests, use
OpenSRE work management. Gateway turns can default reminders and recurring
check-ins to the current Slack channel.

Example prompts:

* "Read the last 20 messages in #incidents and summarize."
* "Search Slack for 'Windows install' this week."
* "Join #ops then reply that mitigation is rolled out."
* "Who is on the team, and what does Vaibhav do?"
* "Add task: ping owners about the deploy window."

Add the scopes in the table under **Create Socket Mode tokens**, then
**Reinstall to Workspace**. Invite the bot (`/invite @OpenSRE`) to private
channels it should read or post in.

***

## Production Engineer schedules (Slack)

Wire morning digests and PR sweeps to a Slack channel (`C…` id from channel
details). The gateway daemon must be running so the scheduler can deliver.

**Sentry morning digest** (unresolved issues → Slack):

```bash theme={null}
opensre sentry digest schedule add \
  --cron "0 8 * * 1-5" \
  --tz Europe/London \
  --provider slack \
  --chat-id C0123ABCD
opensre sentry digest schedule run <task_id>   # dogfood once
```

**Daily ops summary** (investigation pipeline → Slack):

```bash theme={null}
opensre cron add --kind daily_summary --cron "0 9 * * 1-5" \
  --tz Europe/London --provider slack --chat-id C0123ABCD
opensre cron run <task_id>
```

**GitHub PR sweep** (mergeable / stale / conflicted → Slack; needs GitHub configured):

```bash theme={null}
opensre integrations verify github
opensre cron add --kind github_pr_sweep --cron "0 9 * * 1-5" \
  --tz Europe/London --provider slack --chat-id C0123ABCD
opensre cron run <task_id>
```

See also [Scheduled deliveries](/docs/cron) and [Sentry morning digest](/docs/sentry#morning-digest-scheduled).

***

## Two-way chat gateway (Socket Mode)

OpenSRE can also run a **Slack messaging gateway** so you can chat with the agent
from Slack mentions or DMs. Each thread is its own conversation. No public inbound
HTTPS URL is required — the gateway holds an outbound websocket.

### Create Socket Mode tokens

1. In your Slack app settings, enable **Socket Mode** and create an app-level token
   with the `connections:write` scope (`xapp-…`).
2. Under **OAuth & Permissions**, grant the bot scopes below, then install the
   app and copy the bot token (`xoxb-…`).
3. Under **Event Subscriptions**, subscribe to the bot events `app_mention` and `message.im`.

**Bot Token Scopes (Socket Mode chat + teammate tools):**

| Scope                 | Needed for                                                              |
| --------------------- | ----------------------------------------------------------------------- |
| `app_mentions:read`   | Gateway `@mention` inbound                                              |
| `chat:write`          | Gateway replies + `slack_reply_message`                                 |
| `im:history`          | Gateway DMs + reading DM history                                        |
| `channels:history`    | `slack_read_messages` + thread seeding in public channels               |
| `groups:history`      | `slack_read_messages` in private channels                               |
| `mpim:history`        | `slack_read_messages` in multi-party DMs                                |
| `groups:read`         | Resolve private channel names                                           |
| `groups:write`        | Manage / create private channels                                        |
| `files:read`          | Inbound file-attachment downloads + discover Slack Lists (`files.list`) |
| `files:write`         | Upload files as the bot                                                 |
| `lists:read`          | `slack_read_list` — read Slack List rows (`slackLists.items.list`)      |
| `search:read.public`  | `slack_search_messages` in public channels                              |
| `search:read.private` | Search private channels                                                 |
| `search:read.im`      | Search DMs                                                              |
| `search:read.mpim`    | Search group DMs                                                        |
| `search:read.files`   | Search files                                                            |
| `search:read.users`   | Search users                                                            |
| `usergroups:read`     | View workspace user groups                                              |
| `users.profile:read`  | Speaker profile details                                                 |
| `users:read`          | `slack_list_team_members` + user lookup                                 |

<Note>
  Add these only if you use the feature — they are not in the current app config:
  `reactions:write` (gateway ack 👀 / ✓ reactions + `slack_add_reaction`),
  `channels:read` / `im:read` / `mpim:read` (resolve `#channel-name` and DM names
  → ID), and `channels:join` (`slack_join_channel`).
</Note>

Optional env: `SLACK_TEAM_TASKS_LIST_ID` (`F…`) so `slack_read_list` can open the
default team-tasks List without a name search.

Reinstall the app after adding scopes so the bot token picks them up.

### Allow your Slack user

Find your Slack **member ID** (`U…`) in the Slack app:

1. Open your profile (avatar / name).
2. Click **⋯** (More) next to **View as** / profile actions.
3. Choose **Copy member ID**.

Then allow that id:

Interactive shell:

```text theme={null}
/messaging allow -p slack -u U0123ABCD
```

CLI:

```bash theme={null}
opensre messaging allow -p slack -u U0123ABCD
```

or set `SLACK_ALLOWED_USERS=U0123ABCD` in `.env`. The integration store takes
precedence when both are set.

<Warning>
  Use the Slack **member ID** (`U…`) from **Copy member ID**, not `@display-name`
  (e.g. not `@Yauhen`). Handles can be reassigned; inbound authorization only
  matches stable user IDs.
</Warning>

For dogfood only, you may set `SLACK_ALLOW_OPEN_WORKSPACE=1` instead (any
workspace member can talk to the bot).

### DM pairing (optional)

Same policy as Telegram. Generate a code:

```bash theme={null}
opensre messaging pair -p slack
```

Then DM the bot (or mention it) and send:

```text theme={null}
/pair <code>
```

Check / revoke:

```bash theme={null}
opensre messaging status -p slack
opensre messaging revoke -p slack -u U0123ABCD
```

### Start the gateway daemon

```bash theme={null}
opensre gateway start
opensre gateway status
# want: slack: connected via socket mode
```

| Command                   | What it does                                       |
| ------------------------- | -------------------------------------------------- |
| `opensre gateway start`   | Start the daemon (web, Telegram, Slack, scheduler) |
| `opensre gateway status`  | Show daemon and component state                    |
| `opensre gateway logs -f` | Follow live gateway logs                           |
| `opensre gateway stop`    | Stop the daemon                                    |

Built-in chat commands: `/new` (fresh session), `/help`, `/pair <code>`.

While a turn runs, the gateway adds an 👀 (`eyes`) reaction on the inbound
message, then swaps to ✅ (`white_check_mark`) when the reply is finalized.

If Slack is not configured the daemon still runs the other components and
`opensre gateway status` shows `slack: not configured`.

### Deploying the Slack gateway

The Slack gateway backend is deployed and operated separately — not from this
repo. Configure the integration here (tokens and scopes above); provisioning the
hosted backend is out of scope for this repo.

The EC2 gateway path (`make deploy-gateway`) is **Telegram-only** and
ignore `SLACK_*` variables with a validation warning: Slack Socket Mode is
single-consumer, so a second gateway holding the same tokens would split events.

***

## Environment variables

| Variable                     | Description                                                                                 |
| ---------------------------- | ------------------------------------------------------------------------------------------- |
| `SLACK_WEBHOOK_URL`          | Incoming webhook URL. Required for outbound delivery.                                       |
| `SLACK_BOT_TOKEN`            | Bot token (`xoxb-…`) for the two-way Slack bot. Env or integration store.                   |
| `SLACK_APP_TOKEN`            | App-level token (`xapp-…`) for Socket Mode. Env or integration store.                       |
| `SLACK_ALLOWED_USERS`        | Comma-separated Slack user IDs allowed to talk to the bot (required unless open workspace). |
| `SLACK_ALLOW_OPEN_WORKSPACE` | Set to `1` to allow any workspace member (dogfood escape hatch).                            |

***

## Troubleshooting

**`error: webhook_url is required.` from `opensre integrations setup slack`**

You chose webhook (or both) and left the URL empty. Re-run and paste the full URL including the `https://` prefix, or choose Socket Mode only.

**`slack: not configured` from `opensre gateway status`**

Missing `SLACK_BOT_TOKEN` / `SLACK_APP_TOKEN` (env or store) or empty allowlist without `SLACK_ALLOW_OPEN_WORKSPACE=1`. Run `opensre messaging allow -p slack -u <U…>` then `gateway stop` / `start`.

**Connected, but deny reply**

Your `U…` is not in `SLACK_ALLOWED_USERS` / store allowlist. Pair with `/pair <code>` after `opensre messaging pair -p slack`, or add yourself with `messaging allow`.

**`invalid_payload` or `channel_not_found` from Slack**

The webhook URL was created against a channel that has since been archived or renamed in a way that broke the binding. Create a new webhook in the Slack app settings and replace `SLACK_WEBHOOK_URL`.

**Findings posted to the wrong channel**

A webhook is bound to the channel it was created against. To change channels, create a new webhook in Slack pointed at the new channel and update `SLACK_WEBHOOK_URL`.

**Webhook returns `no_service`**

The Slack app or webhook was deleted. Re-create it and update the URL.
