Slack Setup Guide
August 23, 2026 ยท View on GitHub
How to create a Slack app for Kiro Crew and connect it.
Slack is optional: If you don't need Slack, skip this entirely. The default
kirocrew setupconfigures no messaging channels, and the gateway runs the web dashboard without any. When you are ready to connect Slack, runkirocrew setup --slackto enter the tokens created below.
Kiro Crew connects to Slack using Socket Mode, so it runs entirely from your own machine over an outbound WebSocket: no public URL, no inbound webhooks, and no hosting required. You just need a Slack workspace where you can install an app.
Choose Your Path
There are two independent paths to create a Slack app. Pick one, and do not mix them.
| Path | Steps | Best for |
|---|---|---|
| Path A: Manifest (recommended) | 6 steps | Most users; auto-configures all scopes, events, and permissions in one shot |
| Path B: Manual | 11 steps | If you need to customize scopes or understand each setting individually |
Both paths require a Slack workspace where you can install apps (see Prerequisites).
Prerequisites
- A Slack workspace where you have permission to install apps. If you don't have one, create a free workspace at https://slack.com/get-started. You can install your own apps in a workspace you own.
- Python and Kiro Crew installed (
pip install kirocrew), so you can run thekirocrewCLI.
Tip: Use a personal or test workspace for your first run. You can always export the app manifest and recreate the app in another workspace later (see Reusing the App in Another Workspace).
Path A: Create via Manifest (Recommended)
Step 1. Generate the Manifest
kirocrew manifest --url
This prints a one-click URL that opens Slack's "Create New App" page with all scopes, events, and permissions pre-filled:
๐ Click to create your Slack app:
https://api.slack.com/apps?new_app=1&manifest_yaml=...
Step 2. Create the App from the Link
- Click (or Cmd-click) the URL printed in Step 1
- Select your workspace from the workspace dropdown
- Click Create
Alternative: paste manifest manually
If the URL doesn't work, generate the raw YAML instead:
kirocrew manifest -o ~/.kiro/crew/slack-manifest.yaml
Then:
- Go to https://api.slack.com/apps โ Create New App โ From a manifest
- Select your workspace
- Paste the contents of
~/.kiro/crew/slack-manifest.yaml - Click Create
Step 3. Generate App Token
- Settings โ Socket Mode โ Toggle OFF then back ON, which triggers the token generation dialog
- Add scope
connections:writeโ Generate - Copy the
xapp-...token. This is your App Token
Why toggle off/on? Slack manifests can declare
socket_mode_enabled: true, but the App Token (xapp-...) must still be generated manually through the UI. There is no API or manifest field for token generation. Toggling forces the generation dialog to appear.
Step 4. Install to Workspace
- Go to Features โ OAuth & Permissions โ Install to Workspace
- Approve the installation
- Copy the
xoxb-...token. This is your Bot Token
"Install App" button greyed out? The Settings โ Install App page sometimes has the button disabled due to a Slack UI bug. Use Features โ OAuth & Permissions โ Install to Workspace instead, which does the same thing.
Workspace admin approval? Some workspaces restrict who can install apps. If your install needs approval, an admin of that workspace must approve it. In a workspace you own, you can self-approve.
Step 5. Configure Kiro Crew
Run the interactive setup, which prompts for both tokens:
kirocrew setup
Paste your App Token (xapp-...), Bot Token (xoxb-...), and your Slack Member ID when prompted.
To find your Slack Member ID: open your workspace in Slack โ click your profile picture โ Profile โ โฎ โ Copy member ID.
โ ๏ธ Your Member ID is per-workspace. If you install the app in a different workspace, your Member ID changes, so use the ID from the workspace where Kiro Crew is installed.
Step 6. Verify & Run
kirocrew doctor # verify tokens and config
kirocrew gateway # start KiroCrew
Open your workspace in Slack, find your app in the Apps section, and send it a DM. The app only lives in the workspace where you installed it.
You're done! ๐ Skip ahead to After Setup for next steps.
Path B: Manual Setup
Use this path if you want to configure each scope and event individually, or if you need to customize the app beyond what the manifest provides.
Step 1. Create the App
- Go to https://api.slack.com/apps โ Create New App โ From scratch
- Name: something unique (e.g.
kirocrew). Generic names may conflict with existing apps in the same workspace - Workspace: select your workspace
Step 2. Enable Socket Mode & Get App Token
- Settings โ Socket Mode โ Toggle ON
- Click Generate Token โ add scope
connections:writeโ Generate - Copy the
xapp-...token. This is your App Token
Step 3. Add Bot Scopes
Go to Features โ OAuth & Permissions โ Bot Token Scopes and add:
| Scope | Purpose |
|---|---|
app_mentions:read | Respond when @mentioned |
chat:write | Send, update, and delete messages |
channels:history | Read channel messages (for @mentions) |
channels:read | List public channels (the channel picker) and read channel metadata |
groups:history | Read messages and thread replies in private channels the bot is in |
groups:read | List private channels the bot is in and read their metadata |
im:history | Read DM history |
im:read | View DM metadata |
im:write | Open DMs |
reactions:write | Add and remove emoji reactions |
files:read | Read uploaded files |
files:write | Upload screenshots |
users:read | Profile lookups (users.info) resolve a sender's real name. Without it the lookup fails and is caught: the display name falls back to the matching slack.allowed_users entry, then to the raw Slack member ID |
commands | Slash commands |
The emoji:read bot scope is deliberately not in the shipped manifest.
Add it only if you want custom workspace emojis to appear in the emoji picker.
Upgrading an existing app? Adding a scope to the manifest does not retroactively grant it: Slack only grants new scopes when the app is reinstalled to the workspace. After adding scopes (or importing an updated manifest), go to Settings โ Install App โ Reinstall to Workspace and copy the new Bot Token.
Step 4. Add User Scopes
Under User Token Scopes, add:
channels:history, channels:read, groups:history, groups:read,
im:history, im:read, mpim:history, mpim:read, search:read, and
users:read.
These scopes belong to the installing user's xoxp-... token. The Kiro Crew
gateway itself uses the bot token; the user token is for a separately configured
Slack MCP/search integration that lets an agent search Slack as that user. Store
and configure that token only in the integration that consumes it.
Step 5. Subscribe to Events
- Features โ Event Subscriptions โ Toggle ON
- Under Subscribe to bot events, add all of these:
message.immessage.channelsmessage.groupsapp_mentionapp_home_openedfile_changemember_joined_channel
- Click Save Changes
Step 6. Add Slash Commands
Features โ Slash Commands โ Create New Command:
| Field | Value |
|---|---|
| Command | /kirocrew |
| Short Description | Dashboard access, allowlist, and channel tracking |
| Usage Hint | dashboard [duration] | @user | #channel |
The command name you choose here must match the slack.command value in ~/.kiro/crew/config.json (default: kirocrew):
{
"slack": {
"command": "kirocrew"
}
}
When creating the command, check Escape channels, users, and links sent to your app so mentions resolve to <@U1234|user> format.
Step 7. Enable Interactivity
Features โ Interactivity & Shortcuts โ Toggle ON
No Request URL needed: Socket Mode handles it. This is what makes the Block Kit buttons work, including tool approval (approve / trust / reject), the multiple-choice option buttons, the cron and subagent acknowledge buttons, and the session Resume / End buttons.
Step 8. Enable App Home
Features โ App Home:
- Enable Home Tab
- Enable Chat Tab
- Check "Allow users to send Slash commands and messages from the chat tab"
Step 9. Install to Workspace & Get Bot Token
- Features โ OAuth & Permissions โ Install to Workspace โ Approve
- Copy the
xoxb-...token. This is your Bot Token
"Install App" button greyed out? Use Features โ OAuth & Permissions โ Install to Workspace instead (known Slack UI bug).
Step 10. Configure Kiro Crew
Same as Path A, Step 5.
Step 11. Verify & Run
Same as Path A, Step 6.
If you add scopes to an existing app, reinstall it from OAuth & Permissions before testing. Slack does not grant newly declared scopes to tokens from an older installation.
After Setup
Manual Token Configuration
If you prefer to configure tokens manually instead of using kirocrew setup:
mkdir -p ~/.kiro/crew
cat > ~/.kiro/crew/.env << 'EOF'
SLACK_APP_TOKEN=xapp-your-app-token-here
SLACK_BOT_TOKEN=xoxb-your-bot-token-here
KIROCREW_OWNER_ID=your-slack-member-id
EOF
chmod 600 ~/.kiro/crew/.env
Owner-Only Access
Only the owner (KIROCREW_OWNER_ID) can interact with Kiro Crew via Slack.
Multi-user access is disabled at the authorization predicate itself, not by
configuration: is_allowed_user resolves to an owner check, is_open_channel
always returns false, and the channel-join allowlist prompt is a no-op. A
/<command> @user invocation replies that multi-user access is disabled.
Setting or changing
KIROCREW_OWNER_IDinvalidates existing dashboard sessions. The value is not just the Slack DM routing target โ it is also the dashboard's authorization principal and the subject baked into every dashboard token at mint time. A dashboard session signed in before the value was set (or before it changed) keeps its old subject for its whole life, so owner-only actions (the Trust/YOLO switch, tool approvals, worktree creation, cloud setup, and the other owner-gated surfaces) are denied for it afterwards. For a session from before an owner was FIRST configured, the dashboard detects the case and shows a sign-in banner; a session signed in under a PREVIOUS owner value is denied with the generic response and likewise needs a fresh sign-in. Either way, runkirocrew tokenand open the fresh link to re-authenticate under the new owner.
Reaction Emojis
Kiro Crew adds phase-aware emoji reactions during message processing (queued โ thinking โ coding โ done). Customize or disable:
{
"slack": {
"reactions": {
"done": "sparkle",
"thinking": "brain",
"coding": "computer"
},
"reactions_enabled": true
}
}
Set reactions_enabled to false to disable all phase reactions. Valid keys: queued, thinking, coding, browsing, tool, done, error.
To suppress a single phase (keep the others at their defaults), set it to null. For example, to keep the working/browsing/tool reactions but hide the terminal ๐ฆ on every message:
{
"slack": {
"reactions": { "done": null }
}
}
A suppressed phase removes any prior reaction but adds nothing new; stall reactions (๐ฅฑ / ๐จ) are unaffected.
Reusing the App in Another Workspace
To install your app in a different Slack workspace, export the manifest and recreate the app there:
- Export your app manifest: App Config โ App Manifest โ Copy to Clipboard (YAML)
- Go to https://api.slack.com/apps โ Create New App โ From a manifest
- Select the new workspace and paste the YAML
- Re-generate the App Token (Socket Mode) and Bot Token, then re-run
kirocrew setupwith the new tokens and your Member ID for that workspace
Dashboard Access
Dashboard access is token-authenticated. When Slack is connected you can mint a presigned link from Slack; the link is always sent as a DM, never posted into a channel, so the token cannot leak to a channel's members.
Getting a Link
Any of these work:
!dashboard # DM: 1-hour session (default)
!dashboard 2h # DM: 2-hour session
/kirocrew dashboard # Slash command: 1-hour session
/kirocrew dashboard 30m # Slash command: 30-minute session
Durations are <N>h or <N>m and are capped at 20 hours; anything longer
is silently clamped to the cap, and an unparseable value gets a usage reply
instead of a link.
How It Works
- Link must be clicked within 5 minutes (after that the URL expires)
- On first click: token is bound to your IP, and a session cookie is set
(
mc_token_<port>, HttpOnly, SameSite=Lax,Secureonly over HTTPS). The cookie is keyed by the port your browser connects to, not the port the gateway listens on, because browsers do not isolate cookies by port and two tunnelled instances would otherwise overwrite each other's session - Subsequent visits use the cookie, so there is no need to re-click the link
- Session cookie lasts for the requested duration (default 1h, cap 20h)
- Every request needs a valid token or cookie, including requests that
arrive on loopback. Loopback is not an exemption: a local port forwarder
(
socat,ssh -R, a helper script) makes remote traffic appear to come from127.0.0.1, so exempting it would be an auth bypass. The only loopback carve-out is a small set of internal API paths reserved for Kiro Crew's own processes (doctor, the MCP servers), and those additionally require a matchingX-Internal-Secretread from~/.kiro/crew/.local_secret
Dashboard URL Configuration
Set dashboard.url in ~/.kiro/crew/config.json to the host and port you reach
the dashboard on:
{
"dashboard": {
"url": "http://my-host.example.com:8080"
}
}
From this single URL, Kiro Crew derives:
- Port to bind on (8080 in this example)
- Allowed origins for the CSRF / WebSocket checks
- Dashboard link hostname for
!dashboardand/kirocrew dashboard
When omitted, it defaults to port 5476 and the localhost hostname.
The gateway itself always binds loopback in this build: publishing it is your
reverse proxy's or tunnel's job, not the gateway's. KIROCREW_BIND widens the
bind address only (the container image sets KIROCREW_BIND=0.0.0.0 so a
published -p port is reachable from the host) and changes nothing about token
auth, which is mounted unconditionally on both server paths.
Dashboard to Slack Sync
A dashboard chat session can be linked to a Slack thread for two-way sync.
Linking a Session
- Open the session menu (the chevron next to the chat title, or right-click the session row in the sidebar)
- Pick a target from the link list. The Slack DM entry is always offered; other entries come from your configured channel targets
- A new thread is posted in that conversation, titled from the session title (falling back to a snippet of the first prompt), followed by the last five messages as context. Titles and message text are redacted before posting
- The menu then shows a "Connected" row for the link, plus actions to post a reminder into the thread or to unlink
Linking a session that is already linked does not create a second thread: it posts a short note into the existing thread and returns the existing link. Unlinking leaves the session, its history, and the Slack thread intact, and posts a courtesy note into the thread so a Slack-side watcher knows why it went quiet.
Two-Way Sync
- Slack to dashboard: a reply in the linked thread is routed into the linked dashboard session instead of spawning a fresh one
- Dashboard to Slack: dashboard turns are mirrored into the linked thread
sessions Command
Type sessions in any Slack DM to list recent sessions. Each entry shows a
status dot, the session title, the agent name, a bulleted preview of recent
messages, and a Resume button. The same content backs the
/<command> sessions slash command and the App Home tab.
Slack Commands Reference
Slash Commands
The slash command name is configurable via slack.command in config (default: kirocrew).
| Command | Purpose |
|---|---|
/<command> dashboard | Get a presigned dashboard link (DM'd to you) |
/<command> dashboard 2h | Dashboard link with custom duration (cap 20h) |
/<command> yolo | Toggle auto-approve all tool calls |
/<command> agent | Show agent selector dropdown |
/<command> agent <name> | Switch to a named agent |
/<command> voice | Configure TTS voice settings |
/<command> config | Manage users and channels (owner-only) |
/<command> users | Manage allowed users |
/<command> channels | Open channel management modal |
/<command> sessions | List recent sessions with resume buttons |
/<command> status | Show runtime stats |
/<command> restart | Restart the gateway (owner-only) |
/<command> #channel | Track or untrack a channel |
Any unrecognized sub-command prints the same list, generated from the live
registry, so /<command> help is not a special case: anything that does not
match falls through to it.
Owner-Only Bang Commands
These !-prefixed commands are restricted to KIROCREW_OWNER_ID.
| Command | Purpose |
|---|---|
!dashboard / !dashboard 2h | Get a presigned dashboard link |
!yolo on / !yolo off | Toggle auto-approve all tool calls |
!agent <name> / !agent off | Switch the active agent |
!ta <agent> / !ta off | Override agent for current thread only |
!link-to-dashboard | Import the current Slack thread into a dashboard session |
!project <path> / !project off | Scope which project-local .kiro agents !ta can find (does not change the working directory) |
!title <text> | Set the thread title |
!voice | Configure TTS voice settings |
!channel | Configure the current channel |
!stop | Interrupt the running turn |
!restart | Restart the gateway |
Keyword Commands
Available in DMs or @mentions.
| Command | Purpose |
|---|---|
status | Show runtime stats summary |
spawn <task> | Run a subagent (blocking) |
bg <task> | Run a subagent (fire-and-forget) |
spawn list | List active subagents |
cron list | List cron jobs |
cron remove <id> | Remove a cron job |
sessions | List recent sessions with resume buttons |
Security: Protecting Your Dashboard Token
Dashboard tokens grant full session access, so treat them like passwords.
| โ Do | โ Don't |
|---|---|
| Keep the dashboard behind your own tunnel or reverse proxy | Share dashboard URLs, which carry the token in ?token= |
If a token is exposed, run kirocrew logout (ends all sessions, refresh chains included) and revoke at your tunnel or reverse-proxy auth layer | Paste tokens in Slack channels, shared docs, or wikis |
| Avoid showing the browser URL bar during screen shares | Leave dashboard links in screen-share recordings |
Leave the built-in kirocrew token deny rules enabled | Trust an AI agent that asks to run kirocrew token |
kirocrew logout ends every issued session, not just in-memory state: it bumps
a persisted revocation generation that both access cookies and
mc_refresh_<port> refresh tokens embed, so cookies handed out before the
logout โ refresh chains included โ are rejected on their next request. See
remote-and-mobile.md. Restarting the
gateway ends nothing (the generation reloads unchanged). To cut off an exposed
dashboard completely, also revoke at your tunnel or reverse-proxy auth layer;
to end just one browser's session, sign out in that browser
(POST /api/auth/logout), which revokes its chain alone.
โ ๏ธ Prompt injection risk: an attacker can hide instructions in a webpage or document that trick your agent into running
kirocrew tokenand exfiltrating the output. Kiro Crew ships built-in denied-command rules covering that mint, including nested shell payloads and thekiro-crewspelling, enforced at the PreToolUse gate (hooks.py) rather than injected into any agent config file. They are on by default; leave them on. See ../architecture/security-deep-dive.md.
Troubleshooting
| Problem | Fix |
|---|---|
| Install App button greyed out | Use Features โ OAuth & Permissions โ Install to Workspace instead (known Slack UI bug) |
| App created in wrong workspace | Delete the app on api.slack.com, then recreate it in the correct workspace |
| No events received | Verify Socket Mode is ON, events are subscribed, App Home Chat Tab is enabled. Reinstall app after changes |
| Home tab is blank | Add app_home_opened event, enable Home Tab, reinstall app |
missing_scope error | Add the scope in OAuth & Permissions, reinstall app, re-run kirocrew setup |
| Bot doesn't respond | Check kirocrew doctor output. Ensure gateway is running (kirocrew gateway) |
| Install needs approval | Your workspace restricts app installs, so a workspace admin must approve, or use a workspace you own |
| Dashboard shows 403 | Token expired, IP changed, or the link was opened more than 5 minutes after it was issued. Run !dashboard for a new link |