Post AI-Generated SLO and Error-Budget Reports to Slack Weekly
Turn SLO metrics into plain-language error-budget reports in Slack with AI. Bolt, Block Kit, signed interactions, and a human read before the team sees it.
- #slack
- #chatops
- #ai
- #sre
We had SLOs. They lived in a dashboard nobody opened between incidents. The error budget would quietly burn down all month and then someone would be surprised we were out of room to ship risky changes. I wanted the budget in front of the team every week, in words, with a clear “are we okay to ship?” verdict. So I built a bot that reads the SLO numbers, has a model write the weekly narrative, and posts it to #sre. The discipline was keeping the math in code and the judgment with a human.
What an error-budget report should say
A good error-budget report answers three questions: how much budget is left, how fast we are burning it, and what that means for our freedom to take risks this week. The numbers come from your monitoring system. The translation, “we have burned 70 percent of the budget with two weeks left, so slow down on risky deploys,” is the part that gets skipped because writing it weekly is tedious. That tedium is exactly what a model removes, as long as it explains numbers you have already computed rather than inventing its own.
Computing the budget in code
I never let the model touch SLO arithmetic. It computes nothing; it narrates.
function computeBudget(slo, windowDays, successRatio) {
const allowedFailureRatio = 1 - slo; // e.g. 0.001 for 99.9%
const actualFailureRatio = 1 - successRatio;
const budgetUsedPct = (actualFailureRatio / allowedFailureRatio) * 100;
const daysElapsed = windowDays * (/* fraction of window */ 0.5);
const burnRate = budgetUsedPct / ((daysElapsed / windowDays) * 100);
return { budgetUsedPct, burnRate, healthy: budgetUsedPct < 100 && burnRate < 1.5 };
}
Every number in the final Slack message traces back to this function. The model gets the results, not the raw event stream.
Letting the model write the narrative
I hand the computed budget figures to the model and ask for a short, honest narrative with a clear verdict.
const prompt = `Write a 3-4 sentence weekly SLO report for an SRE channel.
State budget used, burn rate, and a clear verdict:
"healthy", "caution", or "freeze risky deploys".
Use only these numbers; do not invent metrics.
${JSON.stringify(budgetByService, null, 2)}`;
The model is a fast junior SRE here: fluent at phrasing the situation, not the source of truth for whether we are healthy. I even compute the verdict (healthy flag) in code and pass it in, so the model phrases a decision I have already made rather than making the call itself.
Pro Tip: Pass the verdict as data, not as something for the model to derive. “Freeze deploys” is an operational decision with real consequences; let your code own that threshold and let the model only describe it.
Rendering the report
Block Kit gives the report a scannable shape with the verdict up top:
function buildSloBlocks(report, services) {
return [
{ type: "header", text: { type: "plain_text", text: "Weekly SLO Report 📊" } },
{ type: "section", text: { type: "mrkdwn", text: report.narrative } },
{ type: "divider" },
...services.map((s) => ({
type: "section",
fields: [
{ type: "mrkdwn", text: `*${s.name}*\n${s.healthy ? "🟢 healthy" : "🔴 over budget"}` },
{ type: "mrkdwn", text: `*Budget used*\n${s.budgetUsedPct.toFixed(0)}% (burn ${s.burnRate.toFixed(1)}x)` },
],
})),
];
}
Posting via Bolt
const { App } = require("@slack/bolt");
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
async function postSloReport(blocks) {
await app.client.chat.postMessage({
channel: "#sre",
blocks,
text: "Weekly SLO and error-budget report", // notification fallback
});
}
Human review before it sets policy
Here is the catch with SLO reports: a “freeze risky deploys” verdict changes what the team does this week. That is too much weight to put on an unreviewed generation. So the bot posts the report to a draft channel first with an “Approve and publish” button. The on-call SRE reads it, confirms the verdict matches reality (sometimes the budget burn was a known load test, not a regression), and approves.
app.action("publish_slo", async ({ ack, body, client }) => {
await ack();
await client.chat.postMessage({
channel: "#sre",
blocks: JSON.parse(body.actions[0].value),
text: "Weekly SLO report",
});
});
The AI writes fast; a human confirms before the report can influence what ships. This is the same rule I apply to anything a bot says that carries operational weight in a real workspace.
Verify the inbound interaction
The approve button posts back to a public endpoint, so signatures get checked. Bolt verifies the X-Slack-Signature HMAC against the raw request body and rejects stale timestamps to stop replays. If you build a raw handler, do that check yourself. The monitoring data the model sees is aggregate ratios and service names, never an API token or a credential.
Tuning and fit
I iterated on the narrative prompt in the prompt workspace against several weeks of real SLO data, then promoted the working version to prompts. The SRE reporting templates in the prompt packs gave me a tested starting structure. Operationally this lives next to the rest of the alerting story in monitoring alerts.
For building it, I used Claude for the narrative prompt and Cursor for the Block Kit rendering, reviewing each change. More patterns are collected in the Slack category.
Conclusion
A weekly error-budget report in Slack keeps the whole team honest about how much risk they can afford. Compute the budget in code, hand the model the numbers and the verdict, let it write the narrative, and require a human to approve before a “freeze deploys” call goes public. Verify every inbound signature and keep credentials out of the prompt. The model narrates; your code and your SRE decide. That is what makes the report something the team trusts enough to act on.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.