Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Slack By James Joyner IV · · 11 min read

Send AI-Summarized Cloud Cost Alerts to Slack Without the Spreadsheet

Turn raw cloud billing data into plain-language cost alerts in Slack with AI. Bolt, Block Kit, signed webhooks, and a human check before anyone panics.

  • #slack
  • #chatops
  • #ai
  • #finops

The monthly cloud bill used to arrive as a surprise. By the time finance noticed a spike, the spend was already locked in. I wanted the spike to show up in Slack the day it started, explained in language a sleepy on-call engineer could parse at 7am. So I built a bot that reads the cost data, asks a model to explain what changed and why it probably changed, and posts a short, actionable summary. The hard part was making sure the explanation was grounded in real numbers and reviewed before it caused a fire drill.

Why summarize cost data at all

Cloud billing exports are precise and unreadable. A daily cost-and-usage report has hundreds of line items by service, region, and tag. A human scanning it sees noise. The signal, “EC2 in us-east-1 jumped 40 percent yesterday, driven by a new tag we have never seen,” is buried. Turning that into one sentence is a translation task, and translation is what a model is good at, provided you give it the actual numbers and ask it not to speculate beyond them.

Pulling the numbers first

I compute the deltas in code, not in the model. The model should never do arithmetic on a budget; it should explain arithmetic I already trust.

async function computeCostDeltas() {
  const today = await getCostByService("yesterday");
  const baseline = await getCostByService("7d-trailing-avg");
  return Object.entries(today)
    .map(([service, cost]) => ({
      service,
      cost,
      delta: cost - (baseline[service] || 0),
      pct: baseline[service] ? (cost / baseline[service] - 1) * 100 : null,
    }))
    .filter((d) => Math.abs(d.delta) > 25) // ignore noise under $25
    .sort((a, b) => b.delta - a.delta);
}

Filtering tiny deltas keeps the channel from crying wolf. Only material changes earn a message.

Letting the model explain, not calculate

I hand the computed deltas to the model and ask for a plain-language summary plus a likely cause based only on the service names and tags it can see.

const prompt = `These are yesterday's cloud cost changes vs a 7-day baseline.
Write a 2-3 sentence Slack summary for an on-call engineer.
Name the biggest driver and a plausible cause from the service/tag names.
Do NOT invent dollar amounts; use only the numbers given.

${JSON.stringify(deltas, null, 2)}`;

The “do not invent dollar amounts” instruction is non-negotiable. The model is a fast junior analyst: great at phrasing, not to be trusted with the books. Every figure in the final message comes from my code, not its imagination.

Pro Tip: Include the previous baseline in the prompt so the model can say “up from $X to $Y” using your verified numbers. If you only pass the delta, it will sometimes back-calculate and get it subtly wrong.

Rendering an alert people will act on

A cost alert needs to be scannable and lead with the action. Block Kit handles the structure:

function buildCostBlocks(summary, topDriver) {
  return [
    { type: "header", text: { type: "plain_text", text: "Cost Alert 💸" } },
    { type: "section", text: { type: "mrkdwn", text: summary } },
    {
      type: "section",
      fields: [
        { type: "mrkdwn", text: `*Top driver*\n${topDriver.service}` },
        { type: "mrkdwn", text: `*Change*\n+$${topDriver.delta.toFixed(0)} (${topDriver.pct?.toFixed(0)}%)` },
      ],
    },
    {
      type: "actions",
      elements: [
        { type: "button", text: { type: "plain_text", text: "Open cost dashboard" }, url: process.env.COST_DASH_URL },
        { type: "button", text: { type: "plain_text", text: "Acknowledge" }, action_id: "ack_cost" },
      ],
    },
  ];
}

Posting it with Bolt

const { App } = require("@slack/bolt");
const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

async function postCostAlert(blocks) {
  await app.client.chat.postMessage({
    channel: "#finops",
    blocks,
    text: "Daily cloud cost alert", // notification fallback
  });
}

The acknowledge loop and human judgment

The “Acknowledge” button is the human seam. A cost spike is not automatically a problem; sometimes it is a planned load test. When someone acks, the bot records who looked and stops re-alerting on the same driver for the day.

app.action("ack_cost", async ({ ack, body, client }) => {
  await ack();
  await client.chat.update({
    channel: body.channel.id,
    ts: body.message.ts,
    text: `Acknowledged by <@${body.user.id}>`,
    blocks: appendAckNote(body.message.blocks, body.user.id),
  });
});

This keeps a person in the decision. The AI flags and explains; a human decides whether it matters. I never let the bot trigger an automated scale-down or budget action on its own. The cost of a wrong autonomous action here is real money or a real outage.

Verify the inbound interactions

The acknowledge button posts an interaction payload to my endpoint, which is internet-facing. Bolt verifies the Slack signing secret on every request, checking the signature against the raw body and rejecting old timestamps. If you wire a raw handler, do that HMAC check yourself. And the billing data the model sees has account IDs and access keys stripped before it ever leaves my process; the model gets service names and dollar deltas, never credentials.

Tuning the prompt

I built the summary prompt iteratively in the prompt workspace using a week of real cost exports, then promoted the stable version into prompts. The FinOps and alerting templates in the prompt packs are a faster on-ramp if you do not want to start blank. For the alerting side of the house more broadly, this sits next to monitoring alerts.

For building the bot, I leaned on Claude for the summary prompt and Cursor for the Bolt and Block Kit scaffolding, reviewing each change. More patterns live in the Slack category.

Conclusion

A cost alert that lands in Slack the morning a spike starts is worth more than a perfect report nobody reads. Compute the numbers in code, let the model translate them into plain language, render an actionable Block Kit message, and keep a human on the acknowledge button. Verify every inbound signature and keep credentials out of the prompt. The model explains; you decide. That division of labor is what makes the alert trustworthy.

Free download · 368-page PDF

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.