Metadata-Version: 2.4
Name: commithygiene
Version: 0.1.0
Summary: Read-only linter for noisy, AI-generated git commit history
Author: commithygiene contributors
License: MIT
Keywords: git,commits,linter,ai,agent,cli,ci
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# commithygiene

<div align="center">

**The read-only linter for AI-mangled git history.**

[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![Zero dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)](#-zero-dependencies)
[![License: MIT](https://img.shields.io/badge/license-MIT-yellow.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/tests-13%2F13%20passing-success.svg)](tests/)

*AI agents write a lot of commits. Some of them deserve to be squashed before anyone sees them.*

</div>

---

## What problem does this solve?

Your AI coding agent (or you, at 2 a.m.) just produced this history:

```
a1b2c3d  Update LoginForm.tsx
d4e5f6  Fix TypeScript error
g7h8i9  Revert LoginForm.tsx
j0k1l2  Update LoginForm.tsx again
m3n4o5  Fix import
p6q7r8  wip
s9t0u1  LoginForm complete
```

Seven commits. One component. **History that is useless for bisect, hostile to review, and embarrassing to merge.**

`commithygiene` finds these commits — *before* they hit your branch. It's read-only: it never rewrites history, never stages files, never touches your reflog. It just **reads** and **reports**. You decide what to do.

> **AI wrote the code. You're still responsible for the history.**

## Why commithygiene?

Every other tool in this space wants to *rewrite* your history:

| Tool | Approach | Needs | Can it gate CI? |
|---|---|---|---|
| Claude `git-squash` skill | Interactive squash | Claude Code runtime | ❌ Lives in a chat session |
| `commit-tidy` / `squash-commits` skills | LLM-guided rebase | Claude + context | ❌ |
| `yawn` | AI *writes new* commit messages | API key | ❌ |
| `git-shrink` | Group + squash by similarity | Node.js + npm | ⚠️ Rewrites history |
| **commithygiene** | **Read-only linter with exit codes** | **Just Python 3.10+** | ✅ **Made for CI** |

The ecosystem had `prettier` but no `eslint`. `git-cliff` but no `shellcheck`. **commithygiene is the linter** — the thing you put in your pipeline to *catch* noise, not the thing you run interactively to fix it.

## Features

- 🔒 **Read-only by design** — `git log` and `git show` only. Zero risk of destroying history.
- 🪶 **Zero dependencies** — one file, pure Python standard library. No npm, no Rust toolchain, no API key.
- 🤖 **Knows AI fingerprints** — detects `wip`, `fix typo again`, `revert the revert`, `actually works now`, and other agent churn patterns.
- 🚦 **CI-ready exit codes** — `0` clean, `1` noise found, `2` error. `--strict` promotes warnings to errors.
- 📊 **JSON output** — machine-readable for scripts, bots, and dashboards.
- 📈 **Health reports** — `report` gives you a project-wide noise ratio and verdict.
- 🐍 **Python 3.10+** — runs anywhere Python runs. Windows, macOS, Linux.

## Quick start

### 1. Drop it in

```bash
# No install needed — it's a single file.
curl -O https://raw.githubusercontent.com/DEL8108/commit-hygiene-checker/main/commithygiene.py
python commithygiene.py check
```

Or install properly:

```bash
pip install git+https://github.com/DEL8108/commit-hygiene-checker.git
commithygiene check
```

### 2. Run it on your current branch

```bash
$ commithygiene check

  commithygiene — scanned 8 commit(s)

  ✗ noise-subject     650b5e8c43  noise commit: 'wip'
  ✗ noise-subject     9743088c03  noise commit: 'wip'
  ! churn-subject     562493cd3e  possible churn commit: 'fix typo again'
  ! churn-subject     5871f1d5c1  possible churn commit: 'actually works now'
  ! churn-subject     a4590d7b47  possible churn commit: 'revert the revert'
  ! trivial-only      4ffd15159e  tiny diff touching only trivial files (README.md)
```

Exit code `1` — your CI just found noise before your reviewer did.

### 3. Gate your PRs

```yaml
# .github/workflows/hygiene.yml
name: Commit Hygiene
on: [pull_request]
jobs:
  hygiene:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # need full history
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Check commit hygiene
        run: |
          curl -O https://raw.githubusercontent.com/DEL8108/commit-hygiene-checker/main/commithygiene.py
          python commithygiene.py check "${{ github.event.pull_request.base.sha }}..HEAD" --strict
```

Now every PR with a `wip` or an `actually works now` in it gets flagged **before merge**.

## Usage

### `check` — find noisy commits

```bash
commithygiene check                    # scan all of HEAD
commithygiene check HEAD~20..HEAD      # scan the last 20 commits
commithygiene check main..HEAD         # only commits on this branch
commithygiene check --strict           # warnings become errors (exit 1)
commithygiene check --format json      # machine-readable output
```

### `report` — project-wide health

```bash
$ commithygiene report

  commit hygiene report — HEAD

    commits        : 128
    noise commits  : 31 (24%)
    churn commits  : 12 (9%)
    verdict        : very noisy
```

### Exit codes

| Code | Meaning |
|---|---|
| `0` | Clean — no noise, or only warnings (without `--strict`) |
| `1` | Noise found — errors, or warnings under `--strict` |
| `2` | Usage / I/O error (not a git repo, bad range, git missing) |

## What gets flagged

| Rule | Severity | Example |
|---|---|---|
| `noise-subject` | error | `wip`, `tmp`, `fixup!`, `???`, `initial commit`, `checkpoint` |
| `churn-subject` | warning | `fix typo again`, `revert the revert`, `actually works now`, `for real this time` |
| `trivial-only` | warning | a 1-file commit touching only `README.md`, lockfiles, `.gitignore` |

Warnings stay warnings unless you pass `--strict` — because sometimes a `revert` is a legitimate, deliberate decision. `commithygiene` errs on the side of *showing* you, not *blocking* you.

## How it works

```
git log --format=%H <range>          # list commits, oldest first
        │
        ▼
git show --numstat --format=%s <h>   # subject + per-file stats per commit
        │
        ▼
heuristic engine                     # noise patterns, churn tokens, trivial paths
        │
        ▼
findings ──► table / json ──► exit code 0/1/2
```

No git history is modified at any step. The only commands executed are `git log`, `git show`, and `git rev-parse`. You can audit the entire tool in one sitting — it's ~500 lines.

## Why "hygiene"?

Because that's what it is. Like flossing, nobody *wants* to think about commit hygiene, but the alternative is worse. The name also means the tool is easily discoverable apart from the squash/rewrite crowd — this is the *prevention* layer, not the *surgery* layer.

## Limitations

Being read-only and heuristic-driven means some things are out of scope, on purpose:

- **It never rewrites history.** For that, use `git rebase -i`, `git-squash`, or `git-shrink`.
- **It judges by signals, not semantics.** A `wip` with a giant meaningful diff is still flagged — you know your repo better than the heuristic does.
- **It doesn't verify build state.** Two commits both labeled `fix` could each be perfectly fine.
- **No AI, no LLM calls, no telemetry.** It's deterministic. The same input always produces the same output. That's a feature.

## Contributing

Found a noise pattern the tool missed? A false positive? Contributions are welcome:

1. Fork and clone the repo.
2. Run the tests: `python -m unittest discover -s tests -v`
3. Add a test for your pattern in `tests/test_commithygiene.py`.
4. Open a PR with a clear description.

The whole philosophy is "small, conservative, zero false-positive pressure." New rules need example commits that prove the signal is real.

## License

MIT — see [LICENSE](LICENSE). Do whatever you want with it; attribution appreciated.

---

<div align="center">

**Star it if your agent's commit history has ever made you say "what is this?"** ⭐

</div>
