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.
https://<your-host>/slack/events.
slakd:8080.
InboundMsg, posts it to gated.
reply or send; slakd
posts via Slack’s Web API.
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.
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
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.
message.channels, message.groups,
message.im, message.mpimreaction_addedmember_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>.
SLACK_SIGNING_SECRET.
xoxb-) →
goes in SLACK_BOT_TOKEN.
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"
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.
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
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.
assistant:write to the bot token scopes. Keep
chat:write. Reinstall the app so the new scope takes
effect.
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.
slakd’s /health returns 503 when Slack’s
auth.test has not succeeded (revoked token, network outage,
Slack down). Reconnect = restart the process.
/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".
/health returns 503 disconnectedxoxb- token, update .env, restart.
reaction_added is subscribed under Event
Subscriptions — it isn’t on by default.
| 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
gated; 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.