Find the files in your codebase that are dying before they kill you.
Project description
██████╗ ███████╗ █████╗ ████████╗██╗ ██╗██████╗ ███████╗██████╗
██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗
██║ ██║█████╗ ███████║ ██║ ███████║██████╔╝█████╗ ██║ ██║
██║ ██║██╔══╝ ██╔══██║ ██║ ██╔══██║██╔══██╗██╔══╝ ██║ ██║
██████╔╝███████╗██║ ██║ ██║ ██║ ██║██████╔╝███████╗██████╔╝
╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝╚═════╝
every codebase has files that are dying. find them.
deathbed analyses every tracked source file in a git repository and gives it a health score based on six real, local metrics — no external API calls, no secrets needed. It then surfaces the files most likely to cause you pain, explains why they are dying, and tells you exactly what to do first.
Why?
Every codebase accumulates rot. Files that nobody owns. Files too complex to understand. Files last touched three years ago by someone who left. These files never show up in sprint planning, but they quietly cause the most bugs, the slowest onboarding, and the worst incidents.
deathbed makes the invisible visible.
Install
pip install deathbed
Or, to hack on it:
git clone https://github.com/yourusername/deathbed
cd deathbed
pip install -e .
Usage
# Analyse the current git repo
deathbed
# Analyse a different repo
deathbed --path /path/to/repo
# Show only the 20 worst files
deathbed --top 20
# Show only WARNING and CRITICAL files (score < 65)
deathbed --min-score 65
# Output JSON for CI pipelines / scripting
deathbed --format json
# Combine flags
deathbed --path ~/projects/myapp --top 10 --format json
Options
| Flag | Default | Description |
|---|---|---|
--path, -p |
. |
Path to the git repository |
--top, -t |
50 |
Show only the N worst files (0 = all) |
--min-score |
— | Only show files with a health score below this value |
--format, -f |
rich |
Output format: rich or json |
--version, -V |
— | Show version and exit |
What it looks like
When you run deathbed you get:
- A crimson ASCII art header — centered, gradient-coloured
- A live progress bar — showing which file is being scanned
- A summary panel — total files, critical / warning / fair / healthy counts, duration
- The main table — every file sorted worst-first, with all metrics colour-coded
- Most Wanted panel — full score-bar breakdown of the single worst file
- Quick Wins panel — files almost healthy that just need one small fix
- Pattern tip — one targeted, actionable suggestion based on the repo's dominant problem
Metrics explained
Each file receives a composite health score from 0–100 (higher is healthier), built from six weighted sub-scores:
| # | Metric | Weight | What it measures |
|---|---|---|---|
| 1 | Size | 15% | Lines of code — penalises files > 300 / 600 / 1000 lines |
| 2 | Age | 20% | Days since any commit touched this file — flags abandoned code |
| 3 | Churn | 20% | Number of commits to this file — instability signal |
| 4 | Complexity | 20% | Radon cyclomatic complexity average — Python files only; N/A otherwise |
| 5 | Authors | 15% | Unique git authors — many authors = diffused ownership |
| 6 | Test coverage | 10% | Whether a corresponding test file exists anywhere in the repo |
Health thresholds
| Score | Status | Meaning |
|---|---|---|
| 86–100 | ✅ HEALTHY | All good |
| 66–85 | 🌡 FAIR | Minor issues |
| 41–65 | ⚠️ WARNING | Needs attention soon |
| 0–40 | 💀 CRITICAL | Actively dangerous |
Diagnoses
deathbed automatically picks the most meaningful single-phrase diagnosis:
| Diagnosis | What it means |
|---|---|
complexity graveyard |
Cyclomatic complexity is extremely high |
legacy ghost |
Not touched in years — likely orphaned |
too many cooks |
Many authors, nobody owns it |
churn monster |
Modified constantly — unstable abstraction |
growing out of control |
Large and getting larger |
nobody's watching this |
Old code with no test coverage |
abandoned and complex |
Old and hard to understand |
healthy |
Nothing to worry about |
JSON output
--format json returns a machine-readable object useful for CI gates:
{
"version": "1.0.0",
"repo": "/path/to/repo",
"total": 3,
"files": [
{
"file": "src/legacy/monster.py",
"health_score": 22,
"status": "CRITICAL",
"diagnosis": "complexity graveyard",
"lines": 1284,
"days_since_commit": 847,
"commit_count": 134,
"author_count": 9,
"avg_complexity": 18.3,
"has_test_file": false,
"scores": {
"size": 0, "age": 5, "churn": 15,
"complexity": 2, "authors": 20, "test": 20
}
}
]
}
Supported file types
.py .js .ts .jsx .tsx .go .rs .rb .java .cpp .c .cs .php .swift .kt
Automatically skipped: node_modules, venv, dist, build, .git, binary files, lock files, and everything matched by .gitignore.
Contributing
- Fork the repo
- Create a branch:
git checkout -b feat/my-idea - Make your changes (run
deathbedagainst itself to test!) - Open a pull request
Bug reports and feature ideas welcome via Issues.
Made with 💀 and Rich
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file deathbed-1.0.0.tar.gz.
File metadata
- Download URL: deathbed-1.0.0.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f9cafc2eb9c8609fffba785c40f0b89dcc5ac180ab14469f97e937d4732bada0
|
|
| MD5 |
493479c86ba5ed37763efbbb3c5062f9
|
|
| BLAKE2b-256 |
91d02957699f823aab03e5a6ed9f7580937abdecc3bf2101abfb98c8ccecf023
|
File details
Details for the file deathbed-1.0.0-py3-none-any.whl.
File metadata
- Download URL: deathbed-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ddc7d99df16f7c0027542fad00bd18226e313dc8be5abe93de512070def2642
|
|
| MD5 |
099094e3cd987fb82c2cdba6fbaed4a3
|
|
| BLAKE2b-256 |
496a277a0d9473ef06adfd4c46da8d3e4146b165dbc3e79321717160657d82d4
|