llm-git
Git commit message generator using Claude AI (or other LLMs) via OpenAI-compatible API. Generates conventional commit messages with concise summaries (≤72 chars) and structured detail points from git diffs.
Two-phase generation:
- Analysis phase: Extract 0-6 detail points from diff using Sonnet/Opus
- Summary phase: Generate commit summary from details using Haiku
Installation
Prerequisites
- Rust (latest stable): Install from rustup.rs
- Git: Required for repository operations
- API Access: One of the following:
- Anthropic API key (recommended)
- OpenAI API key
- OpenRouter API key
- Local LiteLLM proxy (for development)
From Source
From crates.io
Once published:
Quick Start
Configure API Access
Option A: LiteLLM (Recommended for local development)
# Start LiteLLM proxy (handles API keys and routing)
# llm-git uses localhost:4000 by default
Option B: Direct API Access
# Set API URL and key via environment variables
Option C: OpenRouter
Option D: Configuration File
# Create ~/.config/llm-git/config.toml (see Configuration section)
# Edit config.toml with your preferences
Usage
# Stage your changes
# Generate and commit
Commands
Basic Usage:
Compose Mode (Multi-commit generation):
Rewrite Mode (History rewrite to conventional commits):
Environment Variables
All configuration options can be overridden via environment variables:
LLM_GIT_API_URL- API endpoint URL (default:http://localhost:4000)LLM_GIT_API_KEY- API authentication key (default: none)LLM_GIT_CONFIG- Custom config file path (default:~/.config/llm-git/config.toml)LLM_GIT_VERBOSE- Enable verbose output with JSON structure
Examples:
# Use OpenAI instead of Claude
# Use custom config location
# Enable verbose debugging
Testing
Architecture
Modular library structure:
src/lib.rs- Public API exportssrc/main.rs- CLI entry pointsrc/analysis.rs- Scope candidate extractionsrc/api/- OpenRouter/LiteLLM integration with retry logicsrc/config.rs- Configuration and prompt templatessrc/diff.rs- Smart diff truncation with priority scoringsrc/error.rs- Error typessrc/git.rs- Git command wrapperssrc/normalization.rs- Unicode normalization, formattingsrc/types.rs- Type-safe commit types, scopes, summariessrc/validation.rs- Commit message validation
Core workflow:
get_git_diff()+get_git_stat()- Extract staged/unstaged/commit changessmart_truncate_diff()- Priority-based diff truncation when >100KB:- Parse into
FileDiffstructs with priority scoring - Source files (rs/py/js) > config > tests > binaries > lock files
- Excluded files:
Cargo.lock,package-lock.json, etc. (seeEXCLUDED_FILES) - Preserve headers for all files, truncate content proportionally
- Parse into
generate_conventional_analysis()- Call Sonnet/Opus withCONVENTIONAL_ANALYSIS_PROMPTusing function callinggenerate_summary_from_analysis()- Call Haiku withSUMMARY_PROMPT_TEMPLATE+ detail pointspost_process_commit_message()- Enforce length limits, punctuation, capitalizationvalidate_commit_message()- Check past-tense verbs, length, punctuation
Prompts:
CONVENTIONAL_ANALYSIS_PROMPT- Extracts 0-6 past-tense detail statements from diffSUMMARY_PROMPT_TEMPLATE- Creates ≤72 char summary from details + stat- Both enforce past-tense verbs:
added,fixed,updated,refactored, etc.
Smart truncation strategy (src/diff.rs):
- Shows ALL file headers even under length pressure
- Distributes remaining space proportionally by priority
- Keeps diff context (first 15 + last 10 lines per file)
- Annotates omitted files
Implementation Notes
Dependencies:
clap- CLI parsing with derive macrosreqwest(blocking) - OpenRouter API via LiteLLM localhost:4000serde+serde_json- Function calling schema + response parsingarboard- Clipboard support for--copyanyhow+thiserror- Error handling
API integration:
- Uses OpenRouter's function calling API with structured output
- Two tools:
create_conventional_analysis(detail extraction),create_commit_summary(summary creation) - Supports trailing text arguments as user context to analysis phase
- Fallback to
fallback_summary()if model calls fail - Retry logic with exponential backoff for transient failures
Validation rules:
- Summary: ≤72 chars (guideline), ≤96 (soft limit), ≤128 (hard limit), past-tense verb, no trailing period
- Body: Past-tense verbs preferred, ends with periods
- Warns on present-tense usage but doesn't block
Models:
- Default: Sonnet 4.5 (
claude-sonnet-4.5) - Optional: Opus 4.1 (
claude-opus-4.1) via--opus - Summary creation: Haiku 4.5 (
claude-haiku-4-5-20251001) hardcoded
Rewrite Mode Details
Rewrite mode converts entire git histories to conventional commits format:
Workflow:
- Extracts commit list via
git rev-list --reverse - For each commit: analyzes diff and generates conventional message
- Parallel API calls for faster processing
- Rebuilds history with
git commit-tree:- Preserves trees, authors, dates
- Updates messages only
- Maintains parent relationships
- Updates branch ref to new head
Safety:
- Auto-creates timestamped backup branch
--rewrite-preview N/--rewrite-dry-runmodes- Checks working tree is clean
- Preserves all commit metadata except message
Cost: ~$0.001-0.005/commit depending on model and diff size
Configuration
Create ~/.config/llm-git/config.toml to customize behavior:
# API Configuration
= "http://localhost:4000" # Override with LLM_GIT_API_URL
= "your-api-key" # Optional, override with LLM_GIT_API_KEY
# HTTP Timeouts
= 120 # Request timeout (default: 120s)
= 30 # Connection timeout (default: 30s)
# Models (supports any OpenAI-compatible API)
= "claude-sonnet-4.5" # Model for analysis phase
= "claude-haiku-4-5" # Model for summary phase
# Commit Message Limits
= 72 # Target length (conventional commits)
= 96 # Triggers retry if exceeded
= 128 # Absolute maximum
# Retry Configuration
= 3 # API retry attempts
= 1000 # Initial backoff delay
# Diff Processing
= 100000 # Max diff size before truncation
= 0.50 # Threshold for omitting scope (50%)
# Compose Mode
= 5 # Max rounds for multi-commit generation
# Model Temperature
= 0.2 # Low for consistency (0.0-1.0)
# File Exclusions
= [ # Files to exclude from diff
"Cargo.lock",
"package-lock.json",
"yarn.lock",
# ... add more
]
= [ # Low-priority file extensions
".lock", ".toml", ".yaml", ".json", ".md",
# ... add more
]
# Prompt Variants (advanced)
= "default" # Prompt template variant
= "default" # Prompt template variant
= true # Exclude old message in rewrite mode
Configuration Examples
LiteLLM (localhost):
= "http://localhost:4000"
# No api_key needed - LiteLLM handles authentication
= "claude-sonnet-4.5"
= "claude-haiku-4-5"
Anthropic Direct:
= "https://api.anthropic.com/v1"
= "sk-ant-..." # Or use LLM_GIT_API_KEY env var
= "claude-sonnet-4.5-20250514"
= "claude-haiku-4-5-20250514"
OpenRouter:
= "https://openrouter.ai/api/v1"
= "sk-or-..."
= "anthropic/claude-sonnet-4.5"
= "anthropic/claude-haiku-4-5"
OpenAI:
= "https://api.openai.com/v1"
= "sk-..."
= "gpt-4o"
= "gpt-4o-mini"
= 0.3 # OpenAI models may benefit from slightly higher temp
License
MIT