Slack Integration — Self-Hosted
Self-hosted RunWhen deployments connect Slack through the in-cluster slackbot service. You create a dedicated Slack app in your Slack workspace, expose it at https://slack.<domain>, and supply the app’s OAuth credentials to the runwhen-platform Helm chart.
This guide covers the platform-operator path. End-user install and day-to-day use (DMs, @mentions, /runwhen settings) are the same as on RunWhen SaaS — see the Setup Guide after the platform side is configured.
Slack is optional. The chart always deploys slackbot, but it stays idle until you create an app, wire credentials, and complete OAuth.
SaaS vs self-hosted
| Model | Who creates the Slack app | Where credentials live |
|---|---|---|
| RunWhen SaaS | RunWhen | RunWhen-operated secrets; users click Connect in the UI |
| Self-hosted | You (Slack workspace admin) | Your Helm values or a Kubernetes Secret you manage |
See Self-Hosted Deployment Requirements for cluster, DNS, TLS, and registry prerequisites before configuring Slack.
How the chart exposes slackbot
| Item | Value |
|---|---|
| Public URL (Slack → platform) | https://slack.<domain> (override: ingress.services.slack.host) |
| Kubernetes Service | <release>-slackbot:8000 |
| OAuth redirect | https://slack.<domain>/oauth_redirect |
| Event / interactivity URL | https://slack.<domain>/runwhen |
| UI install entry | https://app.<domain> → Connect Slack, or browse to https://slack.<domain>/install |
Replace <domain> with your global.domain Helm value everywhere below. If you set a custom ingress.services.slack.host, use that host instead — the Slack app URLs must match exactly.
Prerequisites
- Public DNS and TLS for
slack.<domain>, reachable by Slack’s servers over HTTPS. Slack validates the Event Subscriptions request URL from the public internet — this does not work on a fully air-gapped cluster. - Public DNS and TLS for
app.<domain>(the OAuth flow redirects the browser back here to link the Slack workspace to a RunWhen workspace). - Slack workspace admin access to create and install the app.
Step 1 — Create the Slack app from a manifest
The fastest path is api.slack.com/apps → Create New App → From an app manifest → YAML.
Paste the manifest below, replacing <domain> with your platform domain (for example acme.example.com):
display_information: name: RunWhen description: | Connect Slack to RunWhen. AI Assistants answer in DMs and @mentions. /runwhen: help or settings only. background_color: "#737373"features: app_home: home_tab_enabled: true messages_tab_enabled: true messages_tab_read_only_enabled: false bot_user: display_name: RunWhen always_online: false slash_commands: - command: /runwhen url: https://slack.<domain>/runwhen description: "Help and settings: workspace defaults, AI Assistants, channel mapping. Chat via DM or @mention." usage_hint: "[help | settings] — chat by DM or @mention, not via this command" should_escape: falseoauth_config: redirect_urls: - https://slack.<domain>/oauth_redirect scopes: bot: - app_mentions:read - assistant:write - channels:read - channels:history - channels:write.invites - chat:write - chat:write.customize - commands - groups:read - groups:history - groups:write.invites - im:read - im:history - im:write.invites - mpim:read - mpim:history - mpim:write.invites - team:read - users:read - users:read.email pkce_enabled: falsesettings: event_subscriptions: request_url: https://slack.<domain>/runwhen bot_events: - app_home_opened - app_mention - assistant_thread_started - assistant_thread_context_changed - channel_rename - member_joined_channel - message.channels - message.groups - message.im - message.mpim interactivity: is_enabled: true request_url: https://slack.<domain>/runwhen org_deploy_enabled: false socket_mode_enabled: false token_rotation_enabled: false is_mcp_enabled: falseThe platform does not use Socket Mode or an app-level token. All traffic runs over public HTTPS request URLs, so
slack.<domain>must be internet-reachable before Slack accepts the Event Subscriptions URL.
Environment-specific slash commands
When several self-hosted environments share one Slack workspace, give each environment a distinct slash command (for example /runwhen-staging, /runwhen-prod). Change the command field in the manifest and set the matching Helm value:
slack: slashCommand: runwhen-staging # without the leading /The request URL path stays /runwhen on the platform — only the command name in Slack differs.
Step 2 — Manual reference (if not using a manifest)
If you configure the app by hand, set these on the Slack app settings pages:
OAuth & Permissions
| Setting | Value |
|---|---|
| Redirect URL | https://slack.<domain>/oauth_redirect |
| Bot Token Scopes | app_mentions:read, assistant:write, channels:read, channels:history, channels:write.invites, chat:write, chat:write.customize, commands, groups:read, groups:history, groups:write.invites, im:read, im:history, im:write.invites, mpim:read, mpim:history, mpim:write.invites, team:read, users:read, users:read.email |
| User Token Scopes | none |
Event Subscriptions
| Setting | Value |
|---|---|
| Request URL | https://slack.<domain>/runwhen |
| Bot events | app_home_opened, app_mention, assistant_thread_started, assistant_thread_context_changed, channel_rename, member_joined_channel, message.channels, message.groups, message.im, message.mpim |
Slash Commands
| Command | Request URL |
|---|---|
/runwhen (or your custom name) | https://slack.<domain>/runwhen |
Interactivity & Shortcuts
Enabled, Request URL: https://slack.<domain>/runwhen
App Home
Enable the Home tab and Messages tab. Allow users to send messages from the Messages tab (required for the DM experience).
Step 3 — Feed credentials into Helm
From the Slack app’s Basic Information and OAuth & Permissions pages, copy three values into your Helm overlay:
| Slack app value | Helm value | Rendered env var |
|---|---|---|
| Signing Secret | secrets.values.slackSigningSecret | SLACK_SIGNING_SECRET |
| Client ID | secrets.values.slackClientId | SLACK_CLIENT_ID |
| Client Secret | secrets.values.slackClientSecret | SLACK_CLIENT_SECRET |
slack: existingSecret: "" # or rw-slack-credentials for BYO Secret (recommended) slashCommand: runwhen # must match the command in your Slack app manifestsecrets: method: "k8s-secret" values: slackSigningSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" slackClientId: "1234567890.1234567890" slackClientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Encrypts OAuth install payloads. Auto-generated when empty on chart 0.2.20+. fernetKey: ""Do not commit plaintext secrets. Inject at deploy time (for example
--set secrets.values.slackClientSecret="$SLACK_CLIENT_SECRET") or use the BYO Secret path below.
BYO Secret (recommended for production)
Keep Slack credentials in an operator-managed Secret:
kubectl create secret generic rw-slack-credentials -n <namespace> \ --from-literal=SLACK_SIGNING_SECRET='...' \ --from-literal=SLACK_CLIENT_ID='...' \ --from-literal=SLACK_CLIENT_SECRET='...'slack: existingSecret: rw-slack-credentialsWhen slack.existingSecret is set, the chart does not write those keys to platform-secrets; backend pods load your Secret instead.
You do not put a bot token in Helm. The per-workspace bot token is minted during OAuth install (Step 4) and stored in Vault automatically.
URL wiring (automatic)
SLACKBOT_URL and SLACKBOT_INTERNAL_URL are derived by the chart from your ingress host — no manual env vars unless you override ingress.services.slack.host.
Step 4 — Deploy and connect a workspace
- Deploy or upgrade the chart with the credentials from Step 3.
- Confirm slackbot is healthy:
Terminal window kubectl rollout status deploy/<release>-slackbot -n <namespace>kubectl logs deploy/<release>-slackbot -n <namespace> - From
https://app.<domain>, use Connect Slack (or openhttps://slack.<domain>/install) and click Add to Slack. - Approve the OAuth scopes. Slack redirects to
https://slack.<domain>/oauth_redirect; the bot token is stored in Vault; your browser returns tohttps://app.<domain>to finish linking the Slack workspace to a RunWhen workspace. - Complete user-facing setup: Slack Setup Guide — Parts 2 and 3.
Verify
- In Slack, run
/runwhen settings(or your custom command) and confirm workspace and AI Assistant selection. - DM the bot or @mention it in a channel — you should get a response.
- The App Home tab should render when opened.
Known limitations
| Limitation | Details |
|---|---|
| Token refresh | Scheduled Slack token refresh is not active yet. Keep token_rotation_enabled: false in the manifest until a future chart release enables it. |
| No disable toggle | The slackbot workload and ingress are always rendered. To fully disable, scale the deployment to zero and remove the slack ingress host. |
| Air-gap | OAuth and event delivery require public reachability to and from slack.com. Slack is effectively unavailable in air-gapped installs. |
For product-level Slack behavior (thread ownership, rich-content handoff, context window), see Slack Integration Overview — Current Limitations.
Troubleshooting
| Symptom | Resolution |
|---|---|
| Slack rejects Event Subscriptions URL | Confirm https://slack.<domain>/runwhen is publicly reachable with a valid TLS certificate |
| OAuth redirect mismatch | Redirect URL in the Slack app must exactly match https://slack.<domain>/oauth_redirect |
/runwhen unknown in Slack | Command name in the Slack app must match slack.slashCommand in Helm |
| Install succeeds but bot is silent | Complete Setup Guide Part 3 — select workspace and AI Assistant |
ValueError: Fernet key must be 32 url-safe base64-encoded bytes | Set secrets.values.fernetKey explicitly or upgrade to chart 0.2.20+ (auto-generates a stable key) |
Related pages
- Slack Integration Overview — features, capabilities, and limitations
- Slack Setup Guide — end-user install and configuration in Slack
- Self-Hosted Deployment Requirements — cluster, DNS, TLS, and registry prerequisites
- Workspace Chat — AI Assistant capabilities available through Slack