arizuko

arizukohowto › Slack

deploy on Slack

arizuko’s Slack adapter (slakd) connects one bot to one workspace via Slack’s HTTP Events API. Public reachability is provided by proxyd — Slack posts events to https://<your-host>/slack/events and proxyd forwards them to slakd verbatim so the X-Slack-Signature HMAC verifies.

how it works

  1. Slack POSTs a webhook event to https://<your-host>/slack/events.
  2. proxyd forwards the raw body and Slack signature headers unmodified to slakd:8080.
  3. slakd verifies the HMAC, converts the event to an internal InboundMsg, posts it to routd.
  4. routd routes to a group and dispatches the turn; runed spawns the agent container.
  5. The agent runs, calls reply or send; slakd posts via Slack’s Web API.

JID format

Every Slack chat has a typed JID that routing rules match against:

chat type JID format example
channel slack:<workspace>/channel/<channel_id> slack:T012ABCD/channel/C0HJKL456
DM slack:<workspace>/dm/<dm_id> slack:T012ABCD/dm/D0XY9876
legacy mpim slack:<workspace>/group/<mpim_id> slack:T012ABCD/group/G0AB1234

Workspace and channel IDs are kept verbatim from Slack — paste-back from Slack URLs works. Threads use Slack’s thread_ts as the message topic; replies in a thread share that topic.

step 1 — create a Slack App

  1. Go to api.slack.com/appsCreate New AppFrom scratch.
  2. Name the app and pick the workspace to install into.

step 2 — OAuth & Permissions

Add these Bot Token Scopes:

channels:history  channels:read
groups:history    groups:read
im:history        im:read
mpim:history      mpim:read
chat:write        chat:write.public
reactions:read    reactions:write
files:read        files:write
users:read

step 3 — Event Subscriptions

  1. Enable events.
  2. Set Request URL to https://<your-host>/slack/events. Slack will POST a url_verification challenge once; slakd echoes it. The Request URL turns green when proxyd + slakd are both running.
  3. Subscribe to bot events:
    message.channels, message.groups, message.im, message.mpim
    reaction_added
    member_joined_channel
Don’t subscribe to app_mention: Slack fires it alongside the regular message.* event, so it would deliver every mention twice. slakd derives verb="mention" from message text containing <@bot_user_id>.

step 4 — copy secrets

  1. Basic Information → copy Signing Secret → goes in SLACK_SIGNING_SECRET.
  2. Install to Workspace → copy Bot User OAuth Token (starts with xoxb-) → goes in SLACK_BOT_TOKEN.

step 5 — configure arizuko

Add to /srv/data/arizuko_<instance>/.env:

SLACK_BOT_TOKEN=xoxb-...
SLACK_SIGNING_SECRET=...
# optional
SLAKD_USERS_CACHE_TTL=900

Regenerate compose and restart:

arizuko run <instance>
sudo systemctl restart arizuko_<instance>

Verify slakd is up:

sudo curl -s -o /dev/null -w '%{http_code}\n' http://localhost:<web_port>/health
sudo journalctl -u arizuko_<instance> --since "30s ago" --no-pager \
  | grep -E "slack|slakd"

step 6 — invite the bot

In any Slack channel you want the agent to read or post in:

/invite @<your-bot-name>

DMs work without an explicit invite — any Slack user in the workspace can DM the bot directly.

step 7 — set up routing

Without a routing entry, messages from Slack are stored but no agent is fired. In the root agent (or via /dash/ → Routing):

add a route: match all Slack messages, target folder "main"

Or narrow to one channel:

match: chat_jid=slack:T012ABCD/channel/C0HJKL456
target: engineering

step 8 (optional) — enable the AI sidebar

Slack’s “Agents & AI Apps” sidebar gives the bot a dedicated pane with a title, suggested-prompt buttons, and a typing indicator. The bot can also see which channel the user is currently viewing. Concept page: slack pane.

  1. Agents & AI Apps → toggle on for the app.
  2. OAuth & Permissions → add assistant:write to the bot token scopes. Keep chat:write. Reinstall the app so the new scope takes effect.
  3. Event Subscriptions → subscribe to: assistant_thread_started, assistant_thread_context_changed. Keep message.im — the bot reads pane messages from the same DM channel.

slakd handles the events transparently — when the user clicks the AI icon, slakd upserts a row in pane_sessions, sets the pane title from ASSISTANT_NAME (or per-folder PERSONA.md frontmatter pane_title), and stages starter prompts. The agent then controls subsequent prompts via the pane_set_prompts MCP tool.

health check

slakd’s /health returns 503 when Slack’s auth.test has not succeeded (revoked token, network outage, Slack down). Reconnect = restart the process.

troubleshooting

Slack’s Request URL stays red
Either proxyd isn’t routing /slack/* (the [[proxyd_route]] block in template/services/slakd.toml is dropped when SLACK_BOT_TOKEN is unset — check it’s in .env and regenerate compose), or slakd’s signing-secret mismatch makes it reject the challenge. Check slakd logs for "slack events: signature rejected".
Bot is in the channel but doesn’t respond
Add a routing entry — without one, messages are stored but no agent fires.
/health returns 503 disconnected
Bot token revoked or wrong. Reinstall the app, copy a fresh xoxb- token, update .env, restart.
Reactions don’t arrive as inbound events
Make sure reaction_added is subscribed under Event Subscriptions — it isn’t on by default.

env vars reference

variable required default notes
SLACK_BOT_TOKEN yes Bot User OAuth Token (starts xoxb-)
SLACK_SIGNING_SECRET yes App → Basic Information → Signing Secret
SLAKD_USERS_CACHE_TTL no 900 seconds — users.info/conversations.info cache TTL
ASSISTANT_NAME no shown in the pane title (<name> — chat) and typing indicator; unset means the pane title is just “chat” with no hint of who’s talking
SLAKD_CHANNEL_SECRET no inherits CHANNEL_SECRET optional per-adapter override of CHANNEL_SECRET. slakd presents this bearer to routd; registration binds it to the slack channel record so a leaked Slack manifest does not compromise other adapters
MEDIA_MAX_FILE_BYTES no 26214400 (25 MiB) upper bound on inbound file size; larger uploads are skipped with a log line and not stored as attachments
Slash commands: Slack intercepts /commands before the bot ever sees them. To send a command to the agent, prefix with backslash instead: \new, \ping, \help. slakd accepts \ as the command prefix on Slack.

Out of scope in v1: OAuth install (manual install only), Socket Mode (HTTP webhooks via proxyd only), Enterprise Grid, slash commands / modals / Block Kit, user tokens.