Verified plugins

Slack

The verified plugin ai.oz0/slack - Slack as the front door to your agents, with answers, questions and approvals in threads.

For: tenant administrators and plugin users.

ai.oz0/slack connects Slack as a chat channel. Mention your Slack app or send /oz0 <request> to start an agent bound to that channel.

The answer, questions and approvals arrive in the thread. Reply there to continue the conversation.

Manifest nameslack (hub name ai.oz0/slack)
Tooloz0_slack: normalize (the event source), post (the channel), send (an agent posts a message)
Event source and channelslack, on POST https://<edge>:7443/events/<tenant>/slack
Tenant secretsSLACK_SIGNING_SECRET (read by the edge only), SLACK_BOT_TOKEN (xoxb-…, saved by Connect or set by hand, which connection slack hands each call that posts or opens a form, for that call only; it is never in the plugin's environment); SLACK_CLIENT_SECRET for Connect
Connectionslack: your own Slack app from a manifest, its credentials pasted and checked, then Slack's OAuth v2 install
Egressslack.com (the Web API) and hooks.slack.com (slash commands' and clicks' response URLs); GovSlack's hosts go on the tenant's egress allowlist

Upgrading to 1.1.0 needs nothing: the same SLACK_BOT_TOKEN now reaches each call through the connection instead of the plugin's environment, and the egress names exact hosts instead of *.slack.com.

Create your own Slack app, about two minutes

Every cluster uses a Slack app of its own, since Slack sends an app's events to one URL and yours go to your edge. Connect makes it from a manifest with your edge's URLs filled in (Connections):

Terminal
oz0 plugin install hub:ai.oz0/slack
oz0 connection start slack --open --wait 15m

Or in the console: Credentials, Connections, slack, Connect. The edge's page for the first step opens:

  1. Create the app on Slack opens Slack's new-app page with the manifest filled in: the app's name (your tenant's plus -oz0, shortened to Slack's 35 characters; --param app_name=... for another), its bot, the /oz0 command, the event subscriptions (app_mention, message.channels, message.groups, message.im) and interactivity, all on https://<edge>/events/<tenant>/slack, the connection's callback as the redirect URL, and the bot scopes app_mentions:read, chat:write, commands, channels:history, groups:history and im:history. Pick the workspace and create it.
  2. From the app's Basic Information, App Credentials, paste the Client ID, the Client Secret and the Signing Secret on the edge's page. The edge checks each one's form, asks Slack's oauth.v2.access whether it knows the Client ID and Client Secret (with a code that is not one, which Slack refuses as invalid_code only for a client it knows), then seals the secrets as SLACK_CLIENT_SECRET and SLACK_SIGNING_SECRET, and never shows them again.
  3. On the app's Event Subscriptions page, click Retry next to the Request URL. Slack sends its URL check again, signed with the signing secret; the edge answers it only if the secret you pasted is the app's, and the page goes on.
  4. Slack asks you to allow the app in your workspace. The edge exchanges the code with the client secret, seals the bot token as SLACK_BOT_TOKEN (management never sees it; the edge hands it to each call that needs it), and checks it with Slack's auth.test.

Then bind the channel and map people:

Terminal
oz0 channel bind helpdesk --channel slack --agent support-triage
oz0 channel member add slack U0123ABCD alice --workspace T0456EFGH

Your Slack user ID is under your profile, Copy member ID; the workspace ID is in the workspace's URL (connection show slack shows it too). Or let people link themselves: each makes a code under Chat channels in the console (or oz0 channel link) and sends link <code> to the app in a direct message or as /oz0 link <code>. Turn on the Messages Tab under App Home so people can write to the app directly. GovSlack: --param slack_url=https://slack-gov.com, and --param apps_url= its app settings page.

If a step does not pass, its page says why; troubleshooting has Slack's usual causes (the URL not verified, a wrong signing secret, missing scopes).

By hand

  1. Create a Slack app for your workspace at Slack's app settings, from scratch.
  2. OAuth & Permissions, bot token scopes: app_mentions:read, chat:write, commands, channels:history, groups:history (to see replies in threads of public and private channels), im:history (direct messages, where people link their identity). Install the app to the workspace and copy the Bot User OAuth Token.
  3. Basic Information: copy the Signing Secret.
  4. Event Subscriptions: on, with the request URL https://<edge>:7443/events/<tenant>/slack. Slack checks it at once; the edge answers its challenge. Subscribe to the bot events app_mention, message.channels, message.groups and message.im, and turn on the Messages Tab under App Home.
  5. Interactivity & Shortcuts: on, with the same URL.
  6. Slash Commands: create /oz0 with the same URL.
Terminal
oz0 secret set SLACK_SIGNING_SECRET --from-file ~/.secrets/slack-signing --signing --host <edge>:7443
oz0 secret set SLACK_BOT_TOKEN --from-file ~/.secrets/slack-bot-token

In Slack

  • @oz0 what broke last night? in a channel the app is in starts the binding's default agent, in a thread on the mention.
  • /oz0 billing why was I charged twice? starts billing when the binding allows it; Slack shows you "On it." and the app posts "you asked billing: …" and starts the thread there.
  • A reply in the thread goes on with the conversation. A reply to an open question answers it.
  • Questions have a button per choice, or Answer, which opens a form (a typed question's fields in a modal). Approvals have Approve and Deny, and Edit and approve opens a modal with the call's fields, where an optional date or choice can be left empty (edit forms per chat); only mapped people with the operator role decide, everyone else gets a message only they see. Open in OZ is a link button to the job's page in the console.
  • An answer that matches its agent's contract and is a table or key-values comes as section fields, each value plain text (results as cards).

The edge refuses a delivery whose X-Slack-Signature does not match the signing secret or whose X-Slack-Request-Timestamp is more than five minutes off. What the plugin posts is escaped (&, <, >), so nothing an agent writes mentions @channel or anyone else; only the person who asked is named.

For agents

An agent that lists oz0_slack.send may post to a channel by its ID: send(channel, text, thread?). The text starts with the tenant's AI label, [AI agent] ..., as the platform's own posts do. Give it to agents that need to, and mind that it posts as the app. Give agents send, never post: buttons count only on the platform's own messages, but post lets an agent post buttons at all. An agent that calls post anyway gets the AI label on its message too.

A rate limit (429, ratelimited) or Slack's 5xx is reported as retryable, and the platform posts again after the wait Slack asked for. not_in_channel is final: invite the app to the channel, and the person who asked is told so.

Settings

SLACK_API_URL in the tool's environment points the plugin at another Web API, such as GovSlack's (https://slack-gov.com/api) or a test fake.

A message an agent sends asks by default

The plugin's suggested policy asks a person before each send ("the plugin asks before it sends a message"), as a function that does not say whether it destroys anything did already. The install writes it as a rule of the tenant's tool policy, marked as the plugin's. An admin who lets an agent post on its own switches it, with a reason: oz0 plugin policy slack --set oz0_slack.send=allow --reason "...". The channel's own replies (post) are the platform's and not asked about.

Copyright © 2026