This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
Writing a commit message is the smallest chore in programming and the one I put off the most. So I built Sloth Commit: a command-line tool where a local open-weight model reads your staged diff and writes the message for you.
git add .
git commit # the editor opens with the message already written
The model runs on my own laptop through Ollama. The tool is plain Python with no dependencies beyond the standard library. A diff is just your unreleased source code, and it never leaves the machine.
Writing a message from a diff is a one-line idea, so I spent the effort on the parts around it:
.env files and huge binaries, then warns you.--slow, a bigger model polishes the draft. Speed is a dial you control.sloth-commit standup, which turns your week of commits into a few bullets.
Anyone who has typed fix stuff at 1 a.m. gets to be a little lazier, and the history still comes out readable.
I ran it on a real project of mine, a clinical NLP pipeline, on a laptop with 16 GB RAM and an RTX 3050 with 6 GB of VRAM, using qwen2.5-coder:3b:
PS> sloth-commit doctor
ok inside a git repository
ok Ollama is running at http://localhost:11434 (1 models)
ok fast model qwen2.5-coder:3b
PS> sloth-commit style
Learned from 7 recent commit(s):
format plain subject lines
casing Capitalised first word
period no
emoji no
length ~60 chars (limit 91)
PS> sloth-commit msg
Asking qwen2.5-coder:3b...
Update README.md with detailed project information
The reply took a second or two. Style Mimic worked: my repo uses plain, capitalised subjects with no period, and that is exactly what came back, not the Conventional Commits default.
The message itself was only half right, and I'd rather show that than hide it. My test change was four comment lines added to frontend/app.py, plus a README edit that only removed a trailing newline. The model wrote about the README and ignored the code. My guess is it anchored on the first file in the diff, but I haven't tested that. This is the kind of mistake a 3B model makes on a tiny, odd diff, and it's why the tool shows the message and asks for confirmation instead of committing silently.
A lazy git commit assistant. A local open-weight model (via Ollama) reads your staged diff and writes the commit message, so you don't have to. Your code never leaves your machine, it works offline, and it costs nothing to run.
Zero Python dependencies: standard library only.
$ git add
$ git commit # editor opens with the message already written
| Feature | What it does |
|---|---|
| Style Mimic | Reads your repo's last 30 commits and copies the conventions (Conventional Commits or plain, casing, length, emoji). No config file. |
| Secret Guard | Scans staged changes for API keys, tokens, private keys, .env files and huge binariesbefore the model or your history sees them. Local regexes, so nothing is uploaded to check. |
| Commit Splitter | Spots unrelated changes in one staged diff (a fix plus a README tweak) and commits them separately, each with its own message. Splits |
The open pieces are what make it work:
qwen2.5-coder:3b, which fits comfortably in 6 GB of VRAM. The slow model defaults to qwen2.5-coder:7b. Both are config, not code, so any model Ollama can run works./api/chat, with clear errors for the failures people actually hit: Ollama isn't running, or the model isn't pulled (it tells you the exact ollama pull command).package-lock.json.<think> blocks. All of that is stripped.sloth-commit hook install adds a prepare-commit-msg hook. It does nothing for -m, merges, squashes or amends, and if Ollama is down it silently lets you type the message yourself. It will never be why a commit fails, apart from one opt-in: SLOTH_GUARD=block stops commits that contain suspected secrets.git commit runs through the installed hook.
Your diff is your source code. Hosted commit tools have to upload it to work. Sloth Commit can't, because there is nowhere for it to go. For private or unreleased projects, that's the whole difference.
Secret Guard only makes sense locally. Checking a diff for leaked API keys by sending it to someone else's server is a good way to leak the keys. With a local model, the scan, the prompt and the answer all stay on the machine.
It's free and works offline. No API key, no per-token bill, no rate limit. It works on a train, on campus Wi-Fi, or on a plane.
It's swappable. If a better small coding model appears next month, it's one environment variable: SLOTH_MODEL=.... You can also point it at another machine on your network or at your own fine-tune. A closed API gives you whichever model the provider decides to serve.
I didn't run a head-to-head benchmark against a hosted model, so I won't quote a number. A frontier model would very likely have described the app.py change that my 3B model missed. For me, a message that is good most of the time, is instant, and is free and private beats one that is slightly better but sends my code to a server I don't control. Where it isn't good enough, --slow and the confirm step catch it.
The model answers in a second or two on a 6 GB laptop GPU, which is faster than I can think of a message, let alone type one. I used it on my own repo this week, and the tool keeps a local tally (sloth-commit stats) of characters you didn't type and time saved. That estimate is based on assumed typing speed, so treat it as a rough figure. What I really gained is a repo history in a consistent style that I no longer have to think about.
Gemma: Sloth Commit is model-agnostic, so I swapped Google's open-weight Gemma into it with one environment variable (SLOTH_MODEL=[the exact Gemma model name you pulled]) and compared it with Qwen on the same staged diff. [One or two honest sentences on what you saw, for example whether it described the app.py change that Qwen missed, or which one was faster on the RTX 3050.]
A huge shoutout to claude and shreyashkakad for contributing (https://dev.to/shreyashkakad)