InTouch Hub · Blue Isle Software

Error Postmortem Drafter

Generate a first-draft incident postmortem from a timeline + log dumps + optional chat thread. Produces Summary, Timeline, Root Cause, Resolution, Prevention, What-Went-Well, What-Didn't sections — blameless tone, ready for human edit.

Error Postmortem Drafter Skill

Drop in the artifacts of a resolved incident — timeline, logs, optional Slack thread — get back a first-draft postmortem that's 80% of the way there. Blameless tone, structured sections, ready for human editing and circulation.

The Problem

The hardest part of writing a postmortem is starting. By the time the incident is over, the on-call is exhausted, the timeline is fragmented across PagerDuty, Slack, and Datadog, and the writeup gets pushed to "next week" and then "next sprint." A first draft generated automatically the moment the incident closes turns a 2-hour blank-page slog into a 30-minute edit.

How It Works

  1. After incident resolution, an on-demand or auto-triggered job collects: - The PagerDuty incident timeline (or your equivalent) - The relevant Slack/Teams response thread - Log excerpts from the incident window
  2. The error-postmortem-drafter skill produces the markdown draft
  3. The draft is delivered to the on-call (email or Slack DM) for editing
  4. After review, the on-call publishes to your postmortem repo / Confluence / wiki

Setup

  1. Install this skill
  2. Set up integrations to gather the inputs: - PagerDuty / Opsgenie API (incident timeline) - Slack API (thread export) - Log source (CloudWatch Insights, Loki, Grafana)
  3. Use the YAML below; trigger on-demand or via a button in your incident-management tool

Example YAML Job

name: postmortem-draft
version: 1.0.0
description: Draft a postmortem from incident artifacts

notifications:
  - userNames: [intouch]
    alertOnError: true

tasks:
  - name: fetch-incident
    tool: http
    credentialName: pagerduty
    properties:
      method: GET
      url: "https://api.pagerduty.com/incidents/${INCIDENT_ID}/log_entries?include[]=channels"
      headers:
        Authorization: "Token token={{credential.secret}}"
        Accept: "application/vnd.pagerduty+json;version=2"

  - name: fetch-slack-thread
    tool: http
    credentialName: slack
    properties:
      method: GET
      url: "https://slack.com/api/conversations.replies?channel=${INCIDENT_CHANNEL}&ts=${INCIDENT_THREAD_TS}"
      headers:
        Authorization: "Bearer {{credential.secret}}"

  - name: fetch-logs
    tool: runtimeenv
    properties:
      credentialNames: ["aws"]
      scriptContent: |
        #!/bin/bash
        # Pull error-level logs from the incident window
        START_MS=$(($(date -d "${DETECTED_AT}" +%s) * 1000))
        END_MS=$(($(date -d "${RESOLVED_AT}" +%s) * 1000))
        aws logs filter-log-events \
          --log-group-name /myapp/prod \
          --start-time "$START_MS" \
          --end-time "$END_MS" \
          --filter-pattern '?ERROR ?FATAL' \
          --output text \
          --max-items 500

  - name: draft
    tool: skill
    properties:
      skillName: error-postmortem-drafter
      input: |
        incident: "${INCIDENT_TITLE}"
        severity: "${INCIDENT_SEVERITY}"
        detectedAt: "${DETECTED_AT}"
        resolvedAt: "${RESOLVED_AT}"
        customerImpact: "${CUSTOMER_IMPACT}"

        timeline:
        {{fetch-incident.responseBody}}

        chatThread:
        {{fetch-slack-thread.responseBody}}

        logs:
        {{fetch-logs.output}}

  - name: send-draft
    tool: message
    properties:
      subject: "Postmortem draft — ${INCIDENT_TITLE}"
      body: "{{draft.answer}}"
      userNames: "intouch"

Customization

Safety notes

Cost