commitpreflight
Pre-flight lint for commit messages written by AI coding agents.
Your agent writes a commit message, calls git commit, gets rejected by a hook, and burns a
turn rewriting it. commitpreflight catches the message before the commit, and returns a
concrete fix rather than a complaint.
pip install commitpreflight
$ echo "Added retry budget to the upload path so that flaky networks recover." | commitpreflight
error: header is not `tag(scope): subject` — got: 'Added retry budget to the upload path so' [conventional-format]
try: feat(scope): added retry budget to the upload path so that flaky networks recover.
error: subject must not end with a period [subject-punctuation]
try: Added retry budget to the upload path so that flaky networks recover
warning: subject opens with 'added'; conventional commits use the imperative [imperative-mood]
try: add retry budget to the upload path so that flaky networks recover.
Why these rules
The rule set is not a style opinion. It is seeded by what actually breaks: 10,976 CLI failures logged over 7 days by a fleet of autonomous coding agents. Roughly 1 in 5 was a malformed commit message — the single largest class of agent CLI failure in the corpus.
| failure | share of all agent CLI failures |
|---|---|
| subject over the length limit | 13.8% |
missing tag(scope): format |
8.1% |
The useful detail is the shape of the overshoot, not its existence:
| how far over the 72-char limit | share of overshoots |
|---|---|
| 1–5 chars | 57% |
| 6–10 chars | 24% |
| 11+ chars | 19% |
81% of overshoots miss by 10 characters or fewer. Agents do not write essays into the
subject line; they miss the limit by a hair. So the right intervention is a trim at the last
word boundary, which is what commitpreflight suggests — and why it declines to suggest one
when the overshoot is large enough that trimming would be a rewrite.
Use it as a git hook
printf '#!/bin/sh\nexec commitpreflight "$1"\n' > .git/hooks/commit-msg
chmod +x .git/hooks/commit-msg
Exit code is 1 when any error-severity finding fires, 0 otherwise. --strict makes
warnings blocking too.
Use it from an agent
--json gives a machine-readable list your agent can act on without parsing prose:
$ commitpreflight --json .git/COMMIT_EDITMSG
[
{
"rule": "imperative-mood",
"severity": "warning",
"message": "subject opens with 'added'; conventional commits use the imperative",
"fix": "add retry budget to the upload path"
}
]
Or call it directly:
from commitpreflight import check
for finding in check("feat(api): Added a thing."):
print(finding.rule, finding.severity, finding.fix)
Rules
| rule | severity | what it catches |
|---|---|---|
empty |
error | no message at all |
conventional-format |
error | header is not tag(scope): subject |
tag-case |
error | tag is not lowercase |
tag-unknown |
error | tag outside the allowed set |
scope-required |
error | scope missing when required |
scope-empty |
error | tag(): subject |
subject-empty |
error | nothing after the tag |
subject-length |
error | header over the limit |
subject-punctuation |
error | subject ends with a period |
body-blank-line |
error | body not separated from the subject |
imperative-mood |
warning | added / fixing / updates openers |
subject-case |
warning | subject starts capitalised |
body-line-length |
warning | wrappable body line over the limit |
Configuration
Optional, in pyproject.toml:
[tool.commitpreflight]
max_subject = 72
max_body_line = 100
require_conventional = true
require_scope = false
allow_unknown_tags = false
tags = ["feat", "fix", "docs", "refactor", "test", "chore"]
disable = ["subject-case"]
Teams
Running commitpreflight across a fleet of AI agents at scale? Team subscription: $100/mo.
License
MIT
Release files for commitpreflight 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| commitpreflight-0.1.1.tar.gz | 13.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| commitpreflight-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:21.1 kB
Release files / commitpreflight-0.1.1.tar.gz
| Download URL | commitpreflight-0.1.1.tar.gz |
|---|---|
| Size | 13.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aeacc7dbad8c3d296f125a08e113b720066eaed226f6aff23c8f87b88ededc08
|
|
BLAKE2b-256 checksum How to use checksums |
e1faaf46ec56069c741005c1a156836c805f07db4ed3680b2641a9b33a9198b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / commitpreflight-0.1.1-py3-none-any.whl
| Download URL | commitpreflight-0.1.1-py3-none-any.whl |
|---|---|
| Size | 7.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
95ebbb7d0b2d1039c1a496dd9a7f1cbf3cb5cc73f1bea7f5cf4ea2b76816b614
|
|
BLAKE2b-256 checksum How to use checksums |
b455e6cb71525c0b70664bc001c1d3afa9a6b705cae195148fcdcb8f0cbc1274
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|