Slack

The Omnigent Slack integration lets your team talk to agents directly from Slack. Mention the bot in a channel or DM it, and it starts an Omnigent session; replies stream into the thread live, and tool approvals show up as interactive Approve / Deny cards you can answer in place.

The core model is simple: one Slack thread ↔ one Omnigent session. Replying in a thread continues the same session; a new mention starts a new one.

The bot connects to a single Omnigent server chosen by the operator — users never enter a server URL. Each user still authenticates as their own Omnigent identity, so sessions run with per-user permissions and no shared credential ever passes through Slack.

What you can do

Setting it up (operator)

The bot is a Socket Mode Slack app — it opens an outbound WebSocket to Slack, so it needs no public HTTP endpoint and no request URLs.

1. Create the Slack app

  1. Create a Slack app with Socket Mode and Interactivity enabled (Socket Mode also delivers the button/modal payloads — no request URL needed).
  2. Add the OAuth scopes and event subscriptions listed below.
  3. Add a slash command /omnigent (Features → Slash Commands). In Socket Mode the request URL is ignored, so any placeholder works.
  4. Install the app into your workspace.

2. Grant scopes

Bot token scopes (OAuth & Permissions → Bot Token Scopes) — all required:

ScopeWhy
app_mentions:readReceive @mentions — how the bot joins a channel thread.
chat:writePost, delete, and stream replies (including ephemeral nudges).
im:writeOpen a DM to send the setup button and logout confirmation.
im:historyRead DMs — DMs are a first-class entry point.
commandsRegister and receive /omnigent.
team:readRead the workspace name to label the login request.

Add two more bot scopes only for Databricks web-auth mode, where the bot signs the user's email into the enrollment link and matches it against the OAuth-authenticated identity; omit them in accounts / oidc mode:

ScopeWhy
users:readRead the user's profile to look up their email.
users:read.emailRead the user's email address for identity binding.

Channel history scopes — add only for the channel types where the bot will run: channels:history (public), groups:history (private), mpim:history (group DMs). If you only use DMs and channel @mentions, you can omit all three.

App-level token scope: connections:write (required for the Socket Mode connection).

Event subscriptions (Subscribe to bot events): app_mention, message.im, and message.channels / message.groups / message.mpim for the channel types you enabled above.

3. Install and configure the bot

The bot ships as the slack extra of Omnigent (the separate omnigent-slack package), installed in the same environment as the omni CLI so omni integration slack can find it:

uv tool install "omnigent[slack]"    # or, from a source checkout: uv sync --extra slack

Configuration comes from real environment variables — the bot does not read a .env file itself (matching omni server). Export the variables directly, or launch the bot under a tool that injects a .env (e.g. uv run --env-file .env omni integration slack). .env.example documents the full set to copy from:

VariableRequiredPurpose
OMNIGENT_SLACK_BOT_TOKENYesThe bot token (xoxb-…).
OMNIGENT_SLACK_APP_TOKENYesThe app-level token (xapp-…) for Socket Mode.
OMNIGENT_SERVER_URLYesThe one Omnigent server the bot talks to.
OMNIGENT_DEVICE_CLIENT_SECRETNoSet to the same value as the server's OMNIGENT_DEVICE_CLIENT_SECRET so only this bot can drive the device-grant login. Accounts mode only.
OMNIGENT_SLACK_TOKEN_ENCRYPTION_KEYNoA Fernet key that encrypts users' delegated tokens at rest. Without it, tokens live in memory only and users re-authenticate after a restart.
OMNIGENT_SLACK_DATABASE_PATHNoWhere the bot's SQLite store lives. Defaults to $OMNIGENT_DATA_DIR/omnigent_slack.sqlite3 (or ~/.omnigent/omnigent_slack.sqlite3).
LOG_LEVELNoSet to DEBUG when diagnosing why Slack events aren't producing replies.

Generate an encryption key with:

uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"

If the Omnigent server runs as a Databricks App (header/proxy auth), the bot uses its own Databricks web-auth flow instead of the device/OIDC login — see Databricks Apps web-auth below for the extra OMNIGENT_SLACK_DATABRICKS_* variables it needs.

4. Run it

The bot runs as a background daemon managed by the omni CLI:

omni integration slack               # run in the foreground (Ctrl-C to stop)
omni integration slack --background  # run in the background (detached)
omni integration slack status        # is the background bot running?
omni integration slack stop          # stop the background bot
omni integration slack logs          # print the log path
omni integration slack logs -f       # follow the log

Running --background while the bot is already up is a no-op that reports the existing process. A foreground run refuses to start if a background daemon already holds the socket (stop it first).

Per-user setup

The first time someone interacts with the bot without having configured it, the bot DMs them a Set up Omnigent button. The button opens a modal that:

  1. Validates connectivity to the operator's server, and — if the server has authentication enabled — walks the user through login (see below).
  2. Lets them pick an agent and host (both required, populated from the server) and a workspace path — the absolute directory on the host where each session's runner starts. It defaults to the host's home directory.

The choice is saved per (Slack workspace, user). Run /omnigent any time to change agent, host, or workspace, and /omnigent logout to revoke your token and clear all saved settings.

Each new session launches a fresh runner on the chosen host, rooted at the configured workspace.

Authentication

For servers with authentication enabled, each Slack user logs in with their own Omnigent identity inside the /omnigent modal. The bot auto-detects the server's auth mode and picks the matching flow:

Tokens are stored encrypted at rest when OMNIGENT_SLACK_TOKEN_ENCRYPTION_KEY is set; otherwise they're kept in memory only and lost on restart (users simply re-authenticate).

Databricks Apps web-auth

When the Omnigent server is a Databricks App, its proxy authenticates every request and injects the user's identity — a Socket-Mode event carries no such proxy-authenticated request, so the device/OIDC flows can't be driven. Instead the bot runs a custom U2M OAuth app (authorization code + PKCE, offline_access) through an enrollment page it serves as its own Databricks App:

  1. On /omnigent, the bot looks up the user's email, generates a PKCE verifier and single-use nonce, and posts a Sign in with Databricks link to the workspace /oidc/v1/authorize.
  2. The user signs in; Databricks redirects back to the bot's /auth/callback with a single-use, PKCE-bound code, which the bot exchanges for an access + refresh token pair.
  3. Identity binding — the callback requires the OAuth-authenticated email to equal the Slack email signed into the link, so a link bound to one user can't store another's token. A mismatch is refused.
  4. Confirm before storing — the callback shows a consent page naming the exact identities being linked; the token is persisted only when the user submits the confirming button, then the setup modal advances automatically.

The bot presents the access token to the server; the proxy validates it and injects the real identity header, so no server-side change is needed. It refreshes silently, so the user signs in once, not hourly.

Enable it with OMNIGENT_SLACK_SERVER_AUTH=databricks plus these variables:

VariableRequiredPurpose
OMNIGENT_SLACK_DATABRICKS_CLIENT_IDYesThe custom U2M OAuth app's client id (public).
OMNIGENT_SLACK_DATABRICKS_CLIENT_SECRETYesThe custom U2M OAuth app's client secret.
OMNIGENT_SLACK_DATABRICKS_STATE_SECRETYesHMAC key signing the enrollment state (≥32 chars of entropy, e.g. openssl rand -hex 32). Its own secret, separate from the OAuth client secret.
OMNIGENT_SLACK_DATABRICKS_APP_URLYes¹Public base URL of the bot's own Databricks App — the enrollment link base and OAuth redirect base. Not platform-injected, and the URL only exists after the first deploy, so it's wired in on a second deploy pass.
OMNIGENT_SLACK_DATABRICKS_SCOPESNoRequested scopes (space-separated). Defaults to all-apis; must be a superset of the server app's scopes. openid + offline_access are always added.

¹ Not enforced at startup — the bot boots without it, but no enrollment link is issued until it's set. The enrollment web server always binds DATABRICKS_APP_PORT (8000 by convention, platform-injected); there's no override knob.

Register the custom OAuth app's redirect URI as <app-url>/auth/callback. To deploy the bot as its own Databricks App, see integrations/slack/deploy/databricks/README.md in the repo.

Approvals and questions

When the agent needs you — a tool-call approval or a multiple-choice question — it appears in the thread:

Cards are visible to the whole channel, but only the thread owner can act on them. Answering from the web UI works too: the card in Slack finalizes automatically once the request is resolved anywhere.

Sharing a channel with your team

Slack channels are multi-user, so the bot enforces a per-thread owner model: a thread belongs to whoever started it. If someone else replies in your thread, they get a private note pointing them to start their own thread — they are never added to your session.

If you message a thread while the bot is still replying, it privately asks you to wait (or continue in the web UI). A message to an idle thread just continues the conversation.

Supported and not supported

Supported

Not supported

Troubleshooting