<!--
Sitemap:
- [Installation](/installation)
- [Upgrading](/upgrading): Version-specific steps for upgrading an existing Bento install.
- [Concepts](/concepts)
- [Build your first pipeline](/tutorials/pipeline-args)
- [Target a specific issue or PR from a URL](/tutorials/url-targeting)
- [Keep state across runs](/tutorials/pipeline-state)
- [Fire a pipeline on a schedule or on demand](/tutorials/schedule-and-fire)
- [Deploy a box to Railway](/tutorials/deploy-to-railway)
- [Operate a hosted daemon](/tutorials/operate-a-hosted-daemon)
- [Configuration](/configuration)
- [Members](/members)
- [Knowledge base](/knowledge-base/)
- [Method and delivery](/knowledge-base/modes)
- [Config](/knowledge-base/config)
- [MCP](/knowledge-base/mcp)
- [Pipeline configuration reference](/pipelines/config)
- [Filters](/pipelines/filters)
- [Triggers](/triggers/)
- [GitHub trigger](/triggers/github)
- [Linear trigger](/triggers/linear)
- [Webhook trigger](/triggers/webhook)
- [Schedule trigger](/triggers/schedule)
- [Manual trigger](/triggers/manual)
- [Traces](/pipelines/traces)
- [Slack](/integrations/slack)
- [Public access](/public-access)
- [Context engineering](/context-engineering)
- [Best practices](/best-practices)
- [Troubleshooting](/troubleshooting)
- [Architecture](/architecture/vision)
- [Workspaces](/workspaces)
- [Authentication](/authentication)
- [Identity](/identity)
- [Security](/security)
- [References](/references)
- [Changelog](/changelog): Bento release history.
- [CLI reference](/cli/)
- [Setup](/cli/setup)
- [Secrets](/cli/secrets)
- [Lifecycle](/cli/lifecycle)
- [Sandbox image](/cli/image)
- [Sandboxes](/cli/sandbox)
- [Observability](/cli/observability)
- [Diagnostics](/cli/diagnostics)
- [Triggers](/cli/triggers)
- [Workbench](/cli/workbench)
- [Auth](/cli/auth)
- [Knowledge](/cli/knowledge)
- [Evals](/cli/evals)
- [Bento](/index)
- [Runtime wrapper](/architecture/runtime-wrapper)
- [Skill evolve](/architecture/skill-evolve)
-->

# Slack

Project a pipeline result to Slack. The daemon calls the Slack Web API (`chat.postMessage`). You name each bot in config. A pipeline posts by naming one in `outputs.<key>.config`, so different pipelines post as different Slack identities.

The integration is outbound only for terminal projections. The [eval](/pipelines/config#eval) subsystem is the exception: it adds a separate inbound path for button clicks and modal submissions on the bot named `channels.slack.eval_bot` — see [Configuration — Evals (Slack)](/configuration#evals-slack).

## Setup

1. Create a Slack app at [api.slack.com/apps](https://api.slack.com/apps) → **From scratch**, and select your workspace.
2. Under **OAuth & Permissions → Scopes → Bot Token Scopes**, add `chat:write`. To send a direct message to a user (a `U…` target), add `im:write`. To post to a public channel without an invitation, add `chat:write.public`.
3. **Install to Workspace** and copy the **Bot User OAuth Token** (`xoxb-…`).
4. Invite the bot to each target channel: `/invite @your-app`. Private channels always require this. Public channels do too unless the bot has `chat:write.public`.

## Configuration

Name each bot under `channels.slack.bots`. The key is the name pipelines reference. `token` is the bot's `xoxb-…` token (use `${VAR}` to read it from the environment). Add as many bots as you have Slack app identities.

```yaml
channels:
  slack:
    bots:
      teamBot: { token: ${TEAMBOT_TOKEN} }
      alertBot:  { token: ${ALERTBOT_TOKEN} }
```

A pipeline that names a bot with no matching token logs an error and posts nothing.

## Usage

Declare a `slack.message` projection. Its `config` names the `bot` and the `channel`:

```yaml
deploy-notify:
  trigger:
    github:
      - deployment_status
    filter:
      when:
        deployment_status.state: success
  agent: notifier
  instructions: |
    Announce deployment of {{event.deployment.ref}} to {{event.deployment.environment}}.
  result:
    schema:
      type: object
      properties:
        digest:
          $ref: bento://schemas/slack/message/v1
      required: [digest]
  outputs:
    digest:
      handler: slack.message
      config:
        bot: teamBot
        channel: "#deploys"
```

## Channel

The `channel` value selects where the named bot posts:

| Value | Posts to |
|---|---|
| `"#deploys"` | The named public channel. |
| `"C0123456789"` | A channel by id (public or private the bot is in). |
| `"U0123456789"` | A direct message to that user (needs the `im:write` scope). |

## See also

* [Pipeline config — terminal projections](/pipelines/config) — result and handler configuration.
