Local Slack runbook
Synced from
channels/docs/runbooks/slack-local.md. The repository is the source of truth.
Use this runbook to connect the current Channels checkout to a real Slack app, run the bot on your workstation, and verify one mention-to-reply round trip. Socket Mode is outbound: the local process needs no HTTP listener, public URL, or tunnel.
Slack setup links:
- Create or manage Slack apps — select Create New App to add the bot to a workspace.
- Slack’s official Socket Mode setup
— documents app-level tokens,
connections:write, event subscriptions, and why Socket Mode needs no Request URL. - Create an app from Slack’s app settings — Slack’s browser-based app creation walkthrough.
Success criteria
Section titled “Success criteria”The test passes only when all of these are true:
- the resident process connects as the expected bot;
- a human posts one marked, top-level mention in a channel the bot has joined;
- the bot posts exactly one later reply in that message’s thread;
- the bot adds its handled reaction to the mention; and
npm run verify:slackexits zero.
Prerequisites
Section titled “Prerequisites”You need:
- permission to create or install an app in the company Slack workspace, or an app administrator who can approve it;
- a dedicated test channel;
- Node.js, npm, and
pionPATH; - this repository with dependencies installed; and
- working Pi credentials for the selected model.
From the repository root:
npm installpi --versionnpm run checkThe local runner defaults to openai-codex/gpt-5.4-mini. Set
SLACK_DEV_MODEL if your Pi installation uses another authenticated model.
Configure the Slack app
Section titled “Configure the Slack app”Use one app installed in the same workspace as the test channel. If company policy restricts app creation, scopes, or installation, give the following configuration to a Slack app administrator and wait for approval before continuing.
-
Open Slack’s Your Apps page, then create or select the app in the target workspace.
-
Under Socket Mode, enable Socket Mode.
-
Under Basic Information → App-Level Tokens, generate a token with
connections:write. Save the resultingxapp-…token. -
Under OAuth & Permissions → Bot Token Scopes, add:
app_mentions:readchannels:historychat:writereactions:write
Add
groups:historyonly when the test channel is private. Do not addchat:write.public, user-token, or admin scopes. -
Under Event Subscriptions, enable events and subscribe the bot to
app_mention. Socket Mode does not use a Request URL. -
Install the app to the workspace. If the app was already installed, reinstall it after changing scopes.
-
Copy the installed bot token from OAuth & Permissions. It starts with
xoxb-. -
Invite the bot to the dedicated test channel with
/invite @your-bot. -
For verification, open the test channel details and copy its channel ID, such as
C0123ABCD.
The app token, bot token, and channel ID must belong to this app and workspace.
Slack documents the same setup in
Using Socket Mode
and the app_mention event reference.
Set the local environment
Section titled “Set the local environment”The local runner defaults to every channel the bot has joined. Set
SLACK_CHANNEL_IDS=joined explicitly for clarity, or omit it. One or more
channel IDs narrow handling to those channels. joined cannot be mixed with
channel IDs.
The checkout ignores .env.slack.local. The runner loads it automatically when
present:
SLACK_CLI_APP_ID=A0BKPNHJ12NSLACK_CLI_TEAM_ID=T7GCW93AASLACK_CLI_APP_NAME=nonprod-botSLACK_CLI_ENVIRONMENT=localSLACK_CHANNEL_IDS=joinedSLACK_VERIFY_CHANNEL_IDS=C0123ABCDRestrict the file to your account:
chmod 600 .env.slack.localSet SLACK_DOTENV to another path if a password manager or local secrets
workflow writes the file elsewhere.
Preferred: Slack CLI-managed tokens
Section titled “Preferred: Slack CLI-managed tokens”Install and authenticate the Slack CLI, then run:
npm run setup:slacknpm run dev:slack:clisetup:slack creates the ignored dev/nonprod-bot project from Slack’s blank
Bolt template and copies in the repository’s small manifest and launcher
templates. dev:slack:cli runs that project, allowing Slack CLI to inject
SLACK_APP_TOKEN and SLACK_BOT_TOKEN without persisting either secret in the
repository or dotenv.
Alternative: provide tokens directly
Section titled “Alternative: provide tokens directly”To run without Slack CLI, enter tokens without putting their values in shell history:
read -rsp "Slack app token (xapp-): " SLACK_APP_TOKEN; echoread -rsp "Slack bot token (xoxb-): " SLACK_BOT_TOKEN; echoread -rp "Slack verification channel ID: " SLACK_VERIFY_CHANNEL_IDSexport SLACK_APP_TOKEN SLACK_BOT_TOKEN SLACK_VERIFY_CHANNEL_IDSOptional overrides:
export SLACK_DEV_MODEL="openai-codex/gpt-5.4-mini"export SLACK_VERIFY_MARKER="[channels-local-smoke]"export LINK_SLACK_DONE_EMOJI="white_check_mark"Then run npm run dev:slack. Do not commit the tokens, paste them into chat, or
store them in a tracked .env file. The verification terminal needs the same
credentials when it is not launched by Slack CLI, plus the same marker and
emoji overrides.
Start the resident bot
Section titled “Start the resident bot”With Slack CLI, npm run dev:slack:cli performs setup and starts the resident
bot. With direct token environment variables, run:
npm run dev:slackThe command:
- authenticates the bot token with
auth.test; - verifies every explicit channel ID, or uses Slack membership as the boundary
in the default
joinedmode; and - starts Pi in resident RPC mode with only
channel_readandchannel_respond.
Wait for output like:
Slack bot U… authenticated.Listening for mentions in every channel the bot has joined.[channels:slack] socket mode connected as U…The first two lines validate the bot token and channel access. The connection line validates the app-level token and Socket Mode.
Send the test mention
Section titled “Send the test mention”Post a new top-level message in any channel the bot has joined. Replace @your-bot
with the installed app:
@your-bot [channels-local-smoke] Reply with a one-sentence confirmation that the local channel test works.If you changed SLACK_VERIFY_MARKER, use that exact marker. The verifier scans
top-level channel history for the marked mention.
Verify the round trip
Section titled “Verify the round trip”After the bot replies, open a second terminal and set the same environment variables. Then run:
npm run verify:slackA passing result contains only structural evidence:
Slack local round trip verified: channel: C… mention: 17….…… thread: 17….…… reply: 17….…… handled: white_check_markWhen the listener uses joined, SLACK_VERIFY_CHANNEL_IDS tells the verifier
which test channel to inspect without requiring broad channel-list scopes. The
verifier exits nonzero unless it finds the latest marked human mention,
exactly one later reply from the bot, and the bot’s handled reaction. It does
not print message content or tokens.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check |
|---|---|
SLACK_APP_TOKEN must be an xapp-… |
Generate an app-level token under Basic Information with connections:write. Do not use the bot token here. |
SLACK_BOT_TOKEN must be an xoxb-… or authentication fails |
Copy the installed bot token from OAuth & Permissions. Reinstall or rotate the app if the token was revoked. |
missing_scope |
Add the scope named by Slack, then reinstall the app so the installed bot receives it. |
not_in_channel, channel_not_found, or preflight cannot read the channel |
Invite the bot to the channel. For an explicit ID, also confirm the ID and workspace; add groups:history for a private channel. |
| Company approval is pending | Ask the Slack app administrator to approve the app, listed scopes, installation, and dedicated test channel. |
| Socket Mode never connects | Confirm Socket Mode is enabled and the xapp-… token has connections:write. |
| Socket connects but mentions do not wake the bot | Confirm Event Subscriptions is enabled, app_mention is subscribed, and the bot is invited. If using explicit IDs, confirm the channel is included. |
| The bot replies but verification reports no reaction | Confirm reactions:write, reinstall after scope changes, and use the same LINK_SLACK_DONE_EMOJI in both terminals. |
| Pi reports a model or authentication error | Set SLACK_DEV_MODEL to a model for which local Pi authentication is configured. |
| Verification cannot find the mention | Post the marked test as a new top-level message and use the same SLACK_VERIFY_MARKER in the second terminal. |
Stop and clean up
Section titled “Stop and clean up”Stop the resident process with Ctrl-C. Then remove the token values from each terminal:
unset SLACK_APP_TOKEN SLACK_BOT_TOKEN SLACK_CHANNEL_IDS SLACK_VERIFY_CHANNEL_IDSRemove the app from the test channel if it should not remain there. If either token was exposed in source, logs, shell history, or chat, rotate it immediately in the Slack app settings.