incident-trend-analyzer

On-demand postmortem trend analysis — recurrence grouping, trigger categorization, MTTR/MTTD from canonical docs/postmortems/ corpus

Best use case

incident-trend-analyzer is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

On-demand postmortem trend analysis — recurrence grouping, trigger categorization, MTTR/MTTD from canonical docs/postmortems/ corpus

Teams using incident-trend-analyzer should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/incident-trend-analyzer/SKILL.md --create-dirs "https://raw.githubusercontent.com/damianpapadopoulos/auto-claude-skills/main/skills/incident-trend-analyzer/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/incident-trend-analyzer/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How incident-trend-analyzer Compares

Feature / Agentincident-trend-analyzerStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

On-demand postmortem trend analysis — recurrence grouping, trigger categorization, MTTR/MTTD from canonical docs/postmortems/ corpus

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Incident Trend Analyzer

On-demand analysis of historical postmortems from `docs/postmortems/`. Reads canonical postmortems produced by the incident-analysis skill, extracts normalized incident records, surfaces recurrence patterns, trigger distributions, and timing metrics. Terminal-first output with optional persistence on request.

## Step 1: Scan Corpus

If `docs/postmortems/` does not exist, report: "No postmortem corpus found. Expected directory: `docs/postmortems/`. Run incident-analysis to generate postmortems first." and stop.

Read `docs/postmortems/*.md` — **NON-RECURSIVE**. Do NOT descend into subdirectories (e.g., `docs/postmortems/trends/`). Filter to filenames matching `YYYY-MM-DD-*.md`. Report total files found.

**Minimum corpus:** 3 recurrence-eligible postmortems. If fewer than 3 qualify after Step 2, stop the entire analysis and report:

```
Not enough data for trend analysis.
Found N file(s) in docs/postmortems/:
  - <filename> (eligible: yes/no — reason)
Minimum required: 3 recurrence-eligible postmortems.
```

No partial metrics are reported below this threshold.

## Step 2: Parse and Classify Eligibility

For each file matching `YYYY-MM-DD-*.md`, extract the date from the filename and extract raw section text by heading boundaries. Match sections by **heading text**, not ordinal position — e.g., any `## N. Summary` or `## Summary` heading matches "Summary" regardless of its number.

This supports both the canonical 8-section schema (Summary, Impact, Action Items, Root Cause & Trigger, Timeline, Contributing Factors, Lessons Learned, Investigation Notes) and legacy 7-section postmortems (where Timeline was section 3 and Action Items was section 7).

Classify into eligibility tiers:

| Tier | Required | Enables |
|------|----------|---------|
| **Recurrence-eligible** | Valid filename + a Summary heading + a Root Cause heading (matches "Root Cause & Trigger" or "Root Cause") | Recurrence grouping, trigger categorization |
| **Timeline-eligible** | Recurrence-eligible + a Timeline heading with parseable timestamps (at any position) | Timing metric candidates |
| **MTTR-eligible** | Timeline-eligible + identifiable detection and recovery events | MTTR computation |
| **MTTD-eligible** | Timeline-eligible + identifiable trigger and detection events | MTTD computation |

**Parseable timestamps:** Absolute only. Accepted formats:
- ISO 8601: `2026-03-15T10:32:00Z`
- `HH:MM` or `HH:MM:SS` with date inferred from the filename
- `YYYY-MM-DD HH:MM`

Relative timestamps ("5 minutes later", "+10m") are NOT parseable. They produce `low` timing confidence and are excluded from MTTR/MTTD computation.

**Unparseable files:** Listed in coverage report, excluded from analysis. No fuzzy parsing.

## Step 3: Build Normalized Incident Records

For each recurrence-eligible postmortem, build one normalized record with these fields. Failure mode and trigger category are extracted independently from the same section text. They answer different questions: failure mode = "what broke" (the symptom), trigger category = "what caused it" (the change type). The same signal words may match in both vocabularies; this is expected and correct. Signal pattern matching is case-insensitive.

### Service Extraction (from Summary)

| Confidence | Rule |
|------------|------|
| **high** | Explicit service name in summary text (e.g., "auth-service experienced...", "checkout-service returned 500s") |
| **medium** | Filename slug — first segment of the kebab-case portion before a failure-mode word (e.g., `2026-01-12-auth-timeout.md` → `auth`) |
| **low** | No identifiable service → `unknown-service` |

### Failure Mode (from Root Cause & Trigger)

Match signal patterns in the Root Cause & Trigger section text against this vocabulary:

| Key | Signal patterns |
|-----|----------------|
| `timeout` | timeout, deadline exceeded, context cancelled |
| `oom` | OOM, out of memory, memory limit, killed |
| `config-change` | config, misconfiguration, feature flag, env var |
| `dependency-failure` | upstream, downstream, third-party, provider outage |
| `deploy-regression` | deploy, release, regression, rollback, bad merge |
| `traffic-overload` | spike, load, burst, capacity, scaling, rate limit |
| `infra-failure` | node, disk, network, DNS, certificate, zone |
| `unknown` | No confident match (0 signals or tie between keys) |

**Confidence:** high (2+ signal words match one key), medium (1 signal word), low → `unknown`.

Group on vocabulary key only. Show raw Root Cause text as evidence, never as grouping key. Wording differences must not fragment groups.

### Trigger Category (from Root Cause & Trigger)

Match signal patterns in the Root Cause & Trigger section text against this vocabulary:

| Category | Signal patterns |
|----------|----------------|
| `deployment` | deploy, release, rollout, version, merge |
| `config-change` | config, feature flag, env var, parameter |
| `dependency` | upstream, downstream, third-party, provider, API |
| `traffic` | spike, load, burst, capacity, scaling |
| `infrastructure` | node, disk, network, DNS, certificate |
| `unknown` | No clear match, or tie between categories |

Pick the category with the most signal words. If tied, use `unknown`.

### Timing Extraction (from Timeline)

For timeline-eligible postmortems only. Extract these timestamps from the Timeline section rows (matched by heading text, not position):

| Field | Signal patterns in timeline row |
|-------|---------------------------------|
| `incident_start` | "deployed", "pushed", "config changed", "traffic spike", or first row if it describes a causal event |
| `detected_at` | "alert", "page", "noticed", "reported", "detected" |
| `recovered_at` | "resolved", "recovered", "mitigated", "restored" |

**timing_confidence:** high (3/3 timestamps found), medium (2/3), low (0–1). If a timestamp cannot be identified deterministically, the incident is excluded from the relevant metric and noted in coverage.

### Full Record Schema

| Field | Source | Confidence levels |
|-------|--------|-------------------|
| `date` | Filename `YYYY-MM-DD` | Always high |
| `service` | Summary section | high / medium / low → `unknown-service` |
| `failure_mode` | Root Cause & Trigger, vocabulary match | high / medium / low → `unknown` |
| `trigger_category` | Root Cause & Trigger, category match | Same rules as failure_mode |
| `incident_start` | Timeline: first causal event | Per timing_confidence |
| `detected_at` | Timeline: alert/page/noticed row | Per timing_confidence |
| `recovered_at` | Timeline: resolved/mitigated row | Per timing_confidence |
| `timing_confidence` | Count of parsed timestamps | high (3/3) / medium (2/3) / low (0–1) |
| `eligible_for` | Derived from above | `[recurrence, mttr, mttd]` flags |
| `raw_evidence` | Original section text | For audit trail |

## Step 4: Compute Metrics

### Recurrence Grouping

- Group by `(service, failure_mode)` — both from vocabulary keys, not free text
- Minimum group size for recurrence: 2
- Per cluster, show dominant `trigger_category` as annotation (NOT part of grouping key)
- Sort by count descending
- **`unknown-service` / `unknown` failure_mode clusters are excluded from headline recurrence output.** They appear in a separate Uncategorized section to avoid surfacing false patterns.

### Trigger Distribution

- Count each `trigger_category` across all recurrence-eligible incidents
- Show count and percentage
- Sort descending by count

### MTTR (Mean Time to Recovery)

- Formula: `recovered_at - detected_at`
- Both timestamps require `timing_confidence >= medium`
- Report: **median** (headline), mean, range
- Show eligible count vs total recurrence-eligible

### MTTD (Mean Time to Detection)

- Formula: `detected_at - incident_start`
- Both timestamps require `timing_confidence >= medium`
- Report: **median** (headline), mean, range
- Show eligible count vs total recurrence-eligible

## Step 5: Generate Output

### Terminal Summary (default)

Print this exact structure:

```
## Incident Trend Analysis

Corpus: N files scanned, X recurrence-eligible, Y MTTR-eligible, Z MTTD-eligible
Period: YYYY-MM-DD to YYYY-MM-DD (N days)

### Recurrence Patterns
  service / failure_mode  — N incidents (dates) | trigger: category
  ...
  N incidents showed no recurrence

### Trigger Distribution
  category  — N (PP%)
  ...

### MTTR (Y of X eligible)
  Median: Xm | Mean: Xm | Range: Xm – Xm

### MTTD (Z of X eligible)
  Median: Xm | Mean: Xm | Range: Xm – Xm

### Coverage Gaps
  (Report any metric with < 60% eligibility)

### Insights
- (2–4 cited observations)
```

### Insights Rules

Generate 2–4 insight bullets by applying these rules:

1. **Top recurrence cluster** + its dominant trigger → observation
2. **Dominant trigger category** if > 40% of incidents → systemic observation
3. **MTTD outliers** > 2x median → detection gap observation
4. **Coverage gaps** < 60% eligible for any metric → data quality observation

**Every insight bullet MUST cite the supporting count or rate** (e.g., "3x in 63 days", "4/9 incidents, 44%"). Insights are observations with citations, NOT prescriptions. The skill does NOT prescribe fixes — it surfaces patterns and lets the user decide.

## Step 6: Persist (on request only)

Persistence is triggered ONLY when the user explicitly requests it ("save this", "save report", "persist"). Do NOT auto-persist.

1. Create `docs/postmortems/trends/` if it does not exist
2. Write to `docs/postmortems/trends/YYYY-MM-DD-trend-report.md`
3. If a same-day report already exists, append `-2`, `-3`, etc. (e.g., `2026-03-21-trend-report-2.md`)
4. Content: full terminal summary + per-incident record table for auditability
5. **No auto-commit** — the user decides when to commit

Related Skills

incident-analysis

5
from damianpapadopoulos/auto-claude-skills

Use when investigating production symptoms — connection failures, pod crashes/restarts, SIGTERM/OOM errors, latency spikes, Cloud SQL/proxy issues, deployment-correlated errors, ImagePullBackOff, CreateContainerConfigError, or node NotReady events

unified-context-stack

5
from damianpapadopoulos/auto-claude-skills

Tiered context retrieval across External Truth (docs), Internal Truth (dependencies), Historical Truth (memory), and Intent Truth (feature specs) with graceful degradation based on installed tools.

supply-chain-investigation

5
from damianpapadopoulos/auto-claude-skills

Use when investigating a published supply-chain attack on a registry package (npm, Maven, PyPI, Go, Gradle) — advisory-driven org-wide audit. Triggers on attack-language ("compromised", "malicious", "hijacked", "backdoored", "typosquatted"). NOT for routine CVE scanning — that routes to security-scanner.

skill-scaffold

5
from damianpapadopoulos/auto-claude-skills

Emit repo-native seed files (SKILL.md skeleton, routing entry, test snippets) when creating new skills, commands, or plugins

security-scanner

5
from damianpapadopoulos/auto-claude-skills

Use when reviewing code changes for security issues — during REVIEW phase or on explicit security, vulnerability, SAST, or secret-scan requests — running available Semgrep/Opengrep, Trivy, and Gitleaks scanners with a self-healing fix loop

runtime-validation

5
from damianpapadopoulos/auto-claude-skills

Use when you need to prove a change actually works through its real interfaces — during REVIEW or on requests like validate the feature, does it work, run e2e, or smoke test — covering browser E2E, API smoke, CLI checks, and a11y audits with graceful tool-degradation

prototype-lab

5
from damianpapadopoulos/auto-claude-skills

Produce 3 thin comparable variants of a proposed design with a comparison artifact and mandatory Human Validation Plan

project-verification

5
from damianpapadopoulos/auto-claude-skills

Use when you need to run the repo's own declared test/lint/type gate locally and emit pass/fail evidence — during REVIEW, before requesting code review, or on a request to run the tests or verify the build — discovering the gate from CLAUDE.md, Makefile, pyproject, or .verify.yml

product-discovery

5
from damianpapadopoulos/auto-claude-skills

Use when starting a new feature or initiative and you need problem context, prior art, and acceptance criteria before design — the DISCOVER phase entry point — pulling Jira/Confluence context and synthesizing a discovery brief to validate problem framing

outcome-review

5
from damianpapadopoulos/auto-claude-skills

Use when reviewing a shipped feature's real-world outcome in the LEARN phase — checking adoption, error, or experiment metrics after release, validating ship-time hypotheses, or deciding follow-up work — querying PostHog and creating gated follow-up Jira work

openspec-ship

5
from damianpapadopoulos/auto-claude-skills

Use when shipping a completed feature and generating as-built OpenSpec docs before branch finalization

implementation-drift-check

5
from damianpapadopoulos/auto-claude-skills

Use when verifying an implementation still matches its spec or plan — during REVIEW or SHIP, or on demand to check drift, confirm you are still on plan, or run a spec check — surfacing spec deviations, unvalidated assumptions, and untested code paths against Intent Truth