Skip to main content

graveyard

CI GitHub stars crates.io PyPI npm License

graveyard finds dead code across Python, JavaScript, TypeScript, Go, and Rust in a single pass, then ranks every finding with git-aware confidence scoring. It exists because AI coding agents make cross-language dead code cheaper to create than to notice, and the existing toolchain still forces teams to stitch together language-specific scanners with no shared scoring model.

What is graveyard?

graveyard is a compiled Rust CLI that walks a repository once, extracts symbols with tree-sitter, builds a unified reference graph, folds in git age and churn, then emits a ranked report in table, JSON, CSV, or SARIF form. The front-door workflow is intentionally simple: use --min-age when you want "show me code that has been dead for a while" and use --min-confidence when you want CI-grade filtering across exported APIs, dead cycles, and fresh code that might still be in flight.

The repository scanner is manifest-aware, so pyproject.toml, package.json, go.mod, and Cargo.toml shape language detection automatically. .gitignore handling comes from the ignore crate, git history comes from git2, and the baseline commands let teams ratchet new dead code without having to clean an existing backlog in one change.

Installation

pip / pipx

pip install graveyard
pipx install graveyard
uvx graveyard --version

npm

npm install -g graveyard-cli
npx graveyard --version

cargo

cargo install graveyard
graveyard --version

Homebrew

brew install graveyard
graveyard --version

Quick Start

Run a scan in the current repository:

graveyard scan

Filter for code that has been dead for at least a month:

graveyard scan --min-age 30d

Use CI gating with a stricter score threshold:

graveyard scan --ci --min-confidence 0.8

Sample terminal output:

CONFIDENCE  TAG               AGE         LOCATION                  FQN
0.94        ExportedUnused    1.1 years   src/lib.rs:42             src/lib.rs::legacy::old_api
0.88        Dead              8 months    services/api/foo.py:17    services/api/foo.py::cleanup_task
Found 2 dead symbol(s) — min-confidence 0.8, min-age 30 days

Usage

The default scan targets the current directory and prints a ranked table:

graveyard scan
graveyard scan ./services/api
graveyard scan --top 25
graveyard scan --format json
graveyard scan --format sarif --output graveyard.sarif
graveyard scan --format csv --output graveyard.csv

Time-based filtering is the fastest way to adopt the tool in an existing repository:

graveyard scan --min-age 7d
graveyard scan --min-age 30d --min-confidence 0.7
graveyard scan --min-age 1y --ignore-exports

Repository-specific controls map directly to the implemented flags:

graveyard scan --exclude "vendor/**" --exclude "generated/**"
graveyard scan --baseline .graveyard-baseline.json
graveyard scan --no-git
graveyard scan --no-cache
graveyard scan --cache-dir ~/.cache/graveyard
graveyard scan --config .graveyard.toml
graveyard scan -v
graveyard scan -vv

Baseline management and language detection are first-class commands:

graveyard baseline save --output .graveyard-baseline.json
graveyard baseline diff --baseline .graveyard-baseline.json
graveyard baseline diff --baseline .graveyard-baseline.json --ci
graveyard languages
graveyard completions bash > ~/.local/share/bash-completion/completions/graveyard
graveyard completions zsh > ~/.zfunc/_graveyard
graveyard completions fish > ~/.config/fish/completions/graveyard.fish
graveyard completions powershell > graveyard.ps1

CI Integration

The ratchet workflow is the cleanest way to add graveyard to an existing codebase because it only fails the build when a pull request introduces new dead code relative to a stored baseline.

name: Dead Code

on:
  pull_request:
  push:
    branches:
      - main

jobs:
  graveyard:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install graveyard
        run: pip install graveyard
      - name: Enforce new dead code only
        run: graveyard baseline diff --baseline .graveyard-baseline.json --ci

If you do not need a ratchet, replace the final command with graveyard scan --ci --min-confidence 0.8. SARIF output is available through graveyard scan --format sarif --output graveyard.sarif when you want to upload findings into GitHub code scanning.

Configuration

graveyard resolves settings in this order: CLI flags, .graveyard.toml, environment variables, then built-in defaults. The configuration file lives at .graveyard.toml by default and supports the full v1 surface.

[graveyard]
min_confidence = 0.6
min_age = "30d"
fail_on_findings = false
top = 0
format = "table"
output = "graveyard-report.json"
exclude = ["migrations/**", "**/generated/**"]
ignore_exports = false
baseline = ".graveyard-baseline.json"
no_git = false
no_cache = false

[scoring]
age_weight = 0.35
ref_weight = 0.30
scope_weight = 0.20
churn_weight = 0.15
age_max_days = 730
age_min_days = 7

[ignore]
names = ["legacy_*", "TODO_*", "test_*"]
files = ["migrations/**", "**/generated/**", "**/vendor/**"]
decorators = ["@pytest.fixture", "@app.route"]

[languages]
enabled = ["python", "javascript", "typescript", "go", "rust"]

[entry_points]
names = ["main", "__main__", "app", "handler", "create_app"]

[cache]
enabled = true
dir = "~/.cache/graveyard"

The GRAVEYARD_MIN_CONFIDENCE environment variable can override the default confidence threshold when the config file leaves it unset. NO_COLOR and GRAVEYARD_NO_COLOR both disable ANSI color output.

Understanding Scores

--min-age is the intended on-ramp because it maps directly to how engineers reason about stale code. If a symbol has had no meaningful touch for thirty days and still has zero reachable callers, it belongs high in the queue even before anyone thinks about the full formula.

--min-confidence exposes the full score for CI and team policy work. The score is a weighted sum of four factors: age of deadness, reference count, symbol scope, and recent churn. Local private functions with no callers and no recent history score higher than public APIs or code that changed this week.

confidence =
  0.35 * age_factor(deadness_age_days)
  0.30 * ref_factor(in_degree)
  0.20 * scope_factor(symbol)
  0.15 * churn_factor(commits_90d)

Those weights are configurable in [scoring], but they must still sum to 1.0. Use --ignore-exports when a repository has many intentionally public APIs and you only want truly unreachable internals.

Language Support

Language Status Notes
Python Yes Functions, classes, __all__, decorator-aware extraction
JavaScript Yes Functions, arrow functions, exports, export * from
TypeScript Yes JS support plus interfaces, type aliases, TSX parsing
Go Yes Functions, methods, exported identifier detection
Rust Yes Functions, methods, structs, enums, pub visibility, test attributes

vs. Other Tools

Tool Language Scope Git History Scoring Baseline Ratchet Install Surface
graveyard Python, JS, TS, Go, Rust Yes Yes pip, npm, cargo, brew
vulture Python only No No Python
knip JS/TS only No No npm
deadcode Go only No No Go toolchain
cargo-machete Rust dependency analysis No No cargo

graveyard is not trying to replace dependency-pruning tools such as cargo-machete. It sits at the source-code layer, where teams need one ranked list across a polyglot repository instead of separate outputs from five ecosystems.

Metadata

Release files for graveyard 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for graveyard 0.1.2
File
graveyard-0.1.2-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
graveyard-0.1.2-py3-none-manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64 Details
graveyard-0.1.2-py3-none-manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64 Details
graveyard-0.1.2-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
graveyard-0.1.2-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 15.2 MB

Release files / graveyard-0.1.2-py3-none-win_amd64.whl

Download URL graveyard-0.1.2-py3-none-win_amd64.whl
Size 3.3 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
be653c89b17472c20e9748de510b920a23ace3367dbadd49cc976d9f4843ebc8
BLAKE2b-256 checksum
How to use checksums
1dc175f4aa8f58a84b50d1bbbd74840ad9b53795d51da18fb55a635b6aa43cb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / graveyard-0.1.2-py3-none-manylinux_2_28_x86_64.whl

Download URL graveyard-0.1.2-py3-none-manylinux_2_28_x86_64.whl
Size 3.1 MB
Tags Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
1082a412cb4deeaafda023cb6b7590f84a233d9b1c12a120544f9c205a529a1a
BLAKE2b-256 checksum
How to use checksums
f150fa9ff4e65f2172e305780044d7fbe97c7841450ade936c41ee53eb27f682
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / graveyard-0.1.2-py3-none-manylinux_2_28_aarch64.whl

Download URL graveyard-0.1.2-py3-none-manylinux_2_28_aarch64.whl
Size 3.0 MB
Tags Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
e32008e9cfdee0881f54f727697a424f8a0225e49e44ae4e7048926ce96c726b
BLAKE2b-256 checksum
How to use checksums
375cecd897e0421bb8edfdec83bc00960a283a9ab0e6233dad8809ee04bf62a2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / graveyard-0.1.2-py3-none-macosx_11_0_arm64.whl

Download URL graveyard-0.1.2-py3-none-macosx_11_0_arm64.whl
Size 2.8 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e77a5aa6d7d69da0a8116e3ab36edf560e4056a399fa2e0d2c1cf2c5adede7d1
BLAKE2b-256 checksum
How to use checksums
b94ae7ac5beb143c8b483c4758403d8846f09af9e44be656ab3b00ad8f392123
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release files / graveyard-0.1.2-py3-none-macosx_10_12_x86_64.whl

Download URL graveyard-0.1.2-py3-none-macosx_10_12_x86_64.whl
Size 3.0 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
cd5d4fd6415ac605d7e9e06612949f3169e4bbd273bb6b1ce12bffa5c8836bea
BLAKE2b-256 checksum
How to use checksums
54d8091d9a6f7b653767141f7095e6ea5b8ad35120f6f3415b4791d81418af0c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.7

Release history Release notifications | RSS feed

This release

0.1.2 This release

5 release files

0.1.1

5 release files

0.1.0

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page