Slack
Connect Slack from the web app or your own Slack App, map a workspace, and grant a Teammate Slack tools.
Slack is an intake and outbound path for a named Teammate: mentions and DMs become turns carrying Slack source metadata, and granted tools can post back to channels and threads. The desktop app configures the connection — Settings → Connections, the Slack card — and the daemon on that machine owns the token in its vault. The web app's Settings → Integrations page has a Slack row too: Connect with Slack authorizes Kairoku's hosted Slack App, and your linked daemon then collects the bot token into its vault on its own. The rest of the row is a read-only status for the wake relay.
The desktop MCP Servers section also offers a Slack preset that asks for a Slack Bot Token and a Slack Team ID. That is a chat tool the model can call over MCP, and it is unrelated to Teammate intake and to the grants on this page — it will not deliver a single mention. Configure it only if you want the model to browse Slack as a tool.
Client ids, client secrets, bot tokens, and signing secrets never belong in a repository, a brief, a transcript, or these docs. Paste only into Slack's own console or the desktop Slack card. Examples below use clearly fake placeholders such as slack-client-id.EXAMPLE and xoxb-EXAMPLE-not-a-real-token.
What you will do
Two human steps, in order:
- Connect the daemon — either click Connect with Slack in the web app and let your daemon collect the token (hosted), or register your own Slack App and hand its bot token to the daemon. Either way the token lands encrypted in the daemon's vault.
- Map and grant a Teammate — route the workspace at one Teammate, then turn on the Slack tool grants that Teammate should hold.
The hosted path needs no App of your own. Register one only if your deployment has no hosted Slack App configured (the web's Slack row then has no working Connect with Slack), or if you want the App under your own workspace's control.
Prerequisites
- Kairoku desktop on the same machine as the daemon (or able to reach it).
- For the hosted path: the daemon linked to your Kairoku account (signed in from the desktop app) and running. It must be newer than 1.1.0 — 1.1.0 and older never collect a hosted authorization.
- The daemon running and reachable — daemon-first intake assumes an always-on daemon. The wake relay is the offline safety net, and it is an operator deployment, not a user step.
- Permission in Slack to create and install an App in the workspace you want (or an admin who can approve the install).
kairoku doctor asks the desktop daemon about Slack directly, over the daemon's own socket. The desktop daemon (kairokud) row reports its version and uptime, and the desktop daemon slack row PASSes with the workspace name once Slack is connected — otherwise it WARNs with a connect-or-reconnect hint pointing back at desktop Connections. Neither row can FAIL: a headless machine has no desktop app at all, so a missing socket, a stale one, or a daemon too old for the check is a warning and doctor still exits 0. Doctor reads state and changes nothing; you connect Slack from the web app's Connect with Slack or desktop Connections.
1. Create the Slack App
Skip this section if you connect through the web app's Connect with Slack: Kairoku's hosted App is already registered. Otherwise, a workspace admin does this once per workspace at api.slack.com/apps.
Create the App. Open Your Apps → Create New App → From scratch. Give it a display name (for example Kairoku) and pick the workspace. Record the Client ID and Client Secret from Basic Information in a password manager — never in git. Treat values like slack-client-id.EXAMPLE / slack-client-secret.EXAMPLE as shape only.
Bot token scopes. Under OAuth & Permissions, add the bot scopes that let the App:
- receive mentions and DMs, and read thread context for intake
- post and reply in channels and threads for outbound
- read enough user and channel identity to attach source metadata to a turn
The daemon's own default set is app_mentions:read, channels:history, chat:write, im:history and im:read. Keep the list to what those three things need. Do not add extra write scopes "just in case."
Redirect URL. Nothing to add. A redirect belongs to the hosted App's browser OAuth flow, and the bot-token path for your own App does not use one.
Event Subscriptions. There is no Events endpoint on the daemon. If your operator has deployed the wake relay for your deployment, enable events and set the Request URL to the relay's POST /v1/installs/{installId}/events — the relay verifies Slack's request signature and queues the event for your daemon. Subscribe to the bot events for mention, DM, and thread context. Without the relay, Slack cannot deliver events to a daemon on a laptop in this release: live mention delivery needs the relay — and app.kairoku.io does not run one today.
Install to Workspace. Complete Slack's consent screen. Slack then shows a bot token shaped like xoxb-… — that is the credential the daemon takes in the next section, and its only home is the daemon vault, never a screenshot, a chat message, or this page.
Signing secret, client secret, and tokens stay in Slack's console and the daemon vault. Rotate anything that was ever pasted into a ticket or a commit.
2. Connect the daemon
Hosted: Connect with Slack in the web app
- Make sure your daemon is running and linked to the same Kairoku account (your user, or the organization you have selected).
- In the web app, open Settings → Integrations → Slack and click Connect with Slack. Slack asks you to approve Kairoku's App for a workspace: app mentions, posting messages, public channel history, direct message history and the user list (
app_mentions:read,chat:write,channels:history,im:history,users:read). - Slack sends you back to Integrations, which shows Slack authorised — Your linked daemon collects it within a minute and stores it in its vault.
Behind that notice, the Kairoku API holds the token in an encrypted, single-use handoff for 10 minutes. A linked daemon asks the API for it every 30 seconds, and the API deletes the handoff as it hands it over, so Kairoku keeps no copy. The daemon then stores it exactly as a pasted token (below). If no daemon collects it within 10 minutes — the daemon was off, or not linked — the handoff is gone: start again from Connect with Slack. If you link more than one daemon to the same account, the first one to ask collects it.
Your own App: hand the bot token to the daemon
The desktop Slack card has two actions. Install installs the slack catalog entry on the daemon. Connect asks the daemon to start an OAuth flow and shows Complete Slack authorization with a URL and a user code, but against real Slack that dialog does not complete on its own: the daemon carries no client id for an App. With your own App, connect with its bot token instead:
- Install the Slack catalog entry from Settings → Connections.
- Take the
xoxb-…bot token Slack showed after Install to Workspace. - Hand that token to the daemon with its
integration.slack.oauth.pollmethod and anaccessToken. The desktop Slack card has no token field in this release.
What the daemon stores
Either way, the daemon encrypts the token straight into its vault (ChaCha20-Poly1305, under the same master key the integration vault uses) and records the workspace's team id and name. The card then shows Stored Slack token (masked) — the value itself is never rendered back and never crosses the wire. Remove revokes it. Re-authorizing replaces the stored credential rather than adding a second one.
integration.slack.status is the state of record: connected (a token is in the vault), installed (the catalog row exists but holds no token), or notInstalled, plus the team id and name.
3. Map and grant a Teammate
Connecting Slack does not route anything, and it does not let a persona post. Those are two more decisions.
Mapping routes a workspace at a Teammate. integration.slack.mapTeammate points one slackTeamId — optionally narrowed to one channelId — at one Teammate. A channel row wins over the workspace default. An unmapped channel is refused, never quietly routed to the default. Mappings are daemon-local, and in this release they are made through that daemon method: there is no mapping form on the desktop Slack card yet.
Intake records a Teammate turn, or continues an existing one when the message arrives under a threadTs the daemon has already seen. The result carries source metadata — kind slack, mention or DM, team, channel, user, thread, and a 160-character preview. The full message body never appears in events. A turn is picked up by the agent session bound to that Teammate; a Teammate with no bound session still accepts intake, and the turn waits until you bind a chat to it — nothing runs on its own.
Grants let that Teammate act. Mapping is not a grant: the mapped Teammate must also hold slack.intake, or intake is denied. Open the Teammate from the chat sidebar → Teammates panel and use the Slack tool grants switches:
| Switch | Scope | Without it |
|---|---|---|
| Accept Slack mentions and DMs | slack.intake | Mentions and DMs are refused |
| Read Slack channels and threads | slack.read | slack.read fails closed |
| Post and reply in Slack | slack.send | slack.send fails closed |
The panel says it plainly: Denied — tools fail closed without this grant. slack.send takes {channel, text, threadTs?} and posts or replies in a thread; slack.read takes {channel?, limit ≤ 200} and reads the mentions and DMs this Teammate has received. When the vault holds no token (connected: false), every invoke fails closed no matter which grants are on.
See Teammates for the panel itself.
The wake relay
Daemon-first intake is the baseline: an always-on daemon takes Slack events as they arrive. The relay is the offline safety net, and in this release it is also what makes live delivery possible at all for a daemon that Slack cannot reach.
kairoku-slack-wake-relay is a Cloudflare Worker with a Durable Object. It accepts Slack events while the daemon is offline, queues an intake-shaped projection of each for 72 hours, and hands them over when the daemon reconnects.
| Endpoint | Caller |
|---|---|
POST /v1/installs/{installId}/events | Slack, verified by request signature |
POST /v1/installs/{installId}/drain | The daemon, with a ticket |
GET /v1/installs/{installId}/status | The daemon or an operator, with a ticket |
GET /health | Anyone |
The daemon drains with integration.slack.relay.drain and finds the relay through KAIROKUD_SLACK_WAKE_RELAY_URL. Delivery is at-least-once and idempotent per relay event id: a replayed event lands in skipped: already_delivered and never opens a second turn. Tickets are short-lived JWTs minted by the Kairoku API — never Slack tokens, and never logged.
The web app's Settings → Integrations → Slack row reports which of four states your deployment is in (app.kairoku.io reports the first):
- Cloud wake relay is not configured for this environment. Daemon-first Slack intake still works without it.
- Relay reachable. No pending offline events.
- Relay URL is set, but ticket mint is not configured yet.
- Relay is configured but not reachable right now.
Deploying the relay is an operator step (wrangler), not something a user does from the app.
After setup
| Check | Expect |
|---|---|
| Desktop Slack card | Connected; the stored token masked, never a value |
| Hosted path | Slack authorised on web Integrations, then connected within a minute |
| Teammate grants | Slack switches on only for Teammates that should use them |
| Mapping | A row present for the workspace, and for the channel if you scoped one |
| Wake relay, if deployed | Reachable on the web app's Settings → Integrations → Slack row |
| Mention or DM | Arrives through the relay drain and opens a Teammate turn with Slack source metadata |
| Outbound with grant | Reaches the channel or thread |
| Outbound without grant | Denied; no post |
This page is setup only. Running the whole Slack path with a person watching is a separate gate.
Related
- Teammates — the Teammates panel and its Slack tool grants
- Desktop — Settings → Connections and the MCP Servers section
- Glossary — Teammate vs Floor Team vs Crew
- Connections — GitHub and GitLab in the web app, plus the Slack row and wake relay status
- Integration catalog — additional curated installs with vault token / PAT
- CLI —
kairoku doctorand daemon install on the machine
Connections
Connect once in Settings → Connections — GitHub and GitLab sign-in, picking repositories, trackers, and remote MCP tools, refreshed centrally and delivered to every run with no second login.
Integration catalog
Browse and install additional curated connectors on the daemon — vault token or PAT when required.