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
-
Slack POSTs a webhook event to
https://<your-host>/slack/events. -
proxyd forwards the raw body and Slack signature
headers unmodified to
slakd:8080. -
slakd verifies the HMAC, converts the event to an
internal
InboundMsg, posts it to routd. - routd routes to a group and dispatches the turn; runed spawns the agent container.
-
The agent runs, calls
replyorsend; 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
- Go to api.slack.com/apps → Create New App → From scratch.
- 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
- Enable events.
-
Set Request URL to
https://<your-host>/slack/events. Slack will POST aurl_verificationchallenge once; slakd echoes it. The Request URL turns green when proxyd + slakd are both running. -
Subscribe to bot events:
•message.channels,message.groups,message.im,message.mpim
•reaction_added
•member_joined_channel
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
-
Basic Information → copy
Signing Secret → goes in
SLACK_SIGNING_SECRET. -
Install to Workspace → copy
Bot User OAuth Token (starts with
xoxb-) → goes inSLACK_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.
- Agents & AI Apps → toggle on for the app.
-
OAuth & Permissions → add
assistant:writeto the bot token scopes. Keepchat:write. Reinstall the app so the new scope takes effect. -
Event Subscriptions → subscribe to:
assistant_thread_started,assistant_thread_context_changed. Keepmessage.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 intemplate/services/slakd.tomlis dropped whenSLACK_BOT_TOKENis unset — check it’s in.envand 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.
/healthreturns 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_addedis 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 |
/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.