Unearthing the code that time forgot — mine your git history for dead, deleted, and abandoned code.
Project description
⛏ DeadCode Archaeologist
Unearthing the code that time forgot.
A CLI tool that mines your git history and performs static analysis to surface dead functions, deleted code blocks, ancient TODOs, ghost imports, and other archaeological artifacts of forgotten code — ranked by how tragic their abandonment was.
Features
| Artifact | Detection Method |
|---|---|
| 🪦 Deleted code blocks | Git history — large hunks removed and never restored |
| 👻 Dead functions | AST (Python) + regex (JS/TS) — defined but never called |
| ⏳ Ancient TODOs | git blame — TODO/FIXME/HACK/BUG comments older than 180 days |
| 🌫️ Ghost imports | AST / regex — imported but never referenced |
| 💔 Reverted dreams | Git history — commits merged then immediately reverted |
| 🗿 Lone variables | AST — assigned inside a function but never read |
| 💬 Orphaned comments | AST — comments referencing names that no longer exist |
Every artifact receives a tragedy score (0–100):
| Score | Label |
|---|---|
| 80–100 | 💀 Devastating |
| 60–79 | 😢 Very Tragic |
| 40–59 | 😔 Tragic |
| 20–39 | 😐 Melancholic |
| 0–19 | 🙂 Bittersweet |
Installation
pip install deadcode-archaeologist
Or from source:
git clone https://github.com/deadcode-archaeologist/deadcode-archaeologist
cd deadcode-archaeologist
pip install -e ".[dev]"
Requirements: Python 3.9+ · click · gitpython · rich
Quick Start
# Full scan — git history + static analysis
archaeologist excavate .
# Static analysis only (no git required)
archaeologist analyze .
# Analyze a single file
archaeologist analyze src/models.py
# Git history only
archaeologist history .
Commands
excavate — full scan
archaeologist excavate [OPTIONS] [REPO_PATH]
| Option | Default | Description |
|---|---|---|
--max-commits N |
300 | Commits to scan in git history |
--top N |
20 | Show top N findings |
--min-score N |
15 | Minimum tragedy score (0–100) |
--no-git |
off | Skip git history; works on non-git directories |
--no-static |
off | Skip static analysis |
--format terminal|json |
terminal | Output format |
--output FILE |
— | Save report to file |
--no-color |
off | Disable Rich colours |
# Deeper scan with stricter filter
archaeologist excavate . --max-commits 1000 --min-score 40
# Static analysis only on a non-git directory
archaeologist excavate /path/to/code --no-git
# Save a JSON report
archaeologist excavate . --format json --output report.json
# Pipe JSON to jq
archaeologist excavate . --format json | jq '.artifacts[] | select(.tragedy_score > 60)'
analyze — static analysis only
No git repository required. Accepts a directory or a single file.
archaeologist analyze [OPTIONS] [REPO_PATH]
| Option | Default | Description |
|---|---|---|
--top N |
30 | Show top N findings |
--min-score N |
10 | Minimum tragedy score |
--format terminal|json |
terminal | Output format |
--output FILE |
— | Save report to file |
--no-color |
off | Disable Rich colours |
archaeologist analyze .
archaeologist analyze src/utils.py
archaeologist analyze . --format json --output analysis.json
history — git history only
archaeologist history [OPTIONS] [REPO_PATH]
| Option | Default | Description |
|---|---|---|
--max-commits N |
500 | Commits to scan |
--top N |
20 | Show top N findings |
--format terminal|json |
terminal | Output format |
--output FILE |
— | Save report to file |
--no-color |
off | Disable Rich colours |
archaeologist history . --max-commits 2000
archaeologist history . --format json --output history.json
JSON Output
Note:
artifactscontains the top--top Nfindings.total_artifactsreflects the full count — use--top 9999to retrieve everything.
{
"repo_name": "myapp",
"total_artifacts": 47,
"average_tragedy_score": 47.3,
"scan_duration_seconds": 3.2,
"artifacts": [
{
"type": "dead_function",
"title": "def process_legacy_data() — called by no one",
"file_path": "src/pipeline.py",
"line_number": 84,
"tragedy_score": 78,
"tragedy_label": "Very Tragic",
"code_snippet": "def process_legacy_data(records):\n ...",
"author": "alice",
"date": "2021-03-14",
"tags": ["dead-function", "python"]
}
]
}
Language Support
| Language | Dead functions | Ghost imports | Lone variables | Orphaned comments |
|---|---|---|---|---|
| Python | ✅ AST | ✅ AST | ✅ AST | ✅ AST |
| JS / TS / JSX / TSX | ✅ regex | ✅ regex | — | — |
| Go, Rust, Java, … | via git history only | — | — | — |
False-Positive Guards
Dead function detection skips functions that are:
- Referenced via
getattr(obj, "func_name")(dynamic dispatch) - Listed in
__all__(public API) - Used as a decorator (
@my_decorator) - Inside a file that uses
from module import * - Framework hooks (
setUp,save,get,post,dispatch, …) - Dunder methods (
__init__,__str__, …)
Ancient TODO detection only matches keywords (TODO, FIXME, BUG, etc.) that:
- Appear as whole words (not inside identifiers like
debuggeroruse_debug) - Are on an actual comment line starting with
#,//,/*,--, or* - Are not inside string literals, variable names, or URLs like
http://xxx.example.com
Programmatic Use
from archaeologist.analyzer import Analyzer
from archaeologist.excavator import Excavator
# Static analysis
an = Analyzer("/path/to/project")
for artifact in an.find_dead_functions():
print(f"{artifact.tragedy_score:3d} {artifact.title}")
# Git history with progress callback
ex = Excavator("/path/to/project", max_commits=500)
for artifact in ex.excavate_deleted_blocks(
progress=lambda done, total: print(f"{done}/{total}", end="\r")
):
print(artifact.title)
Development
git clone https://github.com/deadcode-archaeologist/deadcode-archaeologist
cd deadcode-archaeologist
pip install -e ".[dev]"
pytest
Linting and type checking:
ruff check archaeologist/ tests/
mypy archaeologist/ --ignore-missing-imports
Publishing a New Release
# 1. Bump version in pyproject.toml and archaeologist/__init__.py
# 2. Add entry to CHANGELOG.md
# 3. Commit, tag, push — the publish workflow fires automatically
git tag v1.0.1
git push origin v1.0.1
First-time setup: configure a PyPI Trusted Publisher for the publish.yml workflow, or add a PYPI_API_TOKEN secret to the repository.
Changelog
See CHANGELOG.md for the full history.
License
Project details
Release history Release notifications | RSS feed
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 deadcode_archaeologist-1.0.1.tar.gz.
File metadata
- Download URL: deadcode_archaeologist-1.0.1.tar.gz
- Upload date:
- Size: 39.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f86461a9a220390903dd4c51cbcf51f5e688b8ab2f996ea66025ca536d694f0b
|
|
| MD5 |
ca31e51f239324640d768c5abea6ec97
|
|
| BLAKE2b-256 |
e90791d0cb4419ea8d6752a150cefab1ce793fc91670d3de990adf078e0fd6ae
|
Provenance
The following attestation bundles were made for deadcode_archaeologist-1.0.1.tar.gz:
Publisher:
publish.yml on arjinexe/deadcode-archaeologist
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
deadcode_archaeologist-1.0.1.tar.gz -
Subject digest:
f86461a9a220390903dd4c51cbcf51f5e688b8ab2f996ea66025ca536d694f0b - Sigstore transparency entry: 1033801329
- Sigstore integration time:
-
Permalink:
arjinexe/deadcode-archaeologist@78de5b78dcb4848fac6cc75896a77e15b917e9a8 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/arjinexe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@78de5b78dcb4848fac6cc75896a77e15b917e9a8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file deadcode_archaeologist-1.0.1-py3-none-any.whl.
File metadata
- Download URL: deadcode_archaeologist-1.0.1-py3-none-any.whl
- Upload date:
- Size: 29.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0422b198381cc9064c34db99d02c0cecd0c716aeefb33b605939acca46be7b89
|
|
| MD5 |
0c0fa999d1127754cabc55e76ba69ad7
|
|
| BLAKE2b-256 |
92e7d51ae5c93727c13d307e7709e4b3381fd9fdff44285a8568920eaa2df2e2
|
Provenance
The following attestation bundles were made for deadcode_archaeologist-1.0.1-py3-none-any.whl:
Publisher:
publish.yml on arjinexe/deadcode-archaeologist
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
deadcode_archaeologist-1.0.1-py3-none-any.whl -
Subject digest:
0422b198381cc9064c34db99d02c0cecd0c716aeefb33b605939acca46be7b89 - Sigstore transparency entry: 1033801491
- Sigstore integration time:
-
Permalink:
arjinexe/deadcode-archaeologist@78de5b78dcb4848fac6cc75896a77e15b917e9a8 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/arjinexe
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@78de5b78dcb4848fac6cc75896a77e15b917e9a8 -
Trigger Event:
push
-
Statement type: