~/projects/committed $ generate

committed.

Conventional Commit messages from your code diffs.

~397 MB
runs locally on CPU
quantized GGUF
0.15 → 0.60
commit-type accuracy
vs. base, reweighted
0.29 → 0.81
faithfulness
vs. base model
0.78 → 2.09
graded mean (0–3)
LLM-judge score
live · connecting
total downloads
across the project's artifacts — models, adapters & dataset

I built Committed on Qwen3-1.7B, then tested whether a model a third the size could do the same job — and it essentially can. The 0.6B fine-tune matches the 1.7B on picking the right commit type and staying faithful to the diff, at roughly a third the parameters, a smaller download, and faster local inference. The one honest trade is specificity: it writes slightly vaguer messages. So the 0.6B is the default here — for most commits it's the better deal — and the 1.7B stays available as the bigger sibling when you want maximum specificity. Both are the same QLoRA fine-tune recipe on ~58k real commits, served as a quantized GGUF through llama.cpp, CPU-only, so your diffs never leave your machine. A GBNF grammar constrains decoding, so every output is a valid commit by construction. Paste a diff below, or try an example.

Try the demo ↓
architecture
rendering diagram…
committed - generateconnecting
try an example
model
Same recipe and data, two sizes — see the full comparison in results.
0 chars

This hosted demo sends your diff over the network to the model Space to generate a message. The model itself is small and runs fully offline. If you would rather not send code anywhere, run it locally.

// how it works

Committed is a complete pipeline, not just a model. I started from CommitChronicle (roughly 10.7M real GitHub commits) and wrote a filter to extract clean, single-file diffs paired with well-formed Conventional Commit subjects, normalizing them into a consistent training target. I fine-tuned Qwen3 with QLoRA on the result — first the 1.7B, then the 0.6B on the identical recipe — evaluated each against its un-tuned base on a multi-metric harness with an LLM judge I validated against my own hand-ratings, then served them locally through llama.cpp with grammar-constrained decoding that guarantees every output is syntactically valid. Most of the work was the data, not the model, and all four stages (data, training, evaluation, serving) are here.

git diffcommittedfeat(scope): subject

// results

I fine-tuned two sizes on the identical pipeline — Qwen3-1.7B and a smaller Qwen3-0.6B — and evaluated each against its un-tuned base on a 442-example test sample, scored by a DeepSeek (deepseek-chat)judge on four orthogonal axes and reweighted to the test split's true commit-type distribution. All four arms share the same judge, so every comparison below is apples-to-apples.

spotlighting Qwen3-0.6B — synced with the demo

The default. It matches the 1.7B on commit-type and faithfulness at roughly a third the parameters — a smaller download and faster local inference. The honest trade: slightly vaguer messages (specificity 0.55 vs 0.67).

2.094
graded mean (0–3)
0.726
type-correctness
0.810
faithfulness
0.545
specificity
metric0.6B base0.6B ft1.7B base1.7B ft
Prefix-type accuracyreweighted; always-fix floor 0.4890.1540.6010.1310.637
Type-correctness0.2960.7260.2960.778
Faithfulness0.2850.8100.4910.848
Completeness0.3530.7290.5430.776
Specificity0.4140.5450.8140.667
Conjunctive (all 4)0.1010.3590.1750.471
Graded mean (0–3)0.7772.0941.4472.139
feat-share of outputsdiagnostic: base collapses to ~all-feat86.7%9.7%95.5%8.4%

Both base models share the same dominant failure mode — “feat-collapse”: they label the overwhelming majority of diffs as feat (86.7% for the 0.6B base, 95.5% for the 1.7B), regardless of what the change actually did. Because fix commits alone make up about 49% of real-world commits, a model that almost never predicts fix scores below a trivial always-fix baseline (0.489) on reweighted type accuracy — which is exactly what both bases do (0.15 and 0.13). Fine-tuning breaks the collapse: feat-share drops under 10% and type accuracy clears the floor for both sizes.

The one axis the fine-tunes give something up on is specificity. The 1.7B fine-tune trades down from its base (0.81 → 0.67) as it adopts the terse, normalized subject style of the training targets, and the smaller 0.6B is vaguer still (0.55). It's a real trade-off, traceable to a normalization choice in the training data, and the next iteration targets it. Otherwise the two fine-tunes are close — graded 2.09 (0.6B) vs 2.14 (1.7B) — so the 0.6B gets most of the quality at roughly a third the size.

An LLM judge is only trustworthy if it agrees with a human. I hand-rated 50 examples blind and validated the DeepSeek judge against them:

axisagreementCohen's κ
type-correctness0.820.61
faithfulness0.780.56
completeness0.800.60
specificity0.880.34

Three axes land at moderate-to-substantial agreement (κ ≈ 0.56–0.61); specificity is the weakest (κ 0.34), so specificity-driven differences carry the most judge uncertainty. Two honest caveats: these DeepSeek-judged numbers are not comparable to earlier Gemini-judged figures (only the deltas within the table above are valid), and n=50 gives wide confidence intervals.

// sample outputs

input diffPython
@@ -1639,7 +1639,7 @@ def moveaxis(a, source, destination): >>> np.transpose(x).shape (5, 4, 3)->>> np.swapaxis(x, 0, -1).shape+>>> np.swapaxes(x, 0, -1).shape (5, 4, 3) >>> np.moveaxis(x, [0, 1], [-1, -2]).shape (5, 4, 3)
base Qwen3-1.7B →feat(additional-function): Add `swapaxes` function with same behavior as `swapaxis` but using `swapaxes` notation. 📦
committed →docs: Fix typo in np.swapaxis docstring
input diffC#
@@ -20,13 +20,17 @@ public partial class RestClient { /// <param name="request">Request to be executed</param>-public RestResponse Execute(RestRequest request) => AsyncHelpers.RunSync(() => ExecuteAsync(request));+/// <param name="cancellationToken">The cancellation token</param>+public RestResponse Execute(RestRequest request, CancellationToken cancellationToken = default)+    => AsyncHelpers.RunSync(() => ExecuteAsync(request, cancellationToken));
base Qwen3-1.7B →feat(adds-parameter): Adds a `CancellationToken` parameter to `Execute` and `DownloadStream` methods, allowing for cancellation support. 📦
committed →feat(RestClient): add support for cancellation tokens

// run it locally

Committed runs entirely on your machine — no API, no diff ever leaving your laptop. It defaults to the 0.6B (a smaller, faster download); the 1.7B is available when you want maximum specificity. Install it once, pipe a diff in, and get a commit message back:

pip install --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpu "committed @ git+https://github.com/marzoukbaig14/Committed.git"
showing Qwen3-0.6B~397 MB download
git diff | committed   # 0.6B GGUF, ~397 MB

Both serve as a quantized GGUF through llama.cpp on CPU — the first run downloads the weights once (~397 MB), then it's fully offline. The hosted demo above runs the model you pick with the toggle.

// built with

Qwen3 (0.6B / 1.7B)QLoRA / PEFTllama.cppGBNF grammarFastAPIDockerHugging FaceNext.js
GitHub repo 0.6B GGUF 0.6B adapter 1.7B GGUF 1.7B adapter Dataset