# smart-commit-rs
Minimal CLI tool that generates git commit messages via LLMs.
Fast, lightweight, cross-platform. No runtime dependencies, just a single binary.
(Formerly `auto-commit-rs`)
## ⚠️ Disclaimer: AI Generation and Code Quality
Please note that the majority of the code in this repository was generated by agentic AI. To ensure the quality and stability of the project, the following workflows are strictly enforced:
- Human Oversight: An AI agent does not commit code blindly. Every pull request, architecture decision, and code block generated by the AI is carefully reviewed and refined by a human developer.
- Unit Testing: The codebase is supported by comprehensive unit tests. We rely on standard CI/CD practices and test coverage to verify that the AI-generated logic performs exactly as expected.
- Use at Your Own Risk: While we strive for high code quality through testing and review, this software is provided "as is," without warranty of any kind.
## Why Rust?
Tools like [opencommit](https://github.com/di-sukharev/opencommit) do the same thing but require Node.js and weigh in at **~100MB** of `node_modules`. cgen is a single **~2MB** static binary. No runtimes, no interpreters, no package managers, download and run at lightning speed.
| Install size | ~2 MB | ~100 MB |
| Runtime deps | None | Node.js |
| Startup time | Instant | ~300ms (Node cold start) |
| Generation time | ~800ms | ~4s |
| Distribution | Single binary | npm install |
## Install
### Linux / macOS (curl)
```sh
This detects your OS and architecture, downloads the latest release binary to `/usr/local/bin`, and makes it executable. Set `INSTALL_DIR` to change the target:
```sh
INSTALL_DIR=~/.local/bin curl -fsSL https://raw.githubusercontent.com/gtkacz/smart-commit-rs/main/scripts/install.sh | bash
```
### Windows (PowerShell)
```powershell
This downloads the latest release to `%LOCALAPPDATA%\cgen\` and adds it to your user PATH.
### Cargo
From [crates.io](https://crates.io/crates/auto-commit-rs):
```sh
cargo install auto-commit-rs
```
From git:
```sh
cargo install --git https://github.com/gtkacz/smart-commit-rs
```
### Manual Download
Grab a binary from the [Releases](https://github.com/gtkacz/smart-commit-rs/releases) page and place it somewhere in your PATH.
Available binaries:
- `cgen-linux-amd64`, Linux x86_64
- `cgen-macos-amd64`, macOS Intel
- `cgen-macos-arm64`, macOS Apple Silicon
- `cgen-windows-amd64.exe`, Windows x86_64
## Quick Start
```sh
# 1. Set your API key (one-time)
cgen config
# or: export ACR_API_KEY=your-key-here
# 2. Stage files and generate commit
git add .
cgen
```
## Usage
```
cgen # Generate commit message and commit
cgen --dry-run # Generate and show message without committing
cgen --verbose # Print final system prompt used for LLM call (diff omitted)
cgen --tag # Create next semantic version tag after commit
cgen --no-verify # Forward flags to git commit
cgen alter <hash> # Regenerate message from that commit's diff and rewrite it
cgen alter <old> <new> # Use old..new net diff, rewrite <new> message
cgen undo # Undo latest commit with safety prompts (soft reset)
cgen update # Update cgen to the latest version
cgen config # Interactive config editor (auto-detects scope)
cgen prompt # Print the LLM system prompt without running anything
cgen history # Browse AI-generated commits for the current repo
cgen preset # Manage LLM presets (same UI as config menu entry)
cgen fallback # Configure fallback order (same UI as config menu entry)
```
Any arguments passed to `cgen` (without a subcommand) are forwarded directly to `git commit`.
## Configuration
All settings use the `ACR_` prefix. Layered resolution: defaults → global TOML → local `.env` → env vars.
| `ACR_PROVIDER` | `groq` | LLM provider (`groq`, `openai`, `anthropic`, `gemini`, `grok`, `deepseek`, `openrouter`, `mistral`, `together`, `fireworks`, `perplexity`, or custom) |
| `ACR_MODEL` | `llama-3.3-70b-versatile` | Model name |
| `ACR_API_KEY` |, | API key (required) |
| `ACR_API_URL` | auto | API endpoint (auto-resolved from provider) |
| `ACR_API_HEADERS` | auto | Custom headers (`Key: Value, Key2: Value2`) |
| `ACR_LOCALE` | `en` | Commit message language |
| `ACR_ONE_LINER` | `1` | Single-line commits (`1`/`0`) |
| `ACR_COMMIT_TEMPLATE` | `$msg` | Template, `$msg` is replaced with LLM output |
| `ACR_LLM_SYSTEM_PROMPT` | (built-in) | Base system prompt |
| `ACR_USE_GITMOJI` | `0` | Enable gitmoji (`1`/`0`) |
| `ACR_GITMOJI_FORMAT` | `unicode` | Gitmoji style (`unicode`/`shortcode`) |
| `ACR_REVIEW_COMMIT` | `1` | Review message before committing (`1`/`0`) |
| `ACR_POST_COMMIT_PUSH` | `ask` | Post-commit push behavior (`never`/`ask`/`always`) |
| `ACR_SUPPRESS_TOOL_OUTPUT` | `0` | Suppress git subprocess output (`1`/`0`) |
| `ACR_WARN_STAGED_FILES_ENABLED` | `1` | Warn when staged file count exceeds threshold (`1`/`0`) |
| `ACR_WARN_STAGED_FILES_THRESHOLD` | `20` | Staged files warning threshold (warn when count is greater) |
| `ACR_CONFIRM_NEW_VERSION` | `1` | Ask before creating the computed `--tag` version (`1`/`0`) |
| `ACR_AUTO_UPDATE` |, | Enable automatic updates (`1`/`0`); prompts on first run if unset |
| `ACR_FALLBACK_ENABLED` | `1` | Try fallback presets when primary LLM fails (`1`/`0`) |
| `ACR_TRACK_GENERATED_COMMITS` | `1` | Track AI-generated commits per repository (`1`/`0`) |
| `ACR_DIFF_EXCLUDE_GLOBS` | (see below) | Comma-separated glob patterns for files to exclude from LLM analysis |
### Diff Exclusion Patterns
`ACR_DIFF_EXCLUDE_GLOBS` filters files from the diff sent to the LLM while still committing them. This reduces noise and token usage for binary, generated, or data files. Default patterns:
```
*.json, *.xml, *.csv, *.pdf, *.lock, *.svg, *.png, *.jpg, *.jpeg, *.gif, *.ico, *.woff, *.woff2, *.ttf, *.eot, *.min.js, *.min.css
```
Override with a comma-separated list:
```sh
export ACR_DIFF_EXCLUDE_GLOBS="*.lock,*.svg,package-lock.json"
```
Note: `ACR_AUTO_UPDATE` is a global-only setting and is not written to local `.env` files.
### Config Locations
- **Global**: `~/.config/cgen/config.toml` (Linux), `~/Library/Application Support/cgen/config.toml` (macOS), `%APPDATA%\cgen\config.toml` (Windows)
- **Local**: `.env` in git repo root
### Variable Interpolation
`ACR_API_URL` and `ACR_API_HEADERS` support `$VARIABLE` interpolation from environment variables:
```sh
ACR_API_URL=https://api.example.com/v1/$ACR_MODEL/chat
ACR_API_HEADERS=Authorization: Bearer $ACR_API_KEY, X-Custom: $MY_HEADER
```
### Safety and Workflow Controls
- `cgen` now prints staged file count and names before generating a commit message.
- If staged files exceed `ACR_WARN_STAGED_FILES_THRESHOLD` and warnings are enabled, cgen asks for confirmation before continuing.
- `cgen --dry-run` generates and prints the final commit message but does not create a commit.
- `cgen --verbose` prints the final system prompt sent to the LLM and never prints diff payload.
- `cgen prompt` prints the full LLM system prompt (based on current config) without running any LLM call or git operations.
- `cgen config` auto-detects the context: inside a git repo it asks whether to edit local or global settings; outside a repo it opens the global config directly.
- The config view includes additional features:
- **Show descriptions [?]**: toggle to display help text for each setting
- **Search settings [/]**: find settings by name (auto-expands matching groups)
- Groups and subgroups are color-coded for easier navigation
- `cgen alter --dry-run` generates and prints the rewritten message but does not rewrite history.
- `cgen --tag` creates a semantic version tag after a successful commit:
- no existing tag -> `0.1.0`
- latest semver tag `x.y.z` -> `x.(y+1).0`
- latest tag not in semantic versioning -> error
- If `ACR_CONFIRM_NEW_VERSION=1`, cgen asks before creating the computed tag; if `0`, it creates it directly.
- `cgen alter <old> <new>` uses the `old..new` net diff as LLM input and rewrites only the `<new>` commit message.
- If `cgen alter` targets an already-pushed commit, cgen requires explicit confirmation before rewriting.
- After a real commit, push behavior follows `ACR_POST_COMMIT_PUSH`:
- `never`: never push
- `ask`: prompt whether to push (default)
- `always`: push automatically
- For rewritten pushed history, cgen does not auto-force-push; use manual `git push --force-with-lease` if needed.
- `cgen undo` only undoes the latest commit (`git reset --soft HEAD~1`), never pushes, and warns before undoing pushed commits.
### Updating
- `cgen update` checks for a newer version on GitHub and runs the appropriate installer:
- If `cargo` is available: `cargo install auto-commit-rs`
- Otherwise on Linux/macOS: re-runs the curl install script
- Otherwise on Windows: re-runs the PowerShell install script
- On every run, cgen checks the latest GitHub release tag against the current version.
- The first time cgen runs, it asks whether to enable automatic updates and saves the preference to the global config.
- If `ACR_AUTO_UPDATE=1`, cgen automatically updates when a newer version is found.
- If `ACR_AUTO_UPDATE=0` (or unset after the prompt), a warning is shown at the end of the output with the available version.
### LLM Presets
Presets let you save and reuse LLM provider configurations. Manage them from the `cgen config` interactive menu:
- **Save current as preset**: saves the current provider/model/key/url/headers as a named preset
- **Load a preset**: applies a saved preset to the current config session
- **Manage presets**: create, rename, duplicate, delete, export, and import presets
- **Export/Import**: export presets as TOML (optionally redacting API keys) for sharing or backup
Presets are stored in `{config_dir}/cgen/presets.toml` alongside the global config. Deduplication uses `(provider, model, api_key, api_url)` as the key.
### Fallback Order
When `ACR_FALLBACK_ENABLED=1` (default) and the primary LLM returns an HTTP error (4xx/5xx), cgen automatically tries fallback presets in the configured order:
- Configure fallback order from the `cgen config` menu under "Configure fallback order..."
- Presets matching the current config are skipped
- Transport/network errors fail immediately (no fallback)
- A summary of all failures is shown if every provider fails
### Commit History
When `ACR_TRACK_GENERATED_COMMITS=1` (default), cgen records each AI-generated commit hash and message preview in a per-repository cache.
- `cgen history` inside a git repo shows that repo's tracked commits
- `cgen history` outside a git repo lists all tracked repos, then shows commits for the selected one
- Selecting a commit runs `git show` on it
- Cache is stored in `{config_dir}/cgen/cache/`
## Providers
Built-in providers: **Groq** (default), **OpenAI**, **Anthropic**, **Gemini**, **Grok**, **DeepSeek**, **OpenRouter**, **Mistral**, **Together**, **Fireworks**, **Perplexity**.
| groq | llama-3.3-70b-versatile |
| openai | gpt-4o-mini |
| anthropic | claude-sonnet-4-20250514 |
| gemini | gemini-2.0-flash |
| grok | grok-3 |
| deepseek | deepseek-chat |
| openrouter | openai/gpt-4o-mini |
| mistral | mistral-small-latest |
| together | meta-llama/Llama-3.3-70B-Instruct-Turbo |
| fireworks | accounts/fireworks/models/llama-v3p3-70b-instruct |
| perplexity | sonar |
For custom providers, set `ACR_PROVIDER` to any name and provide `ACR_API_URL`. Custom providers default to OpenAI-compatible request format.
```sh
export ACR_PROVIDER=ollama
export ACR_API_URL=http://localhost:11434/v1/chat/completions
export ACR_MODEL=llama3
```
## Testing and Coverage
```sh
# Run all tests
cargo test --locked
# Enforce core logic coverage (matches CI gate)
cargo llvm-cov --locked --lib --tests \
--fail-under-lines 95
```
## Contributing
Contributions are welcome! Whether it's a new provider (often just 5 lines), a bug fix, or a documentation improvement, every bit helps.
See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide, including how to set up the development environment and how to add a new default provider step-by-step.
## License
[MIT](LICENSE)