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

AI-Drafted Postmortems From Slack Incident Channels

Pull an incident channel's history, summarize the timeline, extract action items, and let AI draft a blameless postmortem the incident commander owns and edits before sharing.

  • #slack
  • #chatops
  • #postmortem
  • #ai

The postmortem is the part of incident response everyone agrees matters and nobody wants to write. By the time the fire’s out, the incident commander is exhausted, the channel is six hundred messages of timestamps and “trying a rollback now,” and the doc is due in the morning. I built an AI drafter for exactly this moment — not to write the postmortem, but to do the soul-crushing first pass: reconstruct the timeline from the channel, pull out what looked like action items, and hand the IC a structured draft to edit. The key word is draft. The human still owns it. The AI just clears the blank page.

This post shows the mechanics: pulling conversation history with conversations.history, building a prompt that respects blamelessness, and formatting the output so a person can take it the rest of the way. And it shows where I draw the line, because a postmortem written by a model and shipped unread is worse than no postmortem at all.

What the AI is actually good at here

Be precise about the job. The model is a fast junior engineer who’s excellent at summarizing a long, messy transcript and terrible at knowing what actually mattered. It can turn a wall of Slack messages into a tidy timeline. It cannot tell you the real root cause, and it definitely can’t assign blame fairly — which is good, because a blameless postmortem doesn’t assign blame at all. So the AI drafts the timeline and a first cut of action items. The IC supplies judgment, root cause, and the human accountability that makes the document worth anything.

Framed that way, the draft is genuinely valuable and genuinely incomplete. That’s the right relationship.

Pulling the channel history

Slack’s conversations.history returns messages for a channel, paginated by cursor. You’ll need the channels:history (or groups:history for private channels) scope on your bot token. Bolt verifies inbound request signatures with your signing secret, but this flow is outbound API calls, so the security focus shifts: never hand the model your bot token or any secret — it only ever sees message text.

import os
from slack_sdk import WebClient

client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])

def fetch_history(channel_id):
    messages, cursor = [], None
    while True:
        resp = client.conversations_history(
            channel=channel_id,
            cursor=cursor,
            limit=200,
        )
        messages.extend(resp["messages"])
        cursor = resp.get("response_metadata", {}).get("next_cursor")
        if not cursor:
            break
    # Slack returns newest-first; reverse to chronological
    return list(reversed(messages))

If the incident lived in a thread, swap in conversations.replies with the parent ts. Either way, you now have the raw record.

Pro Tip: resolve user IDs to display names and convert each ts to a human time before you build the prompt. The model reasons far better over “14:02 — Priya: rolled back to v4.1” than over a <@U07X...> mention and a Unix float. Cleaner input, cleaner draft.

Scrubbing before you send

Incident channels leak secrets — someone pastes a connection string, a token, a curl with an auth header. Never send real secrets to the model. Run a redaction pass first, and while you’re at it, strip anything that reads as finger-pointing so the draft starts from a blameless place.

import re

SECRET_PATTERNS = [
    re.compile(r"xox[baprs]-[A-Za-z0-9-]+"),     # Slack tokens
    re.compile(r"AKIA[0-9A-Z]{16}"),             # AWS access keys
    re.compile(r"(?i)bearer\s+[a-z0-9._-]+"),    # bearer tokens
]

def clean(text):
    for pat in SECRET_PATTERNS:
        text = pat.sub("[REDACTED]", text)
    return text

def to_transcript(messages, name_for):
    lines = []
    for m in messages:
        if m.get("subtype"):  # skip joins, topic changes, etc.
            continue
        who = name_for(m.get("user", "unknown"))
        when = format_ts(m["ts"])
        lines.append(f"{when}{who}: {clean(m.get('text', ''))}")
    return "\n".join(lines)

Building the postmortem prompt

The prompt sets the format and, importantly, the tone. Blameless means systems and timelines, not people and faults.

def draft_postmortem(transcript):
    system = (
        "You draft BLAMELESS incident postmortems. Focus on systems, timeline, "
        "and contributing factors — never blame individuals. Output Markdown with "
        "these sections: Summary, Timeline, Impact, Contributing Factors, "
        "Action Items (as a checklist with owners marked TODO). "
        "Where the transcript is unclear, write 'NEEDS REVIEW' rather than guessing."
    )
    user = f"Incident channel transcript:\n\n{transcript}\n\nDraft the postmortem."
    return call_model(system, user)

The NEEDS REVIEW instruction matters more than it looks. It turns the model’s uncertainty into visible flags the IC must resolve, instead of confident filler. The draft is a starting point a human owns, and those markers are where the human’s attention goes first. If you want to tune this prompt for your org’s template, a prompt workspace lets you iterate, and our prompt library includes postmortem and retro templates worth borrowing.

Posting the draft back for editing

Drop the draft into the channel (or a thread) as a Block Kit message with a clear “this is a draft” banner, so nobody mistakes it for a finished, blessed document.

def post_draft(channel_id, markdown):
    client.chat_postMessage(
        channel=channel_id,
        text="Draft postmortem ready for review",
        blocks=[
            {
                "type": "header",
                "text": {"type": "plain_text", "text": "Draft Postmortem — review required"},
            },
            {"type": "section", "text": {"type": "mrkdwn", "text": markdown[:2900]}},
            {
                "type": "context",
                "elements": [{
                    "type": "mrkdwn",
                    "text": "AI-generated first pass. The IC owns the final version. Verify the timeline and root cause before sharing.",
                }],
            },
        ],
    )

Block Kit section text caps around 3000 characters, so for long drafts post a snippet and attach the full Markdown as a file, or split across blocks. The banner and the context footer do real work: they keep the social contract clear that a human reviews and edits before this leaves the channel.

The line I don’t cross

Two rules. First, the IC reads and edits every line before the postmortem is shared — the AI never gets the final word on root cause or action items. If you scaffolded this pipeline with help from an assistant like Claude, review that code too, especially the redaction step. Second, action items become real tracked work, not a list that dies in Slack — route them into your incident response workflow, and feed recurring contributing factors back into monitoring alerts so the next incident gets caught earlier. A code review pass on the drafter itself is worth it before it touches a real workspace.

Conclusion

AI-drafted postmortems solve the worst part of incident response — the blank page at the end of a long night — without pretending to replace the judgment a good postmortem requires. Pull the history, scrub the secrets, draft a blameless timeline, flag the uncertain bits, and hand it to the human who owns it. Treated as a first draft, it’s a gift to your future self. Treated as a finished document, it’s a hazard. Keep that distinction and the tool earns its place. More in the Slack category.

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.