The problem
The change is done. Tests pass. Then I run git commit and sit there,
staring at a blinking cursor, trying to compress an hour of work into
seven words.
I have typed "fix stuff" more times than I will admit. Also "wip",
"changes", and once, memorably, "please work". Every one of those
commits was good code with a message written by a person who had
already spent his attention on the code.
So for Slow and Steady I built the tool I kept wishing for. It does not
write code. It does the clerical work after the code, which is exactly
the work laziness should take.
What I built
lazycommit is a small CLI, one Python file, standard library only.
Stage your changes, run it, and it prints three commit messages in
Conventional Commits format. You press 1, 2 or 3, and it commits
with the one you picked. Press q and it walks away and commits
nothing.
git add stats.py
lazycommit
No dependencies to install, no config file, no API key. The whole thing
is small enough to read in one sitting, which I count as a feature.
How it works
Three steps, and the interesting part is what each one refuses to do.
1. Read the staged diff, and only the staged diff.
git diff --cached. Unstaged work never leaves the machine, because it
was never part of this commit. If nothing is staged, the tool says so
and exits. It does not guess.
2. Send a capped diff to a free text endpoint.
The diff is truncated at 6,000 characters before it goes anywhere. The
head of a diff carries the file names and the first hunks, which is
enough context for a subject line, and the cap keeps the request small.
The default endpoint is the Pollinations text API: free, no key,
a messages array in and text out. The model and endpoint are flags
(--model, --endpoint), so swapping providers is a one-line change.
The prompt is strict. Exactly three lines. Conventional Commits format.
Imperative mood, under 72 characters each. Three different angles on the
same change.
3. Parse like you do not trust the model. Because I do not.
Models like to help. They add "Here are three options for you!" and
numbering and backticks. The parser strips all of that, prefers lines
that actually match the type(scope): summary pattern, drops
duplicates, and takes the first three. If nothing usable comes back,
you get a one-line error. Not a traceback, and not a garbage commit.
That defensive parser is most of the code, and most of the tests.
23 tests, all offline, API and git mocked.
Demo
A real run, live free API, throwaway repo. The staged change adds an
empty-list guard to an average() helper:
$ git add stats.py
$ lazycommit
1. feat(stats): handle empty list in average
2. fix(stats): return 0 for empty numbers
3. perf(stats): guard against division by zero
pick 1-3 (or q to quit): 1
[master bab7bea] feat(stats): handle empty list in average
1 file changed, 2 insertions(+)
Notice what happened there. Three messages, one change, and they still
disagree about whether it was a feat, a fix or a perf. Anyone who
has argued about commit types in a review thread knows that argument.
The tool does not settle it. It just makes sure I am choosing between
three decent options instead of inventing a fourth bad one from
nothing.
Total time, about ten seconds, most of it network.
What I learned
The API call was the easy part. Fifteen lines, including the error
handling. Everything else was deciding where the laziness stops.
One generated message would have been faster to build. It also would
have been a command: take it or leave it. Three messages is a menu.
Reading three short lines and pressing one key is genuinely lazy, and
the choice stays mine. That difference is the whole design.
The other thing: a tool that commits on your behalf has to be boring
about safety. Stage nothing, get nothing. Model rambles, commit
nothing. Network dies, one clean line of error and commit nothing.
Every failure path in lazycommit ends the same way, with your repo
exactly as you left it.
Slow and steady, it turns out, is a decent spec for a lazy tool.
Small, a little stubborn, and it saves its effort for the part you
actually want to skip.
The code is on GitHub: https://github.com/Dextheking1/lazycommit. MIT licensed.
Take it, break it, and go back to not writing commit messages.
This is part of the DEV x MLH Hacktoberfest "Slow and Steady"
challenge.
Top comments (0)