rule-based, no api calls
works on a plane, in a tunnel, in a faraday cage. no tokens burned. no rate limits. the tool is a few hundred lines of python and a lookup table.
commitgen reads your staged diff and suggests a conventional-commit message using rule-based heuristics. no prompts, no api key, no tokens. regexes, path matching, and roughly 400 lines of python doing the boring part well enough.
╭─────────────────╮ ╭──────────────────────╮
│ git diff │ ──────▶ │ commitgen analyzes │
│ (staged) │ │ │
│ │ │ · file paths │
│ + def login() │ │ · added symbols │
│ + import │ │ · imports │
│ bcrypt │ │ · test coverage │
╰────────┬────────╯ ╰──────────┬───────────╯
│ │
└──────────────┬────────────────┘
▼
╭───────────────────────╮
│ feat(auth): add │
│ login flow │
╰───────────────────────╯
rev. 0.1 · cg-2026-04-19
stage a file, run commitgen, read what it thinks, accept or edit. same keystrokes you use now.
01 $ git add src/auth/login.py 02 $ commitgen 03 04 suggested: 05 feat(auth): add login flow 06 07 why: 08 · new function login_user() in src/auth/login.py 09 · imports bcrypt suggest password handling 10 · no test file touched → consider adding one 11 12 accept? [y/n/e] e 13 (opens your $EDITOR with the suggestion pre-filled)
01 $ commitgen --explain 02 03 heuristics matched (ranked): 04 [type] 05 feat new symbol `def login_user` +0.80 06 fix no bug-ish keywords in diff +0.05 07 refactor no pure-rename rows +0.02 08 09 [scope] 10 auth path prefix `src/auth/` on 1/1 files +0.95 11 12 [subject] 13 add login flow 14 · verb `add` from net-add vs net-delete ratio 15 · noun `login` from symbol name `login_user` 16 · noun `flow` from import graph (bcrypt + http handler) 17 18 final → feat(auth): add login flow 19 disagree? use --type / --scope to lock, or press `e` to edit.
four moving parts. together they suggest something usable more often than not.
works on a plane, in a tunnel, in a faraday cage. no tokens burned. no rate limits. the tool is a few hundred lines of python and a lookup table.
reads conventional-commit types from the shape of your diff. new symbol added → feat. test-only changes → test. docs folder → docs. pure renames → refactor.
every heuristic that fired gets printed with a weight. agree, disagree, or learn from what it saw. no black box, no vibes.
heuristics miss sometimes. lock the type with --type fix, lock the scope with --scope api, or skip review with --no-edit. tool stays out of your way.
"why not just call an llm?" because i already know what changed. i staged it. i don't need a 7-billion-parameter model to read+def login_userand guessfeat(auth).
for people who can't trust a model but will trust a regex.
python 3.9+, macos and linux when it ships. repo isn't up yet, i'm still polishing it. ping bennett@frkhd.com if you want early access.