Skip to main content

Slack plugin

A worked setup for the slack plugin — messaging, threads, search, reactions, channels, users, files, bookmarks, presence, and emoji against the Slack Web API. This page walks through the exact sequence using only the flux CLI. For the general plugin mechanics (capability grants, trust model, everyday commands), see Using plugins.

1. Install

flux plugin install slack

This resolves the newest signed plugins-v* pack release, verifies the index signature and the archive's SHA-256, and unpacks the binary into the versioned store. Confirm it landed:

flux plugin status slack

status reads the installed version and operation total from the live manifest. For setup, check the bot_token and user_token auth purposes, the slack.endpoint endpoint, the slack.channels and slack.users datasources, and the HTTP, declared-secret, and blob capabilities. With no configuration it reports each purpose's declared environment key or stored-token command, plus the endpoint's https://slack.com/api default.

ok/verified only proves the binary launched and its hash matches the signed descriptor. The auth: lines are the wiring itself: how each declared purpose would resolve right now (never the value) — a stored token, or which env var is set.

2. Provide the tokens

Slack has two token kinds, and the plugin declares one auth purpose for each. Both come from a Slack app of your own (create one at api.slack.com/apps, install it to your workspace):

PurposeTokenUsed by
bot_tokenBot token (xoxb-…), from OAuth & PermissionsMost operations: messages, channels, users, files, reactions, bookmarks
user_tokenUser token (xoxp-…), granted via user scopesslack.search, slack.mentions, slack.unreads, and presence

You only need the purposes your operations use — a bot token alone covers messaging and reading channels; add a user token when you want workspace search, mentions, or unread tracking.

Option A — environment variables (simplest when your shell already carries them):

export SLACK_BOT_TOKEN="xoxb-…"
export SLACK_USER_TOKEN="xoxp-…" # optional; search/mentions/unreads/presence only

Option B — store them once with flux auth set (no env vars needed in later sessions):

flux auth set slack bot_token # hidden prompt — or pipe it in:
pass show slack/bot | flux auth set slack bot_token
flux auth set slack user_token

Stored tokens live in ~/.flux/credentials.toml (created 0600), the same store plugin OAuth logins use, keyed plugin:slack:bot_token. A stored token wins over the env var; --clear removes it. Either way, re-run flux plugin status slack and the lines flip to :

auth: ✓ bot_token — stored token (`flux auth set slack bot_token`)
auth: ✓ user_token — stored token (`flux auth set slack user_token`)

Note what status never shows: the token value itself. The plugin subprocess never sees these as OS environment variables at all — it is spawned with a cleared environment and requests the token by purpose over an IPC capability call; the host resolves it (stored token first, then declared env) and injects it as a bearer header on the plugin's behalf. See Credentials & secrets for the full resolution path.

The endpoint needs no configuration: slack.endpoint defaults to https://slack.com/api. Set SLACK_API_URL only when routing through a proxy or a mock.

3. Verify

flux plugin call slack slack.test

slack.test calls Slack's auth.test with each configured token — the cheapest end-to-end check that tokens, endpoint, and workspace all line up:

{
"count": 2,
"status": "ok",
"tokens": [
{ "ok": true, "role": "user", "team": "acme", "user": "jane.doe", "user_id": "U0…" },
{ "ok": true, "role": "bot", "team": "acme", "user": "acme-bot", "bot_id": "B0…", "user_id": "U0…" }
]
}

A missing credential fails with the exact fix in the message (no credential for purpose `bot_token` — set a declared env key (tried ["SLACK_BOT_TOKEN"]) or store one with `flux auth set slack bot_token` ); an invalid_auth comes from Slack itself and means the token value is wrong or revoked, not that the wiring is broken.

4. Call a real operation

Any of the plugin's declared operations works the same way — flux plugin call slack <op> [json] (--arg key=value also works), or let an agent call them once the plugin is installed:

flux plugin call slack slack.channel.list --arg limit=10
flux plugin call slack slack.message.send '{"channel": "C0123456789", "text": "hello from Flux"}'
flux plugin call slack slack.search '{"query": "deploy failed"}' # needs user_token
flux plugin call slack slack.message.send '{"channel": "…"}' --dry-run # validate input, send nothing

Write operations (slack.message.send, reactions, uploads, …) are policy-gated like every other tool when an agent calls them; --dry-run validates the input against the operation's schema without invoking it.

Recap

StepCommandFailure mode if skipped
Installflux plugin install slackno such plugin \slack``
Tokensexport SLACK_BOT_TOKEN=… or flux auth set slack bot_tokenno credential for purpose `bot_token` — …
Verifyflux plugin call slack slack.test(this is the verification step)
User-token opsalso set/store user_tokenno credential for purpose `user_token` — …
  • Using plugins — install, pin, capability grants, and the trust model shared by every plugin.
  • Credentials & secrets — stored tokens, flux auth set, and how a token resolves without the plugin ever seeing raw environment variables.
  • Plugin capability sandbox — the manifest fields behind these grants.