Setting Up the Slack Bot (Operator Guide)
This guide walks you through creating a Slack app, configuring it to receive events and slash commands, and installing it into a workspace via OAuth.
MyExternalCortex uses Slack's HTTP events mode: Slack sends events to your public webhook URL, which the web container verifies and forwards to the bot. This requires a live public HTTPS endpoint (already provided by the web container + nginx setup).
1. Create the Slack App
- Go to api.slack.com/apps and click Create New App.
- Choose From scratch.
- Give it a name (e.g. "MyExternalCortex" or "Aria") and select a development workspace.
- Click Create App.
2. Configure OAuth & Permissions
Go to OAuth & Permissions in the left sidebar.
Under Bot Token Scopes, add:
| Scope | Purpose |
|---|---|
chat:write |
Send messages to users |
im:history |
Read DM message history |
im:read |
List DMs |
im:write |
Open DM channels |
commands |
Register slash commands |
Under Redirect URLs, add:
https://your-domain.com/slack/oauth/callback
3. Enable Event Subscriptions
Go to Event Subscriptions and toggle Enable Events on.
Set the Request URL to:
https://your-domain.com/webhooks/slack
Slack will immediately send a URL verification challenge. Your web container must be running and reachable for this to pass. Once verified, the URL shows a green checkmark.
Under Subscribe to Bot Events, add:
message.im
Save changes.
4. Register Slash Commands
Go to Slash Commands and create each command. For all commands, use:
- Request URL: https://your-domain.com/webhooks/slack
- Escape channels, users, and links: unchecked
| Command | Description |
|---|---|
/list |
Show tasks, appointments, and reminders |
/help |
List available commands |
/summary |
Get your weekly win summary |
/set_timezone |
Update your timezone (e.g. America/Denver) |
/profile |
View your profile |
/link |
Link your Discord or Telegram account |
/unlink |
Remove a linked platform account |
/usage |
Show API usage and cost (optional days argument) |
/weblogin |
Get a one-time link to your web dashboard |
/delete_my_data |
Permanently delete all your data |
5. Get Credentials
Go to Basic Information and copy:
- Signing Secret → SLACK_SIGNING_SECRET
Go to OAuth & Permissions and copy:
- Client ID → SLACK_CLIENT_ID
- Client Secret → SLACK_CLIENT_SECRET
6. Configure Environment Variables
Add to your .env (and set in GitLab CI/CD variables for deployment):
SLACK_SIGNING_SECRET=your_signing_secret
SLACK_CLIENT_ID=your_client_id
SLACK_CLIENT_SECRET=your_client_secret
SLACK_REDIRECT_URI=https://your-domain.com/slack/oauth/callback
These must be set in both the bot and web service environments
(see docker-compose.yml).
7. Install the App to Your Workspace
Visit:
https://your-domain.com/slack/install
This redirects to Slack's OAuth consent screen. Authorize the app for your workspace. After authorization, you'll be redirected back and a success message will appear.
The workspace's bot token is now stored (encrypted) in the slack_workspaces table.
8. Verify
- DM the bot in Slack — it should respond with the onboarding prompt.
- Type
/help— you should see the command list. - Check the
slack_workspacestable has a row for your workspace:docker compose exec bot python manage.py --help
Local Development (Socket Mode)
For local dev without a public URL, use Slack's Socket Mode:
- Go to Socket Mode in the Slack app settings and enable it.
- Generate an App-Level Token with scope
connections:write. - Run separately (outside
main.py):
import asyncio
from slack_bolt.adapter.socket_mode.async_handler import AsyncSocketModeHandler
from slack_bot.client import build_app
async def main():
app = build_app(signing_secret="your_signing_secret")
handler = AsyncSocketModeHandler(app, "xapp-your-app-token")
await handler.start_async()
asyncio.run(main())
Socket Mode bypasses the webhook URL requirement — events arrive over a WebSocket connection that the bot initiates, so no public URL is needed.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| URL verification fails | Web container not running or SLACK_SIGNING_SECRET not set |
| Slash commands return "dispatch failed" | Slash command Request URL not set, or 3-second timeout exceeded (AI calls take longer — this is expected for /summary) |
| Bot doesn't respond to DMs | message.im event not subscribed, or workspace not installed |
| OAuth callback error | SLACK_CLIENT_ID / SLACK_CLIENT_SECRET wrong, or redirect URL mismatch |
503 Slack not configured from /internal/slack/events |
SLACK_SIGNING_SECRET not set in bot container |
Slash command timeout note
Slack requires a response within 3 seconds. /summary calls the AI and typically
takes 5–15 seconds. The handler calls await ack() immediately (satisfying the
timeout), then sends the response via respond() which uses Slack's response_url
for delayed delivery. This is the correct pattern and does not cause errors.