🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Build an AI Incident Timeline Reconstructor with Claude API

Writing an incident timeline after the fact means manually cross-referencing Slack messages, deploy logs, alert timestamps, and PagerDuty events. Build a tool that pulls all of it together and generates an accurate, chronological timeline with Claude API.

Shubham3 min read
Share:Tweet

Postmortem timelines are almost always reconstructed hours or days after the incident, from memory and scattered sources — which is exactly when details get fuzzy or reordered. This tool pulls the actual timestamped evidence from every system involved and lets Claude assemble it into a coherent, accurate timeline before anyone has to rely on memory.

Setup

bash
pip install anthropic slack-sdk requests

Data Collectors

python
import anthropic
from slack_sdk import WebClient
from datetime import datetime, timedelta
import requests
 
client = anthropic.Anthropic()
 
 
def get_slack_incident_channel_history(channel_id: str, slack_token: str) -> list[dict]:
    slack = WebClient(token=slack_token)
    history = slack.conversations_history(channel=channel_id, limit=200)
    return [
        {"timestamp": msg["ts"], "user": msg.get("user", "unknown"), "text": msg.get("text", "")}
        for msg in history["messages"]
        if msg.get("text")
    ]
 
 
def get_deploy_events(service: str, start: datetime, end: datetime) -> list[dict]:
    """Pull deploy events from your CD system's audit log."""
    resp = requests.get(
        f"https://cd.internal/api/deployments",
        params={"service": service, "since": start.isoformat(), "until": end.isoformat()}
    )
    return resp.json()["deployments"]
 
 
def get_alert_events(start: datetime, end: datetime, pagerduty_token: str) -> list[dict]:
    resp = requests.get(
        "https://api.pagerduty.com/incidents",
        headers={"Authorization": f"Token token={pagerduty_token}"},
        params={"since": start.isoformat(), "until": end.isoformat()}
    )
    return [{"title": i["title"], "created_at": i["created_at"], "status": i["status"]}
            for i in resp.json()["incidents"]]
 
 
def get_metric_anomalies(service: str, start: datetime, end: datetime) -> list[dict]:
    """Pull relevant metric threshold breaches from Prometheus Alertmanager history."""
    resp = requests.get(
        "http://alertmanager:9093/api/v2/alerts/history",
        params={"filter": f'service="{service}"', "start": start.isoformat(), "end": end.isoformat()}
    )
    return resp.json()

Timeline Reconstruction with Claude

python
import json
 
RECONSTRUCT_PROMPT = """Reconstruct an accurate incident timeline from these
raw data sources, all from the same incident window.
 
Slack channel messages (chronological, with timestamps):
{slack_messages}
 
Deployment events:
{deploy_events}
 
PagerDuty alert events:
{alert_events}
 
Metric anomaly/threshold breach events:
{metric_events}
 
Build a single, merged, chronological timeline. For each event:
- Exact timestamp
- What happened (be specific — "deploy of api v2.4.1 to production" not "a deploy happened")
- Source (deploy log / alert / human observation from Slack)
 
Also identify:
- The likely trigger event (what started the incident)
- Time from trigger to first alert (detection time)
- Time from first alert to first human acknowledgment
- Time from acknowledgment to resolution
 
Format as a clean markdown timeline suitable for a postmortem document."""
 
 
def reconstruct_timeline(slack_messages: list, deploy_events: list, alert_events: list, metric_events: list) -> str:
    response = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=3000,
        messages=[{
            "role": "user",
            "content": RECONSTRUCT_PROMPT.format(
                slack_messages=json.dumps(slack_messages, indent=2)[:4000],
                deploy_events=json.dumps(deploy_events, indent=2),
                alert_events=json.dumps(alert_events, indent=2),
                metric_events=json.dumps(metric_events, indent=2)[:2000],
            )
        }]
    )
    return response.content[0].text

Example Output

markdown
## Incident Timeline — Payments API Degradation, 2026-07-31
 
**14:02:15** — Deploy: `payments-api v2.4.1` to production (source: CD log)
**14:04:32** — Metric anomaly: p99 latency crosses 2000ms threshold (source: Alertmanager)
**14:04:58** — PagerDuty alert triggered: "Payments API High Latency" (source: PagerDuty)
**14:07:41** — First human acknowledgment in #incident-payments-api (source: Slack, @priya)
**14:09:03** — Slack: "checking the new deploy, might be the connection pool change" (source: Slack, @priya)
**14:12:30** — Deploy: rollback to `v2.4.0` initiated (source: CD log)
**14:15:47** — Metric anomaly resolved: p99 latency back under 500ms (source: Alertmanager)
**14:16:02** — PagerDuty incident resolved (source: PagerDuty)
 
**Likely trigger:** Deploy of v2.4.1 at 14:02:15 (2m17s before first anomaly)
**Detection time:** 2m17s (deploy to first alert)
**Acknowledgment time:** 2m43s (alert to human ack)
**Resolution time:** 6m49s (ack to resolution via rollback)

Usage

bash
python reconstruct_timeline.py \
  --incident-channel C0123ABCDEF \
  --service payments-api \
  --start "2026-07-31T14:00:00" \
  --end "2026-07-31T14:30:00" \
  --output timeline.md

Why This Matters for Postmortem Quality

The value here isn't just saving reconstruction time — it's accuracy. A human reconstructing a timeline from memory two days later reliably compresses or reorders events, especially the gap between "alert fired" and "someone actually looked at it," which is exactly the number most postmortems need to be honest about to drive real process improvements. Pulling from actual timestamped system data removes that memory distortion entirely.


More AI incident response tooling? Read our Build AI incident postmortem generator and Build AI SRE incident commander with Claude API.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Build an AI Load Test Scenario Generator with Claude API

Writing realistic k6 or Locust load test scenarios means understanding actual traffic patterns, not just hammering one endpoint. Build a tool that reads your API spec and real traffic logs, then generates realistic load test scripts with Claude API.

S
3 min readRead

Comments