Minimal Slack bot using TypeScript and Slack Bolt. Defaults to Socket Mode (no public URL), with optional Events API (HTTP) support.
- Boom Game module (isolated):
- Detect single-emoji messages in
#capetownbetween 12:00:00–12:05:00 - One fixed 5-minute window per day, 12:00:00–12:05:00 local, shared by every emoji: it opens at noon whether or not anyone posts, and every unique entrant inside it is counted. A message counts on its own timestamp alone — not on when Slack delivered it, and not on who posted first
- One entry per player per emoji: accepted entries get a ✅ reaction to confirm they are in the tally
- When the window closes, the
nentrants each draw a unique random amount between 1 andn(3 people sending 💥 split 3/2/1 in random order; 9 people sending :hadeda-boom: split 9…1) - Post the daily results + week-to-date leaderboard once every game for the day has settled; medals go to the three biggest point earners
- Crown weekly winner(s) once Friday’s games have settled; leaderboard resets weekly (Mon)
- The bot adds a 🤡 reaction (and ignores the message entirely) if a boom emoji is posted outside the 12:00–12:05 window, after the day’s points are assigned, or as a repeat by a player who already entered that game
- A required game nobody entered settles empty when the window shuts, rendering as
— no entries, so the day's results (and a Friday crown) never stall on a game nobody played - The crown is recorded only after its message posts, so a failed post is retried rather than leaving a king nobody was told about
- On a weekend or public holiday the "Boom isn't played today" notice is posted once per date, not once per poster
- Detect single-emoji messages in
- Chat (mentions):
- AI-powered chat replies when a user mentions the bot (except "leaderboard", handled by Boom).
- History is in-memory only, keyed by channel, and pruned by configurable caps. Replies honor
DEFAULT_REPLY_MODE(thread or channel). - Configure via CHAT_* env vars; optional
CHAT_CONFIGfile for defaultsystemPrompt,temperature, andmaxTokens. - Admin-only update of the default prompt from Slack:
@bot chat update default prompt <new system prompt>. - Admin-only context commands:
@bot clear chat(clears current channel context) and@bot clear chat all(clears all channel contexts). Replies are sent as ephemeral confirmations. - Rate limits: 1 request per user per minute, 20 requests per channel per minute
- Socket Mode by default; optional Events API
- Incoming event logging to aid development
- Channel allowlist and dedupe middleware in place
- Feature toggles via
FEATURESenv (default:boom,chat)
- Create a Slack app and bot user. See
docs/SETUP.md. - Copy
.env.exampleto.envand fill values. - Install deps and run locally:
npm install # Dev (hot reload) using tsx (stable on Node 22/24) npm run dev # If dev has issues, run the compiled app: npm run build && npm start
- Socket Mode (default): requires
SLACK_APP_TOKENandSLACK_BOT_TOKEN. - Events API: requires
SLACK_SIGNING_SECRETandSLACK_BOT_TOKEN(and a public HTTPS URL).
See docs/CONFIG.md for more details.
npm run dev— run with tsx (watch mode)npm run dev:run— run once with tsxnpm run build— compile TypeScript todist/npm start— run compiled app fromdist/npm run serve— production runner (builds if needed, then starts)
- Bot Token Scopes:
chat:writeapp_mentions:readchannels:history(public channels) and optionallygroups:history(private channels)reactions:write(to add reactions for wins and clowning)
- Event Subscriptions → Subscribe to bot events:
app_mention(for chat)message.channels(public channel messages)message.groups(private channels, if used)
- Reinstall the app after adding scopes/events, then invite it to your channels.
- Set in
.env:TIMEZONE=Africa/JohannesburgALLOWED_CHANNELS=C0919MX7KJS(your#capetownchannel ID)- Optionally
HOLIDAYS=YYYY-MM-DD,YYYY-MM-DDto add extra dates - Optionally
BOOM_SCORING=random(legacyrestores the 3-2-1 podium; takes effect at the next restart) - Random mode only:
BOOM_ENTRY_WINDOW_MS=300000(how long the window stays open from 12:00:00 local; points are assigned 5s after it shuts) - Legacy mode only:
BOOM_ANNOUNCE_GRACE_MS=15000(delay between a full podium and the announcement) - Chat fallback is configurable via
CHAT_*variables. See docs/CONFIG.md.
- Seeded SA public holidays for 2025 at
data/holidays/za-2025.json. - To adjust or add another year, place a JSON file at
data/holidays/za-<year>.jsoncontaining an array ofYYYY-MM-DDdates.
- Uses a simple JSON file at
data/store.jsonfor wins, counts, daily announcements, and weekly crowns. No native modules required.
- If you later want to react to private-channel messages, add the
groups:historyscope and subscribe to themessage.groupsbot event in your Slack app settings, then reinstall the app.
You can run the bot on server boot and keep it alive using either systemd (recommended) or PM2. The app reads .env from the repo root via dotenv, so ensure it exists and is correct.
-
Edit
systemd/slack-bot.serviceif needed:- Set
User/Groupto a non‑root service account (recommended). - Set
WorkingDirectoryand theExecStartpath to your deployed repo path.
- Set
-
Install and enable:
sudo cp systemd/slack-bot.service /etc/systemd/system/slack-bot.service
sudo systemctl daemon-reload
sudo systemctl enable --now slack-bot- Logs and management:
sudo systemctl status slack-bot
sudo journalctl -u slack-bot -f
sudo systemctl restart slack-botNotes:
- The unit runs
scripts/run-prod.sh, which builds if needed and then launches the compiled app. Remove the install/build steps if your deployment pipeline already builds artifacts. - To update: pull changes, then
sudo systemctl restart slack-bot.
If you prefer PM2:
npm install -g pm2
pm2 start ecosystem.config.cjs
pm2 save
pm2 startup # follow the printed command to enable on bootLogs and management:
pm2 logs slack-bot-ts
pm2 restart slack-bot-ts
pm2 status