Skip to main content

Find the files in your codebase that are dying before they kill you.

Project description

██████╗ ███████╗ █████╗ ████████╗██╗  ██╗██████╗ ███████╗██████╗
██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██║  ██║██╔══██╗██╔════╝██╔══██╗
██║  ██║█████╗  ███████║   ██║   ███████║██████╔╝█████╗  ██║  ██║
██║  ██║██╔══╝  ██╔══██║   ██║   ██╔══██║██╔══██╗██╔══╝  ██║  ██║
██████╔╝███████╗██║  ██║   ██║   ██║  ██║██████╔╝███████╗██████╔╝
╚═════╝ ╚══════╝╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚═════╝ ╚══════╝╚═════╝

every codebase has files that are dying. find them.

Python 3.9+ License MIT Rich PyPI


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:

  1. A crimson ASCII art header — centered, gradient-coloured
  2. A live progress bar — showing which file is being scanned
  3. A summary panel — total files, critical / warning / fair / healthy counts, duration
  4. The main table — every file sorted worst-first, with all metrics colour-coded
  5. Most Wanted panel — full score-bar breakdown of the single worst file
  6. Quick Wins panel — files almost healthy that just need one small fix
  7. 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

  1. Fork the repo
  2. Create a branch: git checkout -b feat/my-idea
  3. Make your changes (run deathbed against itself to test!)
  4. 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

deathbed-1.0.0.tar.gz (15.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deathbed-1.0.0-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

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

Hashes for deathbed-1.0.0.tar.gz
Algorithm Hash digest
SHA256 f9cafc2eb9c8609fffba785c40f0b89dcc5ac180ab14469f97e937d4732bada0
MD5 493479c86ba5ed37763efbbb3c5062f9
BLAKE2b-256 91d02957699f823aab03e5a6ed9f7580937abdecc3bf2101abfb98c8ccecf023

See more details on using hashes here.

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

Hashes for deathbed-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0ddc7d99df16f7c0027542fad00bd18226e313dc8be5abe93de512070def2642
MD5 099094e3cd987fb82c2cdba6fbaed4a3
BLAKE2b-256 496a277a0d9473ef06adfd4c46da8d3e4146b165dbc3e79321717160657d82d4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page