Skip to content

phlx0/postmortem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ” postmortem

When production breaks, stop guessing. Start knowing.

CI Python 3.11+ License: MIT

Stitches together git history, file hotspots, and Sentry errors
into a shareable incident report β€” in seconds.

postmortem --since 2h --output markdown --out-file incident.md

Why postmortem?

Production is down. You need to know what changed and when β€” fast.

That means opening GitHub, scanning commits, cross-referencing deploy times, and asking teammates "did anyone push anything?" β€” all while the clock is ticking.

postmortem does it in one command.

────────────────────────────────────────────────────────────────────────
  πŸ”  postmortem  Β·  my-api
  Since 2h  Β·  19:58 UTC
────────────────────────────────────────────────────────────────────────

  πŸ”₯  File Hotspots

  β– β– β–   payments.py     changed 4x  risk 94%
       coupled: db.py  utils.py
  β– β–   db.py            changed 3x  risk 71%

  ── Sat 07 Mar 2026 ──

  17:58  ⚠  [ERROR] NullPointerException in PaymentService.charge()  ← Sentry
             payments-api  Β·  142 occurrences

  18:21  ●  fix: patch null pointer in payment handler  [3a7f2b1]  ← alice
             ↳ src/payments/handler.py
             ↳ tests/test_payments.py

  19:08  ⇄  Merge branch 'feature/stripe-v3' into main  [9c1e4fd]  ← bob
             ↳ src/stripe/client.py  ↳ src/stripe/webhooks.py  ↳ … +4

────────────────────────────────────────────────────────────────────────
  6 events  Β·  2 authors  Β·  1 Sentry error  Β·  top hotspot: payments.py

Installation

postmortem installs into an isolated virtualenv at ~/.postmortem and adds itself to your $PATH automatically. Open a new terminal and you're ready.

Linux / macOS

curl -sSL https://raw.githubusercontent.com/phlx0/postmortem/main/install.sh | bash

Windows (PowerShell)

irm https://raw.githubusercontent.com/phlx0/postmortem/main/install.ps1 | iex

From source (edits apply instantly β€” no reinstall needed)

git clone https://github.com/phlx0/postmortem
cd postmortem
bash install.sh       # or: .\install.ps1 on Windows

Requires: Python 3.11+, git

postmortem --version   # verify install
bash install.sh --uninstall   # remove cleanly

Commands

Basic usage

postmortem                                    # last 2 hours, current repo
postmortem --since 30m                        # last 30 minutes
postmortem --since 1d                         # last day
postmortem --since 4h --repo /path/to/repo    # different repo

Generate a shareable report

postmortem --since 2h --output markdown --out-file incident.md

Paste directly into a GitHub issue or Slack. The report includes a TL;DR table, file hotspot rankings, Sentry errors, and the full commit timeline with collapsible file diffs.

Sentry integration

export SENTRY_TOKEN=sntrys_...
export SENTRY_ORG=my-org
export SENTRY_PROJECT=api         # optional β€” searches all projects if omitted

postmortem --since 2h

Or pass inline:

postmortem --since 2h --sentry-org my-org --sentry-token sntrys_...

All flags

Flag Default Description
--since, -s 2h How far back to look: 30m, 2h, 1d, 1w
--repo, -r . Path to a git repository
--output, -o terminal Output format: terminal or markdown
--out-file, -f stdout Write output to a file
--no-color false Disable ANSI colours
--sentry-token $SENTRY_TOKEN Sentry auth token
--sentry-org $SENTRY_ORG Sentry organisation slug
--sentry-project $SENTRY_PROJECT Sentry project slug
--version, -v Show version and exit

What's in the report

πŸ”₯ File hotspots

Pure git analysis β€” no config needed. Ranks every file touched during the window by:

  • Change frequency β€” how many times it was modified
  • Recency β€” changes in the last 25% of the window score higher
  • Coupling β€” files that always change together are a hidden coordination risk

The coupling column is often the most useful: if payments.py and db.py consistently appear in the same commits but aren't directly imported by each other, that's a hidden dependency worth knowing about.

πŸ”΄ Sentry errors

Surfaces issues whose last seen time falls inside the incident window. Requires a read-scope auth token β€” see Sentry setup above.

πŸ“‹ Git timeline

Commits, merges, and tags in chronological order, each with author, SHA, and the list of files changed. Merges are labelled separately so you can spot integration points at a glance.


Project structure

postmortem/
β”œβ”€β”€ cli.py              Click entry point β€” stays thin
β”œβ”€β”€ pipeline.py         Wires collectors β†’ Timeline
β”œβ”€β”€ models.py           Event, Timeline, HotspotFile β€” pure data
β”œβ”€β”€ collectors/
β”‚   β”œβ”€β”€ __init__.py     BaseCollector ABC
β”‚   β”œβ”€β”€ git.py          Commits, merges, tags
β”‚   β”œβ”€β”€ hotspot.py      File frequency + coupling analysis
β”‚   └── sentry.py       Sentry Issues API
β”œβ”€β”€ renderers/
β”‚   β”œβ”€β”€ __init__.py     BaseRenderer ABC
β”‚   β”œβ”€β”€ terminal.py     ANSI terminal output
β”‚   └── markdown.py     GitHub-flavoured incident report
└── utils/
    └── time.py         "2h" β†’ datetime

Adding a collector

# postmortem/collectors/datadog.py
from postmortem.collectors import BaseCollector
from postmortem.models import Event, EventKind

class DatadogCollector(BaseCollector):
    def collect(self) -> list[Event]:
        # hit the Datadog API, return Events
        ...

Register it in pipeline.py. That's it.

Planned collectors

  • GitHub Actions β€” CI run pass/fail per commit
  • Datadog / Grafana β€” annotation and alert events
  • PagerDuty β€” on-call alerts in the window
  • Heroku / Railway β€” deploy events

PRs welcome.


Development

git clone https://github.com/phlx0/postmortem
cd postmortem
bash install.sh          # editable install β€” changes apply immediately

pytest                   # run all tests
ruff check postmortem    # lint

See CONTRIBUTING.md for the full guide.


Made with β˜• Β· MIT License