Metadata-Version: 2.5
Name: checkowners
Version: 0.6.0
Summary: Keep CODEOWNERS aligned with reality.
Project-URL: Homepage, https://github.com/smusali/checkowners
Project-URL: Issues, https://github.com/smusali/checkowners/issues
Project-URL: Source, https://github.com/smusali/checkowners
Project-URL: Documentation, https://github.com/smusali/checkowners/blob/main/docs/USAGE.md
Project-URL: Changelog, https://github.com/smusali/checkowners/blob/main/docs/CHANGELOG.md
Author-email: Samir Musali <samir.musali@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: cli,code-review,codeowners,drift-detection,expertise-decay,git,github-actions,knowledge-graph,ownership,platform-engineering,team-topology
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Version Control :: Git
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: pyyaml<7,>=6.0
Requires-Dist: rich<16,>=13.0.0
Requires-Dist: typer<1,>=0.9.0
Provides-Extra: all
Requires-Dist: networkx<4,>=3.0; extra == 'all'
Requires-Dist: pygithub<3,>=2.0.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: hypothesis<7,>=6.100; extra == 'dev'
Requires-Dist: jsonschema>=4.18; extra == 'dev'
Requires-Dist: mutmut<4,>=3; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: networkx<4,>=3.0; extra == 'dev'
Requires-Dist: pygithub<3,>=2.0.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: pyyaml-ft>=8.0.0; (python_version >= '3.13') and extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: github
Requires-Dist: pygithub<3,>=2.0.0; extra == 'github'
Provides-Extra: graph
Requires-Dist: networkx<4,>=3.0; extra == 'graph'
Description-Content-Type: text/markdown

[![CI](https://github.com/smusali/checkowners/actions/workflows/ci.yml/badge.svg)](https://github.com/smusali/checkowners/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/smusali/checkowners/graph/badge.svg)](https://codecov.io/gh/smusali/checkowners)
[![PyPI](https://img.shields.io/pypi/v/checkowners.svg)](https://pypi.org/project/checkowners/)
[![PyPI downloads](https://static.pepy.tech/badge/checkowners/month)](https://pepy.tech/project/checkowners)
[![Python versions](https://img.shields.io/pypi/pyversions/checkowners.svg)](https://pypi.org/project/checkowners/)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/smusali/checkowners/blob/main/LICENSE)

# CheckOwners

**Keep CODEOWNERS aligned with reality.**

```text
$ 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](https://docs.pypi.org/trusted-publishers/). Sigstore signs each distribution.

> This is a knowledge-risk tool, not a performance-measurement tool. Using it for individual evaluation is unsupported and harmful.

```bash
uvx checkowners drift
```

## Install

Requires Python 3.11 through 3.14 and Git 2.23 or newer.

```bash
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

```bash
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](https://github.com/smusali/checkowners/blob/main/docs/USAGE.md#exit-codes).

## CI

Least privilege (job summary only; no pull-request comment):

```yaml
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](https://github.com/smusali/checkowners/blob/main/docs/USAGE.md#github-actions) and [Pre-commit](https://github.com/smusali/checkowners/blob/main/docs/USAGE.md#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`.

![checkowners drift reporting high severity on /payments/](https://raw.githubusercontent.com/smusali/checkowners/main/examples/demo.gif)

The composite Action posts that finding as one comment on same-repo pull requests:

![CheckOwners pull-request comment for high-severity drift](https://raw.githubusercontent.com/smusali/checkowners/main/examples/pr-comment.png)

`generate --force` on the same tree writes [examples/sample-CODEOWNERS](https://github.com/smusali/checkowners/blob/main/examples/sample-CODEOWNERS):

```text
# 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 `@handles` locally. Other addresses use the GitHub API when a token is set.
- One person with several emails counts once.
- `generate` writes CODEOWNERS and collapses a directory of identical owners into one `dir/` rule.
- `drift` matches 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](https://github.com/smusali/checkowners/blob/main/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](https://github.com/smusali/checkowners/blob/main/examples/sample-output.md). Reference configs live under [examples/](https://github.com/smusali/checkowners/tree/main/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](https://docs.pypi.org/trusted-publishers/). 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](https://github.com/smusali/checkowners/blob/main/docs/PRIVACY.md).

## Documentation

- [docs/USAGE.md](https://github.com/smusali/checkowners/blob/main/docs/USAGE.md): full configuration reference, ownership scoring formula, drift severity tiers, GitHub Actions integration, comparison table.
- [docs/METHODOLOGY.md](https://github.com/smusali/checkowners/blob/main/docs/METHODOLOGY.md): formulas, prior art, terminology, and [project principles](https://github.com/smusali/checkowners/blob/main/docs/METHODOLOGY.md#principles).
- [docs/GLOSSARY.md](https://github.com/smusali/checkowners/blob/main/docs/GLOSSARY.md): one-sentence definitions of the terms used in reports.
- [docs/limitations.md](https://github.com/smusali/checkowners/blob/main/docs/limitations.md): when the tool can be wrong, and what repository evidence cannot prove.
- [docs/FAQ.md](https://github.com/smusali/checkowners/blob/main/docs/FAQ.md): identity (usernames vs emails, teams + subteams), GitHub API access, file locations, tuning, troubleshooting.
- [docs/PRIVACY.md](https://github.com/smusali/checkowners/blob/main/docs/PRIVACY.md): what is read, what leaves the machine, the cache, `cache purge`, and the threat model.
- [docs/CONTRIBUTING.md](https://github.com/smusali/checkowners/blob/main/docs/CONTRIBUTING.md): dev setup, commands, conventional commits, code conventions, PR workflow.
- [Good first issues](https://github.com/smusali/checkowners/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) · [Discussions](https://github.com/smusali/checkowners/discussions)

## License

MIT
