arizuko › components › slakd
slakd
What it is
In plain terms, slakd is the connector that plugs Slack into arizuko, so the agent can read and reply in Slack channels, DMs, and threads.
slakd is the Slack channel adapter. It receives Slack workspace events over the HTTP Events API (proxyd forwards /slack/events to slakd) and posts outbound via the Slack Web API. From routd’s point of view it is a normal channel adapter with JID prefix slack: and per-message JIDs of the form slack:<workspace>/<kind>/<id> where kind is channel, dm, or group.
Why it exists
Slack is where many teams already work, and it’s the only platform arizuko targets that ships an “Agents & AI Apps” assistant pane — a sidebar with suggested prompts and a conversation title. Talking to Slack directly, rather than through a SaaS gateway, is what lets slakd drive that pane and verify the same CHANNEL_SECRET signature as every other adapter.
How it fits
Slack workspace
| HTTPS Events API webhook
v
proxyd (verifies X-Slack-Signature, forwards /slack/...)
|
v
slakd (LISTEN_ADDR=:8080)
| POST /v1/messages (signed by CHANNEL_SECRET)
v
routd
| POST /send (callback to slakd)
v
slakd (chat.postMessage / files.* / reactions.add)
|
v
Slack Web API
slakd verifies the X-Slack-Signature HMAC of v0:<ts>:<body> on every webhook and rejects skew > 5 minutes. Reactions added on Slack become synthetic like / dislike inbound rows (classified by chanlib.ClassifyEmoji). Channel messages that contain <@bot_user_id> are tagged verb=mention; DMs and unaddressed channel messages ride verb=message.
Wired verbs (see slakd/bot.go, slakd/server.go): send, send_file, edit, delete, like, dislike, post, plus the assistant-pane verbs pane_set_prompts and pane_set_title. forward, quote, repost are 501-with-hint.
Assistant pane
With assistant:write scope and the assistant_thread_started + assistant_thread_context_changed subscriptions, slakd upserts a row in pane_sessions when a user opens the sidebar, sets the title to <ASSISTANT_NAME> — chat, seeds three suggested prompts, and dispatches a synthetic pane_open inbound. Pending prompts and title updates staged via MCP tools are drained on the next chat.postMessage.
Output rendering switches the agent into the slack Claude Code output style (*bold*, _italic_, <url|text>) since v0.40.7 so the bot speaks Slack mrkdwn instead of CommonMark.
Standalone usage
slakd is a plain Go binary. It needs a reachable routd, a Slack app with a bot token, and a public URL that forwards /slack/events to it.
export ROUTER_URL=http://routd:8080
export CHANNEL_SECRET=$(grep ^CHANNEL_SECRET .env | cut -d= -f2)
export LISTEN_ADDR=:8080
export SLACK_BOT_TOKEN=xoxb-...
export SLACK_SIGNING_SECRET=...
export ASSISTANT_NAME=arizuko
export DB_PATH=/srv/app/home/store/messages.db
./slakd
Slack-side setup: create a Slack app, enable Events API with request URL pointing at /slack/events, subscribe to message.channels, message.im, message.groups, reaction_added, and (for the pane) assistant_thread_started + assistant_thread_context_changed. Do not subscribe to app_mention — slakd detects mentions from <@bot_user_id> in the message text, and a parallel app_mention subscription causes duplicate processing. Scopes: chat:write, files:write, reactions:write, im:history, channels:history, groups:history, assistant:write.
GET /health returns 503 when Slack auth fails or the workspace cache cannot warm.
Go deeper
- components/channels — cross-adapter verb matrix.
slakd/README.md— full env var table, file map, pane lifecycle.specs/7/D-*— assistant pane spec.