# Slack Integration

Visor provides bidirectional Slack integration through Socket Mode, enabling interactive workflows, human input collection, real-time notifications, and AI-powered chat assistants directly in Slack threads.

## Table of Contents

- [Overview](#overview)
- [Prerequisites](#prerequisites)
- [Configuration](#configuration)
- [Features](#features)
- [Example Workflows](#example-workflows)
- [Message Triggers](#message-triggers)
- [Troubleshooting](#troubleshooting)
- [Related Documentation](#related-documentation)

## Overview

The Slack integration enables:

- **Bidirectional Communication**: Receive messages from Slack threads and post AI-generated responses back
- **Human Input Collection**: Pause workflows to wait for user input via Slack messages
- **Conversation Context**: Access full thread history for context-aware AI responses
- **Mermaid Diagram Rendering**: Automatically render mermaid diagrams to PNG and upload to Slack
- **Reaction Management**: Visual acknowledgement (eyes) and completion (thumbsup) reactions
- **Rate Limiting**: Protect against abuse with configurable rate limits per user, channel, or globally
- **Thread Caching**: Efficient conversation history retrieval with TTL-based caching

## Prerequisites

### Slack App Setup

1. **Create a Slack App** at https://api.slack.com/apps

2. **Enable Socket Mode**:
   - Navigate to "Socket Mode" in the sidebar
   - Toggle "Enable Socket Mode" to On
   - Generate an App-Level Token with `connections:write` scope
   - Save the token (starts with `xapp-`)

3. **Configure Bot Token Scopes** under "OAuth & Permissions":
   ```
   app_mentions:read      - Receive @mentions
   channels:history       - Read messages in public channels
   channels:read          - View basic channel info
   chat:write             - Send messages
   files:write            - Upload diagram images
   groups:history         - Read messages in private channels
   groups:read            - View basic private channel info
   im:history             - Read DM messages
   im:read                - View basic DM info
   mpim:history           - Read group DM messages
   mpim:read              - View basic group DM info
   reactions:read         - View reactions
   reactions:write        - Add/remove reactions
   users:read             - View user info
   ```

4. **Enable Event Subscriptions**:
   - Navigate to "Event Subscriptions"
   - Toggle "Enable Events" to On
   - Subscribe to bot events:
     - `app_mention` - When someone mentions your bot
     - `message.channels` - Messages in public channels (optional)
     - `message.groups` - Messages in private channels (optional)
     - `message.im` - Direct messages (optional)
     - `message.mpim` - Group DMs (optional)

5. **Install to Workspace**:
   - Navigate to "Install App"
   - Click "Install to Workspace"
   - Save the Bot User OAuth Token (starts with `xoxb-`)

### Environment Variables

```bash
# Required for Socket Mode
export SLACK_APP_TOKEN="xapp-..."   # App-level token for Socket Mode
export SLACK_BOT_TOKEN="xoxb-..."   # Bot user OAuth token
```

## Configuration

### CLI Flag

Enable Slack Socket Mode runner with the `--slack` flag:

```bash
visor --config workflow.yaml --slack
```

### Environment Variables

| Variable | Description | Required |
|----------|-------------|----------|
| `SLACK_APP_TOKEN` | App-level token for Socket Mode (xapp-...) | Yes |
| `SLACK_BOT_TOKEN` | Bot user OAuth token (xoxb-...) | Yes |

### Configuration File

Add Slack-specific configuration in your workflow YAML:

```yaml
version: "1.0"

# Slack runtime configuration
slack:
  version: "v1"
  mentions: all           # 'direct' (only @mentions) or 'all' (DMs too)
  threads: required       # 'required' or 'any'
  channel_allowlist:      # Optional: limit to specific channels
    - C12345678
    - CENG*               # Wildcard prefix matching
  show_raw_output: false  # Set true to post raw JSON (debugging)

  # Optional: customize reaction names
  reactions:
    enabled: true
    ack: eyes             # Acknowledgement reaction
    done: thumbsup        # Completion reaction

  # Optional: allow bot_message events (default: false)
  # When true, messages posted by other bots can trigger runs (still subject
  # to mention/threads/channel allowlist gating).
  allow_bot_messages: false

  # Optional: allow guest users (default: false)
  # When false, single-channel and multi-channel guests are ignored.
  # Set to true to allow guest users to interact with the bot.
  allow_guests: false

  # Optional: rate limiting
  rate_limiting:
    enabled: true
    user:
      requests_per_minute: 10
      requests_per_hour: 100
    channel:
      requests_per_minute: 30
    global:
      concurrent_requests: 5

  # Optional: conversation fetching
  fetch:
    scope: thread
    max_messages: 40
    cache:
      max_threads: 200
      ttl_seconds: 600

# Frontend configuration for posting to Slack
frontends:
  - name: slack
    config:
      defaultChannel: C12345678
      groupChannels:
        overview: C87654321
        review: C11111111

checks:
  # Your workflow checks...
```

### Slack Configuration Options

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `version` | string | `"v1"` | API version identifier |
| `mentions` | string | `"direct"` | `"direct"` for @mentions only, `"all"` for DMs too |
| `threads` | string | `"any"` | `"required"` to only respond in threads |
| `channel_allowlist` | string[] | `[]` | Limit to specific channels (supports `*` wildcard) |
| `allow_bot_messages` | boolean | `false` | Allow `bot_message` events to trigger runs |
| `allow_guests` | boolean | `false` | Allow guest users (single/multi-channel) to trigger runs |
| `show_raw_output` | boolean | `false` | Post raw JSON output (for debugging) |
| `reactions.enabled` | boolean | `true` | Enable reaction management |
| `reactions.ack` | string | `"eyes"` | Reaction name for acknowledgement |
| `reactions.done` | string | `"thumbsup"` | Reaction name for completion |

### Rate Limiting Options

```yaml
slack:
  rate_limiting:
    enabled: true
    bot:                          # Per-bot limits
      requests_per_minute: 60
      requests_per_hour: 1000
      concurrent_requests: 10
    user:                         # Per-user limits
      requests_per_minute: 10
      requests_per_hour: 100
    channel:                      # Per-channel limits
      requests_per_minute: 30
    global:                       # Global limits
      concurrent_requests: 5
    actions:
      send_ephemeral_message: true
      ephemeral_message: "Rate limit reached. Please wait."
      queue_when_near_limit: false
      queue_threshold: 0.8
```

## Features

### Message Posting and Threading

The Slack frontend automatically posts AI responses to the originating thread:

- AI check outputs with `text` fields are posted as thread replies
- Messages are formatted using Slack's mrkdwn syntax
- Markdown links, bold, italic, and headers are converted appropriately

```yaml
checks:
  reply:
    type: ai
    group: chat
    schema:
      type: object
      properties:
        text:
          type: string
      required: [text]
    prompt: |
      Reply to the user's question.
```

### Reaction Management

The frontend manages reactions for visual feedback:

1. **Acknowledgement** (eyes emoji): Added when a check is scheduled
2. **Completion** (thumbsup emoji): Replaces acknowledgement when workflow completes

Configure custom reactions:

```yaml
slack:
  reactions:
    enabled: true
    ack: hourglass_flowing_sand
    done: white_check_mark
```

### Mermaid Diagram Rendering

Mermaid diagrams in AI responses are automatically:

1. Detected from ```mermaid code blocks
2. Rendered to PNG using @mermaid-js/mermaid-cli
3. Uploaded to the Slack thread as images
4. Replaced with "_(See diagram above)_" placeholder in text

Requirements for diagram rendering:
- Node.js and npx in PATH
- Puppeteer/Chromium dependencies
- On Linux: `apt-get install chromium-browser libatk-bridge2.0-0 libgtk-3-0`

Example AI response that includes a diagram:

```yaml
checks:
  explain-architecture:
    type: ai
    prompt: |
      Explain the system architecture with a diagram.

      Include a mermaid flowchart showing the data flow.
```

### Human Input Prompts

The `human-input` check type integrates with Slack for interactive workflows:

```yaml
checks:
  ask:
    type: human-input
    group: chat
    prompt: |
      What would you like to know?
```

Behavior in Slack:
- First message in a thread is consumed as the initial input
- Subsequent messages resume the workflow from its saved snapshot
- The prompt text is registered internally but not posted (to avoid spam)

### Conversation Context

Access full thread history in your prompts:

```yaml
checks:
  context-aware-reply:
    type: ai
    prompt: |
      Thread context:
      {% if slack.conversation %}
      {% for m in slack.conversation.messages %}
      - [{{ m.user }}] {{ m.text }}
      {% endfor %}
      {% endif %}

      Respond based on the conversation above.
```

Or use the `chat_history` filter for merged history:

```yaml
checks:
  reply:
    type: ai
    prompt: |
      Conversation so far:
      {% assign history = '' | chat_history: 'ask', 'reply' %}
      {% for m in history %}
      {{ m.role | capitalize }}: {{ m.text }}
      {% endfor %}

      Latest message: {{ outputs['ask'].text }}
```

### Markdown to Slack Conversion

The integration automatically converts Markdown to Slack mrkdwn:

| Markdown | Slack mrkdwn |
|----------|--------------|
| `# Header` | `*Header*` |
| `**bold**` | `*bold*` |
| `[label](url)` | `<url\|label>` |
| `![alt](url)` | `<url\|alt>` |
| `- item` | `bullet item` |
| ` ```code``` ` | Preserved as-is |

## Example Workflows

### Simple Chat Assistant

See [examples/slack-simple-chat.yaml](../examples/slack-simple-chat.yaml) for a complete example with:

- Intent routing (chat, FAQ, project help, thread summary)
- Nested sub-flows with inner loops
- Conversation history management
- External integration mocks

Basic chat loop:

```yaml
version: "1.0"

slack:
  mentions: all
  threads: required

frontends:
  - name: slack

checks:
  ask:
    type: human-input
    group: chat
    prompt: |
      Hi! What can I help you with?

  reply:
    type: ai
    group: chat
    depends_on: ask
    schema:
      type: object
      properties:
        text:
          type: string
      required: [text]
    ai:
      disableTools: true
      system_prompt: "You are a helpful assistant."
    prompt: |
      Conversation:
      {% assign history = '' | chat_history: 'ask', 'reply' %}
      {% for m in history %}
      {{ m.role | capitalize }}: {{ m.text }}
      {% endfor %}

      Latest: {{ outputs['ask'].text }}

      Reply briefly.
    on_success:
      goto: ask
```

### Running the Slack Bot

```bash
# Set environment variables
export SLACK_APP_TOKEN="xapp-..."
export SLACK_BOT_TOKEN="xoxb-..."

# Optional: enable debug logging
export VISOR_DEBUG=true

# Start the bot
visor --config examples/slack-simple-chat.yaml --slack
```

The bot will:
1. Connect via Socket Mode
2. Listen for @mentions and DMs (depending on `mentions` setting)
3. Process messages through your workflow
4. Post responses back to the thread

## Troubleshooting

### Connection Issues

**"SLACK_APP_TOKEN (xapp-...) is required for Socket Mode"**
- Ensure `SLACK_APP_TOKEN` environment variable is set
- Verify the token starts with `xapp-`

**"apps.connections.open failed"**
- Check that Socket Mode is enabled in your Slack app settings
- Verify the App-Level Token has `connections:write` scope
- Ensure the token has not been revoked

### Message Handling Issues

**Bot not responding to messages**
- Verify the bot is invited to the channel
- Check `channel_allowlist` if configured
- Ensure `mentions` setting matches your use case:
  - Use `mentions: direct` for @mentions only
  - Use `mentions: all` to respond to DMs

**Bot responding multiple times**
- The deduplication system handles this automatically
- If issues persist, check for multiple bot instances running

**Messages not appearing in thread**
- Verify `SLACK_BOT_TOKEN` has `chat:write` scope
- Check that the bot is a member of the channel
- Review logs for API errors

### Diagram Rendering Issues

**"Mermaid rendering failed"**
- Install mermaid-cli: `npm install -g @mermaid-js/mermaid-cli`
- On Linux, install Chromium dependencies:
  ```bash
  apt-get install chromium-browser libatk-bridge2.0-0 libgtk-3-0
  ```
- Check that `npx` is available in PATH

### Rate Limiting

**"Rate limited" messages in logs**
- Review and adjust rate limit configuration
- Consider increasing limits for legitimate high-volume usage
- Check which dimension is triggering (`bot`, `user`, `channel`, `global`)

### Debug Mode

Enable verbose logging for troubleshooting:

```bash
# Via environment variable
VISOR_DEBUG=true visor --config workflow.yaml --slack

# Or via CLI flag
visor --config workflow.yaml --slack --debug
```

Log messages include:
- `[SlackSocket]` - WebSocket connection and event handling
- `[slack-frontend]` - Message posting and reactions
- `[prompt-state]` - Human input state management

## Message Triggers

Message triggers allow Visor to react to Slack messages in specific channels without requiring an @mention. This is configured via `scheduler.on_message` and is ideal for monitoring bot notifications (e.g., CI/CD failures, deployment alerts).

### Quick Example

```yaml
scheduler:
  on_message:
    cicd-watcher:
      channels: ["C0CICD"]
      from_bots: true
      contains: ["failed", "error"]
      workflow: handle-cicd-failure

steps:
  handle-cicd-failure:
    type: ai
    on: [slack_message]
    prompt: "Analyze this CI/CD failure and suggest a fix."
```

When a message matching the filters appears in the specified channel, Visor dispatches the configured workflow asynchronously. The workflow receives the full Slack event context including message text, sender, channel, and thread conversation history (for thread replies).

### Key Features

- **No @mention required**: Triggers fire based on message content, channel, user, and thread scope
- **Bot message support**: Set `from_bots: true` to react to messages from other bots (CI systems, monitoring tools)
- **Coexists with @mention path**: A message can trigger both a message trigger workflow and the normal @mention-based dispatch
- **Hot reload**: Trigger configuration is rebuilt on config hot-reload without restarting the bot
- **Deduplication**: Built-in dedup prevents duplicate workflow dispatches for the same Slack event

### Filter Options

| Filter | Description |
|--------|-------------|
| `channels` | Channel IDs (wildcard suffix supported, e.g., `CENG*`) |
| `from` | Specific user IDs |
| `from_bots` | Allow bot messages (default: false) |
| `contains` | Keyword match (case-insensitive, any = match) |
| `match` | Regex pattern |
| `threads` | `root_only`, `thread_only`, or `any` (default) |

All specified filters must pass (AND). Within `contains`, any keyword suffices (OR). Omitted filters match everything.

See [Scheduler - Message Triggers](./scheduler.md#message-triggers-on_message) for complete configuration reference.

## Scheduled Reminders

The scheduler integrates with Slack to deliver scheduled reminders and workflow results. See [Scheduler](./scheduler.md) for full documentation.

Quick example:
```
User: "remind me to check PRs every day at 9am"
Bot: Schedule created! Will remind you every day at 9am.
```

When the schedule fires:
1. For simple reminders: The text runs through the visor pipeline, and the AI response is posted back
2. For workflow schedules: The workflow executes and results are posted via `SlackOutputAdapter`

## Related Documentation

- [Scheduler](./scheduler.md) - Schedule workflows and reminders
- [Human Input Provider](./human-input-provider.md) - Detailed documentation on the `human-input` check type
- [Bot Transports RFC](./bot-transports-rfc.md) - Technical design document for Slack integration
- [Recipes](./recipes.md) - Common workflow patterns including chat loops
- [Liquid Templates](./liquid-templates.md) - Template syntax for prompts including `chat_history`
- [Output History](./output-history.md) - Working with workflow output history

## See Also

- [examples/slack-simple-chat.yaml](../examples/slack-simple-chat.yaml) - Complete Slack chat assistant example
