When production breaks, stop guessing. Start knowing.
Stitches together git history, file hotspots, and Sentry errors
into a shareable incident report β in seconds.
postmortem --since 2h --output markdown --out-file incident.mdProduction 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
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 | bashWindows (PowerShell)
irm https://raw.githubusercontent.com/phlx0/postmortem/main/install.ps1 | iexFrom source (edits apply instantly β no reinstall needed)
git clone https://github.com/phlx0/postmortem
cd postmortem
bash install.sh # or: .\install.ps1 on WindowsRequires: Python 3.11+, git
postmortem --version # verify install
bash install.sh --uninstall # remove cleanlypostmortem # last 2 hours, current repo
postmortem --since 30m # last 30 minutes
postmortem --since 1d # last day
postmortem --since 4h --repo /path/to/repo # different repopostmortem --since 2h --output markdown --out-file incident.mdPaste 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.
export SENTRY_TOKEN=sntrys_...
export SENTRY_ORG=my-org
export SENTRY_PROJECT=api # optional β searches all projects if omitted
postmortem --since 2hOr pass inline:
postmortem --since 2h --sentry-org my-org --sentry-token sntrys_...| 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 |
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.
Surfaces issues whose last seen time falls inside the incident window. Requires a read-scope auth token β see Sentry setup above.
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.
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
# 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.
- 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.
git clone https://github.com/phlx0/postmortem
cd postmortem
bash install.sh # editable install β changes apply immediately
pytest # run all tests
ruff check postmortem # lintSee CONTRIBUTING.md for the full guide.
Made with β Β· MIT License