CheckOwners
Keep CODEOWNERS aligned with reality.
$ checkowners --offline drift
severity: HIGH (Δmax=1.00)
CODEOWNERS Drift
┏━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Category ┃ Path ┃ Δ ┃ Reason ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ changed │ /payments/ │ 1.00 │ owners diverge on 2 of 2 covered path(s) │
│ │ │ │ (line 1) │
└──────────┴────────────┴──────┴───────────────────────────────────────────────┘
CheckOwners analyzes git and review history to infer who actually knows each part of your repository, then compares that evidence with your CODEOWNERS policy. Use it to detect stale or incorrect rules, find code with dangerously concentrated knowledge, recommend knowledgeable reviewers, and discover ownership gaps before they become operational risk.
Local-first. Git-native. No source-code upload. No LLM required. The core install is pure git. With no token, CheckOwners sends nothing anywhere. checkowners --offline opens no network connection. PyPI releases use Trusted Publishing. Sigstore signs each distribution.
This is a knowledge-risk tool, not a performance-measurement tool. Using it for individual evaluation is unsupported and harmful.
uvx checkowners drift
Install
Requires Python 3.11 through 3.14 and Git 2.23 or newer.
pip install checkowners # core CLI (pure git, zero API deps)
pip install "checkowners[graph]" # + networkx-backed graph / topology / onboard
pip install "checkowners[github]" # + GitHub API handle/team/review resolution
pip install "checkowners[all]" # everything
Run
checkowners --offline drift
Exit status is the same for every command: 0 clean, 1 internal error, 2 configuration or usage, 3 findings, 4 git or GitHub failure. checkowners --exit-zero hides findings only. See Exit codes.
CI
Least privilege (job summary only; no pull-request comment):
name: checkowners
on: [pull_request]
jobs:
drift:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: smusali/checkowners@v0
with:
config: .github/checkowners.yml
comment_on_pr: false
Same-repo comments need pull-requests: write. The comment workflow and the pre-commit hooks are in GitHub Actions and Pre-commit.
CheckOwners treats code ownership as a confidence-scored spectrum rather than a static binary declaration.
No other open-source tool combines git-history inference, per-path ownership scores with evidence quality, pattern-aware drift with severity tiers, and knowledge-risk reporting behind a single CI-native JSON contract.
See it
checkowners --offline drift on a sanitized two-person tree. The committed rule is /payments/ @platform.
The composite Action posts that finding as one comment on same-repo pull requests:
generate --force on the same tree writes examples/sample-CODEOWNERS:
# Generated by checkOwners. Do not edit manually.
/payments/ @alice @bob
How it works
analyze reads git log and git blame and caches an ownership map per repo under ~/.checkowners/.
- Noreply addresses become GitHub
@handleslocally. Other addresses use the GitHub API when a token is set. - One person with several emails counts once.
generatewrites CODEOWNERS and collapses a directory of identical owners into onedir/rule.driftmatches the committed file with GitHub's CODEOWNERS rules: directories, globs, last match wins.
Other reports use that same map. The table below lists them. In CI, the composite Action writes GITHUB_OUTPUT, a job summary, and one pull-request comment on same-repo pull requests.
Scoring commands accept --json, --as-of, and SOURCE_DATE_EPOCH. The default instant is the HEAD committer time. graph uses --export dot instead of --json.
The full pipeline is in docs/USAGE.md.
| Command | What it does |
|---|---|
checkowners analyze |
Infer ownership scores, qualified owner count, and continuity-risk warnings |
checkowners generate |
Write CODEOWNERS, ordered by ownership score; optional inline annotations |
checkowners explain-path <path> |
Show which CODEOWNERS rule owns a path, and the full match chain |
checkowners explain <path> |
Decompose inferred scores (signals, evidence, --why-not, --owner) |
checkowners owners <path> |
Minimal ranked owner list (who is an alias) |
checkowners print |
Print inferred ownership to stdout |
checkowners validate |
Validate existing CODEOWNERS syntax |
checkowners drift |
Compare inferred vs current; severity + max ownership-score delta |
checkowners baseline create |
Write an accepted-findings file so later runs fail only on new findings |
checkowners sync |
Generate CODEOWNERS and commit the result |
checkowners expertise <path> |
Evidence ranking for one path from cached analysis |
checkowners decay |
Report ownership freshness and continuity risk; suggest a transfer |
checkowners graph [--export dot] |
Render the ownership graph |
checkowners qualified-owners [<path>] [--all] |
Per-path qualified owner count (capped by top_n_owners) with candidate backup reviewers |
checkowners topology |
Exploratory repository topology from commit co-occurrence |
checkowners balance |
Compare a git authorship proxy, or completed reviews when the API is available |
checkowners onboard <path> |
Learning path from broadly shared paths to concentrated qualified ownership |
checkowners trends [--periods N] [--period-days D] |
Historical activity and qualified owner count over time |
checkowners github-action |
Run the full CI flow and write GITHUB_OUTPUT; used by the composite Action |
Trimmed JSON from this repository is in examples/sample-output.md. Reference configs live under examples/.
Trust
Core inference is local git. checkowners --offline opens no network connection. With no token, CheckOwners sends nothing anywhere.
PyPI releases use Trusted Publishing. The publish workflow authenticates with a GitHub OIDC token and does not store a PyPI API token. Sigstore signs each distribution.
Each GitHub release also carries a CycloneDX SBOM and a signed build-provenance attestation.
This repository moved here from a previous GitHub organization; Sigstore attestations for 0.5.0 and earlier record that earlier publisher. 0.5.1 and later are published from smusali/checkowners.
Inference is deterministic git analysis; the scoring heuristics live in analyze.py and are auditable. The codebase has been built with agent assistance. Every AI-assisted change is human-reviewed, tested, and signed off.
What the tool reads, what leaves the machine, what the cache holds, how tokens are handled, and which permissions are required is in docs/PRIVACY.md.
Documentation
- docs/USAGE.md: full configuration reference, ownership scoring formula, drift severity tiers, GitHub Actions integration, comparison table.
- docs/METHODOLOGY.md: formulas, prior art, terminology, and project principles.
- docs/GLOSSARY.md: one-sentence definitions of the terms used in reports.
- docs/limitations.md: when the tool can be wrong, and what repository evidence cannot prove.
- docs/FAQ.md: identity (usernames vs emails, teams + subteams), GitHub API access, file locations, tuning, troubleshooting.
- docs/PRIVACY.md: what is read, what leaves the machine, the cache,
cache purge, and the threat model. - docs/CONTRIBUTING.md: dev setup, commands, conventional commits, code conventions, PR workflow.
- Good first issues · Discussions
License
MIT
Metadata
Release files for checkowners 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| checkowners-0.6.0.tar.gz | 622.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| checkowners-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 730.9 kB
Release files / checkowners-0.6.0.tar.gz
| Download URL | checkowners-0.6.0.tar.gz |
|---|---|
| Size | 622.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8a72e07f471ac8aa566b6b1374df8355169a618556c3ea1d78521e181763db25
|
|
BLAKE2b-256 checksum How to use checksums |
cf933840a3881098940185b4bb38f4018bc3b5e7e2de1bab3996ffa105ac2699
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / checkowners-0.6.0-py3-none-any.whl
| Download URL | checkowners-0.6.0-py3-none-any.whl |
|---|---|
| Size | 108.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f8151810780dc82a430ea62d4d2e8b078a3254760c76756a9ab3d2c94d2c6c50
|
|
BLAKE2b-256 checksum How to use checksums |
0ebb2be2765e69c902453f793b7120f224e9e03ceb380c40c08095b8bbe70ac0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log