Skip to main content

Find the files whose knowledge sits with a single person — the bus factor, made concrete.

Project description

orphan

The bus factor, made concrete.

Not an abstract score — the named list of files whose knowledge sits with a single person, sorted by how much is actually at risk.

PyPI version Python versions License: MIT No dependencies

orphan in action


What it does

Every mature codebase has files only one person has ever really touched. Some are harmless. Some are a terraform module or an nginx.conf holding up production, understood by exactly one engineer — who may have left months ago.

orphan reads your git history and surfaces those files by name, with the owner, the age of the last commit, and a risk category. It reads history only, never file contents, so it works on any repository regardless of language — application code and infrastructure alike.

The three categories

Age alone is misleading: a LICENSE written once and never touched looks exactly like a dangerous orphan, but it's the healthiest file in the repo. orphan separates stable from risky using two axes — how much a file has evolved (commit count, a proxy for accumulated knowledge) and whether its sole owner is still active.

Category Meaning Signal
silo Many commits, one owner, still active Live, concentrated knowledge. One brain holds a growing area.
orphan Many commits, one owner, now inactive The knowledge has likely already walked out the door.
· stable Few commits (a base or config file) Low risk. Shown for completeness, not as an alarm.

The stable bucket exists on purpose: it's where the classic false positives land (base files an author wrote once before moving on), so they stop drowning out the real risks.

Why you'll like it

  • Zero dependencies. Pure Python standard library, 3.8+.
  • Portable. A single script; drop orphan.py anywhere and run it.
  • Language-agnostic. Works on Terraform, Ansible, shell, YAML — anything git tracks, not just source code.
  • Localized output. English, French, German, Spanish, Italian (see Languages).
  • Scriptable. --json for pipelines and dashboards.

Installation

From PyPI

pip install orphan

Then, in any repository:

orphan

From source (no install)

The tool is a single file. Grab orphan.py (and locales.json if you want non-English output), then:

python3 orphan.py

That's it — nothing to build, nothing to install. orphan.py alone runs in English; add locales.json beside it to unlock the other languages.

Usage

orphan                     # analyze the current repository
orphan --lang fr           # localized output (en, fr, de, es, it)
orphan --dense-commits 8   # raise the silo/orphan vs stable threshold
orphan --active-months 6   # "inactive owner" cutoff (default: 12 months)
orphan --threshold 2       # also consider files with up to 2 authors
orphan --top 40            # cap the displayed rows (0 = all)
orphan --path infra/       # restrict to a subdirectory
orphan --json              # machine-readable output (never localized)

Options

Option Default Description
--lang en Output language: en, fr, de, es, it.
--path (repo root) Restrict analysis to a subdirectory.
--threshold 1 Max distinct authors for a file to be considered single-owned.
--dense-commits 5 Commits from which a file counts as knowledge-dense (silo/orphan vs stable).
--active-months 12 An author with no commit for N months counts as inactive.
--top 25 Show only the N riskiest files (0 for all).
--json (off) Emit raw JSON instead of the terminal report.
--no-color (off) Disable ANSI colors.

JSON output

--json emits stable, language-neutral data — ideal for CI gates or a dashboard:

{
  "summary": { "total": 12, "silo": 3, "orphan": 4, "stable": 5, "tracked_files": 210, "dense_commits": 5 },
  "files": [
    {
      "path": "infra/pipeline.tf",
      "kind": "infra",
      "category": "orphan",
      "owners": ["Bob"],
      "owner_count": 1,
      "commits": 8,
      "last_commit": "2024-05-01T10:00:00+00:00",
      "age_days": 800,
      "departed": true
    }
  ]
}

Languages

Switch the display language with --lang. English is built into the script; the other languages live in locales.json next to it. If that file is missing or a string is absent, the output falls back to English.

Adding a language (no code required)

Translations are pure data. To add, say, Portuguese:

  1. Open locales.json.
  2. Copy the "en" block — it's the reference and lists every key.
  3. Rename it "pt" and translate the values. Keep the {placeholders} intact.
  4. For the age units, note the _one / _other pairs — they exist so plurals read correctly (e.g. 1 mês vs 6 meses).
  5. Add "pt" to the --lang choices in orphan.py (the LANGUAGES tuple).
  6. Open a pull request. 🎉

How it works

A single git log pass over the whole repository collects, per file, the set of authors and the date of the last commit, plus each author's most recent activity anywhere in the repo. %aN applies your .mailmap, so one person committing under several emails counts once. Files are then bucketed into the three categories and sorted so the densest live silos rise to the top.

One git invocation for the whole repo — fast even on large histories.

Limitations

Honest by design:

  • Commit count is a proxy for knowledge, not size. A large file written in a single commit reads as stable even if it holds a lot.
  • Renames aren't followed in a repo-wide log, so a freshly renamed file may look single-owner even if it had history under its old name.
  • Ownership is per commit, not per line. "Who has ever touched this file" is the right orphan signal and far faster than running git blame per file.
  • "Inactive" is inferred from git activity, not HR data. Someone working on another repo for a year will read as inactive. Tune --active-months to your team's rhythm.

Contributing

Issues and pull requests welcome — a new translation, a smarter category heuristic, an extra infra file type. Adding a language needs no Python (see above).

License

MIT — do what you like, no warranty.

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

orphan-0.2.0.tar.gz (15.3 kB view details)

Uploaded Source

Built Distribution

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

orphan-0.2.0-py3-none-any.whl (14.0 kB view details)

Uploaded Python 3

File details

Details for the file orphan-0.2.0.tar.gz.

File metadata

  • Download URL: orphan-0.2.0.tar.gz
  • Upload date:
  • Size: 15.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for orphan-0.2.0.tar.gz
Algorithm Hash digest
SHA256 0ffba7fb82f95b3b7c21e02e3330f445914f963399638c62ffed7d9520cad2b1
MD5 dbd2ff2253b27fc6124c61ab4fb1b9e3
BLAKE2b-256 ae3c98717216ec5e545babe71725ef909af94d5e05cc22ac0ebce6c88e460bd3

See more details on using hashes here.

File details

Details for the file orphan-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: orphan-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for orphan-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f5c37d70a663d72de720260526702107f7c225b88f92a96f516c31b9cf3daef0
MD5 e4a93db8392bd7280dd99ecd6daaf6c3
BLAKE2b-256 d1f3a7ec4e7deb274d2807e1f6cc37f2d747fa7eb78df140dbbdd82520f520ca

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