Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

3 Commits

Repository files navigation

lazycommit

Write your git commit messages with AI.

lazycommit reads the diff you have staged, asks an AI to describe it, shows you the message it came up with, and commits only if you accept it. It replaces the part of git commit -m "..." where you stare at the screen trying to remember what you just did.

$ lazycommit
3 files changed, 87 insertions(+), 12 deletions(-)
┌─ Suggested commit ──────────────────────────────────────────┐
│ feat(auth): rotate refresh tokens on every use │
│ │
│ Refresh tokens were long lived, so a leaked token stayed │
│ valid until it expired. Each refresh now issues a new │
│ token and invalidates the previous one. │
│ │
│ - store refresh tokens hashed instead of in plain text │
│ - revoke the whole token family when a used token reappears │
└─────────────────────────────────────────────────────────────┘
Commit with this message? [y/N] y
committed 4f2a1c9 feat(auth): rotate refresh tokens on every use

Requirements

  • Go 1.21 or newer, to build it
  • git
  • The Claude Code CLI, already signed in

The message is generated by shelling out to claude --print, so lazycommit reuses the credentials that CLI already holds. There is no API key to configure and no extra subscription to pay for.

Install

git clone <this repo>&&cd lazycommit
make install # builds and copies the binary to ~/.local/bin

Or, without the Makefile:

go build -o lazycommit .&& mv lazycommit ~/.local/bin/

Make sure ~/.local/bin is on your PATH.

Usage

lazycommit # describe and commit what is already staged
lazycommit -a # stage everything first, then describe and commit
lazycommit --dry-run # print the message and stop, committing nothing
lazycommit -y # skip the confirmation prompt
lazycommit --hint "ticket ASAP-1421, part of the PCI audit"

Flags

FlagDefaultWhat it does
-a, --alloffStage every change (git add -A) before describing it
-y, --yesoffCommit without asking for confirmation
-n, --dry-runoffPrint the message and exit without committing
--hintemptyExtra context the diff cannot show: a ticket ID, the reason behind the change
--modelsonnetModel to generate the message with
--langenglishLanguage to write the message in
--timeout2mHow long to wait for the model
--max-diff120000Maximum diff size in bytes sent to the model

Answering anything other than y or yes aborts, leaving the index exactly as it was. Nothing is committed unless you say so.

Piping

When stdout is not a terminal the message is printed raw, without the frame:

lazycommit --dry-run > message.txt
lazycommit --dry-run | xclip -selection clipboard

Status lines and errors always go to stderr, so they never pollute the piped message.

How it works

  1. git diff --staged produces the diff, and git diff --staged --stat the file summary that survives even when a huge diff has to be truncated.
  2. The diff, the current branch and the last 10 commit subjects (as a style reference) go to the model over stdin.
  3. The model runs with a replaced system prompt and every tool denied, so it behaves as a plain diff-to-message transformer rather than an agent. It runs from a scratch directory, which keeps the target repository's CLAUDE.md, hooks and settings out of the session.
  4. The message is framed on screen, and git commit -F - records it only after you accept. Committing through git means your hooks, GPG signing and commit.template config all still apply.

Message conventions

The model is instructed to follow Conventional Commits: a type(scope): subject line in the imperative mood capped at 72 characters, a blank line, then a body wrapped at 72 columns explaining what changed and why. It never adds Co-authored-by or any other trailer.

Development

make build # compile to ./bin/lazycommit
make test# run the tests
make check # gofmt, go vet and the tests

Layout

main.go entry point
cmd/root.go flags and the accept/commit flow
internal/git/git.go the git commands, shelled out
internal/ai/provider.go the Provider interface and the request sent to it
internal/ai/claudecli.go the claude CLI provider and its system prompt
internal/ui/ the frame, the spinner, the confirmation prompt

Adding another backend means implementing ai.Provider and selecting it in cmd/root.go; nothing else knows which model wrote the message.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages