Slack
Create a Slack app, map members to users, and invite the app to a channel. Slack is the only channel type.
channels: slack: type: slack token: ${SLACK_BOT_TOKEN} signing_secret: ${SLACK_SIGNING_SECRET} members: {U024BE7LH: user:default/@maria, U0G9QF9C6: user:default/@jon}slackis the channel's name: lower-case letters, digits and-. Every key is in config.yaml › channels.- Slack sends events over HTTPS to
/v1/channels/slack/, so the daemon needs a public address. To test without one, use Socket Mode.
A Slack app
Section titled “A Slack app”- At api.slack.com/apps, choose Create New App › From a manifest.
Paste the manifest below. Change
agents.example.comto the daemon's address. - Choose Install to Workspace. Copy the Bot User OAuth Token (
xoxb-...). - Under Basic Information › App Credentials, copy the Signing Secret.
display_information: name: Wardrik description: Agents that answer in threads, and ask before they act.features: app_home: home_tab_enabled: false messages_tab_enabled: true messages_tab_read_only_enabled: true bot_user: display_name: Wardrik always_online: trueoauth_config: scopes: bot: - channels:history - channels:read - chat:write - chat:write.public - groups:history - groups:read - reactions:write - users:readsettings: event_subscriptions: request_url: https://agents.example.com/v1/channels/slack/events bot_events: - app_uninstalled - channel_left - group_left - member_joined_channel - message.channels - message.groups - tokens_revoked interactivity: is_enabled: true request_url: https://agents.example.com/v1/channels/slack/actions org_deploy_enabled: false socket_mode_enabled: false token_rotation_enabled: falseslackin each URL is the channel's name inconfig.yaml.- Slack verifies the events URL on save, so the daemon must be reachable first.
Store both secrets, then restart the daemon:
echo "xoxb-..." | wardrik vault put SLACK_BOT_TOKEN --for api_keyecho "..." | wardrik vault put SLACK_SIGNING_SECRET --for signing_secretwardrik stop && wardrik startCopy each member ID from the Slack profile (Copy member ID) into members.
Testing with Socket Mode
Section titled “Testing with Socket Mode”Socket Mode needs no public address. It's for testing.
- In the manifest, set
socket_mode_enabled: trueand remove bothrequest_urllines. - Under Basic Information › App-Level Tokens, create a token with
connections:write(xapp-...). - Set
app_tokeninstead ofsigning_secret:
channels: slack: type: slack token: ${SLACK_BOT_TOKEN} app_token: ${SLACK_APP_TOKEN}Use a separate app per daemon. Slack distributes events across all of an app's connections.
Members
Section titled “Members”members maps each Slack member ID to a daemon user. A member acts as that user, with that user's
bindings. What members can do is in built-in rules.
- An unmapped member is refused, with a message to ask an admin.
unmapped_members: allowmaps them touser:slack:T0123/U024BE7LH. For small deployments.
Add an agent to a channel
Section titled “Add an agent to a channel”List the channel in the agent's file, then /invite @Wardrik in Slack:
channels: [slack]:wave: books answers here now.
[Answer every message][⋯]
- With one agent available, it replies when mentioned. Answer every message makes it reply to each message, in its own thread.
- With several, the bot posts a button per agent. With none, it posts how to make one available.
- ⋯ has Use another agent and Stop answering here. Removing the bot also unbinds the channel.
- A channel is available to the deployment's org, unless
orgsassigns it to another.
Threads
Section titled “Threads”maria: @Wardrik how much Barolo is left? :eyes: ↳ Wardrik: Two cases, both 2019.
- Mention the bot to start a thread. Replies in the thread need no mention.
- Each thread is a conversation, such as
conversation: "slack.T0123.C024BE91L.1696.1234". Threads share the agent's definition and files. - :eyes: means the agent received the message. :white_check_mark: means it replied.
- The thread's status shows the agent's current activity.
- To post notices in a channel, set
notify: "slack:#updates". See Send notices.
Approval messages
Section titled “Approval messages”A pending call shows its tool, the policy message and its arguments, with Approve, Deny and a note field. Once resolved, the buttons are replaced with the result:
Denied
deployby @jon: Deploy to staging first, and show me the diff.
Who approves
Section titled “Who approves”The member who started the turn can always approve its calls. Anyone else needs a binding (see Who can approve):
roles: approver: {rules: [{verbs: [approve, deny, decide], kinds: [agent], names: [books]}]}bindings: - {org: default, role: approver, subjects: [user:default/@maria]}A triggered turn has no member who started it. Use wardrik approval approve.
The app doesn't reply
Section titled “The app doesn't reply”If the app was invited while the daemon was down, /remove @Wardrik and invite it again. Then
check:
- Event Subscriptions shows the request URL as verified;
wardrik doctorverifies the tokens with Slack;wardrik logs.