A small Rust CLI that generates conventional commit messages from your Git diffs by calling the OpenAI Chat Completions API. It supports streaming (optional), colorized output, progress spinners, strict filtering, a dry-run + approval workflow, and model tuning knobs (verbosity, reasoning effort, store).
- 🧠 Good messages by default: subject + 3–6 bullets (imperative, concise)
- 🔵 Colorized output (blue commit message),
--color auto|always|never - ⏳ Progress spinners (default on),
--no-progressto disable - 📡 Streaming tokens (
--stream) or non-streaming (default) - ✅ Dry run + approve (
--dry-runprompts to commit or abort) - 🧰 Strict post-filter to keep only header + bullets (
--strict) - 🎛️ Model knobs:
--model,--verbosity low|medium|high,--effort minimal|medium|high,--store
# From the project root
cargo install --path .This installs the binary to ~/.cargo/bin/commitmsg (by default).
Make sure ~/.cargo/bin is on your PATH.
# Verify it's on PATH:
echo "$PATH" | tr ':' '\n' | grep -Fx "$HOME/.cargo/bin" || echo '=> Add ~/.cargo/bin to PATH'
# Add to PATH (bash/zsh):
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc
source ~/.bashrc # or ~/.zshrcexport OPENAI_API_KEY=sk-...Tip: put this in your shell profile (
~/.bashrcor~/.zshrc) for persistence.
From any Git repo:
# Generate message from STAGED changes (default)
commitmsg
# Write the message to /tmp/commitmsg.txt and run a dry-run commit, then ask to approve
commitmsg --dry-runThis prints the commit message in blue to STDOUT, and also saves it to:
/tmp/commitmsg.txt
If you approve the dry run, it will commit for real.
git add -A
commitmsg --dry-run
# Review output, press 'y' to approve the real commitcommitmsg --headcommitmsg --stream
commitmsg --stream --dry-run# Different model
commitmsg --model gpt-4o-mini
# Ask for more verbose thinking/output
commitmsg --verbosity high --effort high
# Ask OpenAI to store the interaction (if supported/configured)
commitmsg --store# Force colors on (or off)
commitmsg --color always
commitmsg --color never
# Disable spinners (useful for CI)
commitmsg --no-progresscommitmsg --strictcommitmsg --repo /path/to/repo- Subject:
<type>(<optional scope>): <short subject>(≤ 72 chars, no period) - Blank line
- Bullets: 3–6 concise, imperative lines
- Optional
BREAKING CHANGE:line - The tool post-filters model output to keep only the above.
Example:
refactor(core): enrich workflow logs with structured fields
- add span builder with contextual fields
- include user_id, request_id, phase, run_id in log macros
- await terminal email send; warn on failure
- seed phase shard aggregation for runner phases
- refine SQS routing schema handling
OPENAI_API_KEY— required. Your OpenAI API key.- (Optional) Standard proxy variables (
HTTP_PROXY,HTTPS_PROXY) are respected byreqwest.
commitmsg [OPTIONS]
Options:
-r, --repo <PATH> Path to repo (default: .)
--head Use last commit (HEAD) instead of staged changes
--model <NAME> OpenAI model (default: gpt-5)
--dry-run Run `git commit --dry-run` and ask to approve
--no-progress Disable progress spinners
--no-prompt Don’t ask to approve (useful with --dry-run in CI)
--strict Extra strict filtering (header + bullets only)
--color <WHEN> Color: auto|always|never (default: auto)
--verbosity <LEVEL> low|medium|high (default: low)
--effort <LEVEL> minimal|medium|high (default: minimal)
--store Request the API to store the interaction
--stream Stream tokens live (default: off)
-h, --help Print help
-V, --version Print version
-
Staged vs HEAD: By default, the tool uses staged changes (
git diff --cached). Use--headto summarize the last commit instead. -
Message location: The final message is always written to
/tmp/commitmsg.txtso you can reuse it:git commit -F /tmp/commitmsg.txt
-
CI usage: Disable colors/spinners and don’t prompt:
commitmsg --no-progress --color never --no-prompt
-
Shell piping: The commit message is printed to STDOUT; progress and prompts go to STDERR. Piping
commitmsg | pbcopywill copy the message only.
-
“
OPENAI_API_KEY not set” → export it in your shell:export OPENAI_API_KEY=sk-... -
“
not a git repository” → run inside a repo or use--repo /path/to/repo. -
Message seems too short → add
--verbosity mediumor--verbosity high. -
Model adds fluff → use
--strictto clamp to header + bullets. -
Streaming shows weird prefaces → prefer non-stream mode (default), or keep
--stricton.
MIT — do whatever you want, no warranty.