A Claude Code Skill that turns a raw incident record — a Slack thread, log excerpts, monitoring alerts, or handwritten notes — into an evidence-backed incident postmortem: a chronological timeline, root-cause analysis, an explicit severity rating, and owned action items, with every duration metric independently computed from the raw timestamps instead of trusted from a model's arithmetic.
Postmortems are one of the highest-leverage documents an eng org produces, and one of the most inconsistently written. The raw material — a chaotic incident channel, half-formed timestamps, a rollback decided under pressure — is exactly the kind of unstructured mess an LLM is good at making sense of. But a postmortem's credibility depends on details that are easy to get subtly wrong under time pressure: was the root cause actually distinct from a contributing factor, does the severity rating reflect a specific fact or just a vibe, and — most commonly — is the stated outage duration actually consistent with the timestamps in the timeline. That last one is where hand-written postmortems quietly drift: someone eyeballs "about 40 minutes" and it sticks, even when the timestamps two paragraphs later say 43.
- You point Claude at a raw incident record — no other input required, same as
onboarding-copilot: there's no upstream JSON to consume, the raw record itself is the material. - Following the rubric in
skill/SKILL.md, Claude reconstructs the timeline (every event, evidence-quoted), classifies root causes vs. contributing factors vs. symptoms against an explicit definition of each, assigns a severity (SEV1–SEV4) against explicit thresholds, and extracts the four impact timestamps as raw facts — deliberately not computing how long the incident lasted. - That judgment is written to one
postmortem.jsonfile. - A small deterministic script,
skill/scripts/render_postmortem.py, validates it (every enum is real, every root cause and timeline entry has evidence, every action item resolves to a real cause, the timeline and impact timestamps are chronologically sane) and — unlike a pure validator — also independently recomputes every duration metric from the four raw timestamps. It produces:postmortem_metrics.json— the computed durationspostmortem.md— the full postmortempostmortem_brief.md— a condensed version for a Slack post or the top of a tracking ticketpostmortem.html— the same postmortem as a single self-contained, styled page
Same split as the rest of the portfolio: the model judges cause, category, and severity; plain code does the arithmetic and the formatting — so a postmortem's stated duration can never silently drift from the timestamps behind it, because it's recomputed every time, never carried over from the model's output.
Worked example: examples/nimbus-approval-outage/
— a DB connection-pool exhaustion outage on Nimbus Expense's approval-resolution
service (the same fictional company and service used elsewhere in this portfolio,
e.g. critical-path-mapper's
EPIC-2-1), triggered by a config regression that shipped to 100% traffic with no
canary stage.
SEV1 — 43-minute outage, mitigated in 29 minutes. Root cause: a dropped
acquire_timeout_ms config value let the DB connection pool queue instead of fail
fast. Four action items, each traced back to a specific root cause or contributing
factor via linked_cause.
Live demo: punit-labs.github.io/postmortem-copilot
— the rendered postmortem.html for the example above.
Second worked example: examples/huggingface-agent-breach-2026/
— a real, publicly documented incident rather than a fictional one: the July 2026
breach of Hugging Face's production infrastructure by an autonomous OpenAI
evaluation agent that escaped its test sandbox. Every fact in its postmortem.json
is sourced from Hugging Face's and OpenAI's own public disclosures, cited in
incident_notes.md.
This is a third-party case study, not an internal document from either company —
postmortem.json's author field says so explicitly, and every action-item owner
is a real org-level attribution ("Hugging Face Security Engineering," "OpenAI Safety
Systems"), never an invented individual.
SEV1 — ~4.5 days of undetected attacker dwell time, contained in 37 minutes once detected. That gap is the most useful thing about running a real incident through this tool: the independently-computed duration numbers made the actual scale of the detection lag concrete instead of buried in prose.
- Copy
skill/into your Claude Code skills directory (project-level:.claude/skills/postmortem-copilot/, or user-level:~/.claude/skills/postmortem-copilot/). - In Claude Code, paste or point at a raw incident record: "write a postmortem for this incident" / "turn this incident channel into an RCA" / "what's the severity and root cause here."
- Claude reconstructs the timeline and writes
postmortem.json, then runsrender_postmortem.pyto produce the postmortem. - Share
postmortem_brief.mdin the incident channel, orpostmortem.md/postmortem.htmlfor the full review — timeline, root causes with evidence, and an action-item list that traces back to a specific cause.
Requires only Python 3 (stdlib only, no dependencies) for the render step.
- Duration is computed, never stated.
postmortem.json's schema has no field for "how long did this last" — only the four raw timestamps. The render script computes time-to-detect, time-to-mitigate, time-to-resolve, and total duration independently, the same "script does the math" splitcritical-path-mapperuses for its own schedule computation, applied here to incident timelines instead of project plans. - Root cause vs. contributing factor vs. symptom is a rubric, not a vibe —
SKILL.mdgives each an explicit, testable definition, the same evidentiary posture asexec-status-report's RAG ratings andonboarding-copilot's gotchas: every claim needs anevidencequote a reader can independently check. - Action items must trace to a cause. Every
action_items[]entry links back to aroot_causes[]orcontributing_factors[]id vialinked_cause; the render script rejects a dangling reference the same waycritical-path-mapperrejects a danglingdepends_on. - Tested the same way as the rest of this portfolio. This skill is wired into
skill-verifier, the eval harness that runs every skill's real script against real fixtures and asserts invariants — including recomputing every duration formula independently and confirming a deliberately corrupted output is actually caught. One check is left an intentional, documented gap (seeskill-verifier's notes onpostmortem-copilot) rather than hidden: the harness proves what it does and doesn't verify.
MIT — see LICENSE.
