Duty Log: Slack Bot Practices We’re Keeping This Year
The Slack bot looked finished when it answered a mention. The operational work started when Slack retried an event, a long thread exceeded the context budget, and someone pasted text that told the bot to ignore its instructions. This year, the practices worth keeping are the ones that make those situations routine: acknowledge promptly, queue durable work, limit context, and keep model output separate from permission to act.
Receive the Slack event before starting inference
For HTTP event delivery, verify Slack’s signature against the raw request body and check the request timestamp before accepting work. Use the signing secret for verification, and keep it separate from the bot token used to call Slack APIs. Follow the acknowledgment contract for the interaction you receive; Slack generally expects acknowledgment within three seconds.
A model request does not belong inside that deadline. Persist the accepted job, acknowledge the request, and let a worker perform inference. Use the event ID to deduplicate Events API deliveries, with an appropriate identifier for other interaction types. Slack retries happen, so a repeated delivery should find existing work instead of buying another completion.
Record enough job state to recover after a worker restart. Posting to Slack and updating your database are separate operations; a crash between them can still produce duplicate messages. Store the destination thread and message timestamp, and reconcile uncertain delivery before posting again.
Give each thread a bounded working context
Begin with explicit triggers such as mentions, slash commands, or direct messages. Reading every channel message expands both the privacy boundary and the bill. Request only the Slack scopes the feature needs, and check whether the requesting user is entitled to any additional information the bot retrieves.
Build each model request from a small instruction block, the current question, and selected thread history. Cap input size and output length. Summarize older turns when necessary, while preserving source references for claims that need checking. Keep workspace and thread identifiers in storage keys so conversations from different customers cannot mix.
Treat Slack messages, attachments, and retrieved documents as untrusted content. Their text can inform an answer, but it must not change application permissions or supply credentials. If the bot can update a ticket or trigger a deployment, enforce authorization in application code and require confirmation where the action warrants it.
Choose model routes against real Slack questions
Maintain a small evaluation set drawn from representative, appropriately sanitized requests: short factual questions, ambiguous mentions, long incident threads, and hostile instructions embedded in quoted material. Compare answer usefulness, response time, tool behavior, and cost before changing the default route.
A model such as Gemini 2.5 Flash could be a candidate for brief summaries, while a route using Claude Opus 5.5 could be evaluated for harder synthesis. Those are test candidates, not assumptions about performance. Confirm the provider’s exact model identifiers and supported features before deployment.
Relay365 is worth considering when one Slack bot needs access to several model families through a shared integration. It is a pay-as-you-go relay desk that works with OpenAI SDK clients. Its API base is https://api.api365relay.com; OpenAI clients use https://api.api365relay.com/v1. Test the particular route’s streaming, tool calls, error responses, and usage reporting before relying on those features.
Keep retries, spend, and replies within limits
- Set request deadlines and retry transient failures with bounded backoff, accounting for rate limits and any provider retry guidance.
- Apply concurrency limits and per-workspace spending controls so one busy channel cannot exhaust the shared budget.
- Log job identifiers, route selection, latency, retry counts, and available usage data without storing message bodies or secrets by default.
- Post one useful reply in the originating thread, and update an existing progress message sparingly when a longer task needs visible status.
Make failures understandable: tell the user when a request timed out, whether work is still running, and whether submitting it again could duplicate an action. Keep a way to disable a failing route without redeploying the bot.
If shared access to several model families fits your deployment, create a Relay365 account and run your evaluation set before connecting production traffic. Keep the integration behind a small application interface so routing changes remain reviewable. The shift should end with traceable jobs, bounded costs, and clear answers about what the bot actually did.
Further desk bulletins
| Date | Bulletin title | Filed under | Language |
|---|---|---|---|
| 2026-10-28 | Shift note: Node.js model streams reaching browsers | Wire & endpoints | EN |
| 2026-10-28 | Shift Note: Relay Requests In, Model Answers Out | Wire & endpoints | EN |
| 2026-10-28 | Duty log: model API outage review ready for handoff | Wire & endpoints | EN |
| 2026-10-28 | Shift Note: Keep API Keys Out of the Next Commit | Wire & endpoints | EN |
| 2026-10-28 | Shift Note: Requests Waiting for a Free Slot | Wire & endpoints | EN |
| 2026-10-28 | Shift Note: SDK Requests Hit the Wrong Base URL | Wire & endpoints | EN |
Curious how it runs on your own code? Sign up →