Draft Customer Status-Page Updates From Slack Incidents With AI
Use AI to turn internal Slack incident chatter into clear, public status-page updates. Bolt, Block Kit, signed events, and mandatory human approval before posting.
- #slack
- #chatops
- #ai
- #incidents
During an incident, the last thing anyone wants to do is write a careful, customer-facing status update. The team is heads-down fixing the problem, and the public update gets either forgotten or hastily written in a way that says too much or too little. I built a bot that watches the incident channel, drafts a clean public update in the right tone, and presents it for one-click approval. The single most important design decision was that the bot never posts to the status page on its own. A human always approves first.
Internal chatter is not a public update
The incident channel is full of raw, candid engineering talk: “the db is hosed,” “rolling back the bad deploy,” “still seeing 500s.” None of that belongs on a status page. A public update needs to be calm, specific about impact, vague about internal blame, and honest about timeline. Translating internal urgency into external reassurance is a writing task with real stakes, and it is exactly where a model can produce a strong first draft, as long as a human reviews the tone and accuracy before customers see it.
Watching the incident channel
The bot listens to messages in incident channels and keeps a rolling summary of the situation. When someone triggers it with a slash command or a reaction, it drafts an update from the recent context.
const { App } = require("@slack/bolt");
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
app.command("/status-draft", async ({ command, ack, client }) => {
await ack();
const history = await client.conversations.history({ channel: command.channel_id, limit: 50 });
const draft = await draftStatusUpdate(history.messages);
await client.chat.postEphemeral({
channel: command.channel_id,
user: command.user_id,
blocks: buildDraftBlocks(draft),
text: "Status update draft",
});
});
I use postEphemeral so the draft is visible only to the person who requested it. The draft is a work product, not a broadcast, until it is approved.
Drafting in the right register
The prompt teaches the model the voice of a status page: customer-impact first, no internal jargon, no speculation about cause, clear next-update time.
const systemPrompt = `You write public status-page updates from internal incident chatter.
Lead with customer impact in plain language.
Never name internal systems, people, or root-cause speculation.
State current status and when the next update will come.
Keep it under 60 words. Tone: calm, honest, professional.`;
The model is a fast junior comms writer here. It nails the structure and tone far faster than a stressed engineer mid-incident, but it does not know what is actually safe to say publicly. That judgment stays human.
Pro Tip: Give the model the incident severity as an input and ask it to match the update’s tone to it. A SEV3 “minor degradation” reads very differently from a SEV1 “service unavailable,” and the model will pick the wrong register if you do not tell it which one you are in.
The approval gate
This is the heart of the bot. The draft comes with an “Edit” field and an “Approve and publish” button. Nothing reaches the status page until a human clicks approve.
function buildDraftBlocks(draft) {
return [
{ type: "section", text: { type: "mrkdwn", text: `*Draft public update:*\n>${draft.text}` } },
{
type: "actions",
elements: [
{ type: "button", text: { type: "plain_text", text: "Approve and publish" }, style: "primary", action_id: "publish_status", value: draft.text },
{ type: "button", text: { type: "plain_text", text: "Edit" }, action_id: "edit_status", value: draft.text },
],
},
];
}
app.action("publish_status", async ({ ack, body, client }) => {
await ack();
await publishToStatusPage(body.actions[0].value); // the only place we post publicly
await client.chat.postMessage({
channel: body.channel.id,
text: `Public status update published by <@${body.user.id}>.`,
});
});
The “Edit” path opens a modal pre-filled with the draft so the approver can fix a word before publishing. Most of the time the draft is good; the value is that a human always reads it first. I cannot overstate this: an AI-written sentence on a public status page during a SEV1 is a brand-and-trust event if it is wrong. The model drafts; a person ships.
Posting the resolution too
The same flow handles the “resolved” update at the end. The bot drafts a closing message summarizing impact and resolution, and again it waits for approval. This keeps the status page consistent in tone from first alert to all-clear.
Security and tokens
Slash commands and button interactions hit a public endpoint, so every request is verified. Bolt checks the Slack signing secret against the raw body and the request timestamp, rejecting anything stale to prevent replay. If you ever bypass Bolt with a raw handler, do that HMAC verification yourself. The bot token and the status-page API key both live in environment variables and never enter the prompt; the model sees incident message text only, and I scrub anything that looks like a credential or customer PII before it does.
Where it fits and how I built it
This bot is the public-facing companion to internal incident tooling. It sits naturally beside incident response, which handles the internal coordination while this handles the external voice. I tuned the status-update prompt in the prompt workspace against anonymized real incidents, then saved the working version to prompts. The incident-comms templates in the prompt packs gave me the tone guidance to start from.
For building the Bolt handlers and modal I used Claude and GitHub Copilot, reviewing each change. The broader Slack incident patterns are collected in the Slack category.
Conclusion
An AI status-draft bot removes the worst friction in incident communication: writing a calm public update while everything is on fire. Let the model draft from internal chatter in the right register, present it ephemerally, and require a human to approve before a single word reaches customers. Verify every inbound signature, keep tokens and PII out of the prompt, and remember that on a public status page the human review is not optional. The AI writes the draft; a person owns what ships.
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.