Commiti
AI-powered commit message and pull request description generator for Git repositories, using Google AI models.
What It Does
Commiti helps you:
- Generate conventional commit messages from staged changes.
- Generate structured pull request descriptions from branch diffs.
- Review and optionally edit generated commit messages before writing to Git history.
- Open a prefilled PR/MR page in your browser for GitHub, GitLab, or GitBucket (no provider API token required).
- Preserve semantic diff quality on large changes using file-aware clipping that keeps file headers and hunk markers.
Requirements
- Ruby 3.2+
- Git
- Google AI API key
- A Git repository as your working directory
Install Dependencies (from source)
bundle install
CLI Usage
bundle exec ruby -Ilib bin/commiti [options]
Or after gem installation:
commiti [options]
Configuration
Commiti uses environment variables for secrets and a checked-in project config file for text-generation styling.
Set variables in your shell, CI secret manager, or local .env file (in your project):
GOOGLE_API_KEY=your_google_ai_key
# Optional: provider API tokens for API-first PR/MR creation
# COMMITI_GITHUB_TOKEN=your_github_token
# COMMITI_GITLAB_TOKEN=your_gitlab_token
# COMMITI_GITBUCKET_TOKEN=your_gitbucket_token
# Optional overrides:
# COMMITI_MODEL=gemma-4-31b-it
# COMMITI_CANDIDATES=1
# COMMITI_BASE_BRANCH=main
# COMMITI_NO_COPY=false
# COMMITI_AUTO_SPLIT=false
# Optional per-project prompt styling (safe YAML, no code execution):
# COMMITI_CONFIG=.commiti.yml
GEMINI_API_KEY is also accepted as an alias for GOOGLE_API_KEY.
You can copy .env.example as a starting point.
For project-specific wording and structure, add a .commiti.yml file at the repo root:
text_generation:
commit:
subject_case: uppercase # uppercase, lowercase, or preserve
pr:
sections:
- name: Overview
guidance: Summarize the change in one paragraph.
- name: Validation
guidance: Describe the checks or tests that were run.
The file is parsed with safe YAML loading, and Commiti only accepts declarative styling settings from it.
Your API key is sent directly from your local process to Google's API.
Commiti does not store it and does not proxy requests through any Commiti server.
Never commit .env to git.
Options
--type TYPEwhereTYPEiscommitorpr(default:commit)--base BRANCHbase branch for PR diff (default:main)--no-copyprint output only, skip clipboard copy--candidates NgenerateNoutput candidates (1-5, default:1)--auto-splitauto-group staged changes into multiple connected commits (commit flow only)-h,--helpshow help
Commit Flow (--type commit)
By default, Commiti creates a single commit from staged changes.
Use --auto-split to let Commiti group connected file changes into multiple atomic commits.
- Shows
git status --short. - Asks for confirmation before staging (
git add -A). - Ensures there are staged changes.
- Reads staged diff and generates commit message candidate(s).
- If the AI draft misses a conventional commit prefix, Commiti auto-normalizes it to a valid conventional subject.
- If
--candidatesis greater than1, shows numbered candidates and asks you to select one. - Shows selected message and asks:
Commit with this message? [y/e/N]y: commit nowe: open editor, then validate and re-confirmN: skip commit
- Writes commit with
git commit --file <tempfile>.
Commit Message Validation
- First line must use a conventional commit prefix (e.g.
feat:,fix:). - First line must be 100 characters or fewer.
Why --file instead of -m
Multi-line messages and special characters are safer with git commit --file, avoiding shell quoting edge cases.
Editor Selection
Commit edit mode uses:
VISUALEDITOR- Fallback:
notepadon Windows,vion non-Windows
PR Flow (--type pr)
- Reads branch diff:
git diff <base>...HEAD. - Generates PR description with these sections:
## Summary## Motivation## Changes Made## Testing Notes
- Attempts to create and open PR/MR:
- API-first path (when token is configured):
- GitHub/GitBucket: creates PR via provider API and opens the created PR URL.
- GitLab: creates MR via provider API and opens the created MR URL.
- Fallback path (when no token, provider unsupported, or API call fails):
- Opens browser with prefilled PR/MR form using query parameters.
- If the URL would exceed safe browser/provider limits (~1800 characters), Commiti keeps the title and intelligently truncates the description to the longest text that still fits.
- API-first path (when token is configured):
- Asks before opening browser.
Commiti can create PRs/MRs via provider APIs when tokens are configured, and always opens the resulting page in your browser.
Provider API Logic
When you set a provider token in your configuration, Commiti uses an API-first strategy:
Supported Providers:
- GitHub (github.com and GitHub Enterprise): Uses GitHub REST API v3
- GitLab (gitlab.com and self-hosted): Uses GitLab API v4
- GitBucket: Uses GitHub-compatible API
Token Configuration:
COMMITI_GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
COMMITI_GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
COMMITI_GITBUCKET_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API Request Flow:
- Parses the Git remote URL to extract provider, host, namespace, and repository.
- Constructs provider-specific API endpoint and authentication headers.
- Sends HTTP POST request with generated PR title and description.
- On success (HTTP 2xx): Returns the created PR/MR URL directly.
- On failure: Falls back to browser prefill with a user-friendly error message explaining why.
Error Handling:
- Missing token: Falls back to browser prefill. (Info message)
- Unsupported provider: Falls back to browser prefill. (Warning message)
- API error: Falls back to browser prefill with error details. (Warning message)
- Redirect handling: Automatically follows HTTP redirects (301, 302, 307, 308) but aborts if redirected to a different host.
- Network errors: Caught and reported with fallback to browser prefill.
Advantages of API-First:
- Creates PR/MR immediately without manual form interaction.
- Preserves full description text (no URL length constraints).
- Seamlessly opens the created PR/MR for immediate review and collaboration.
- Gracefully degrades to browser prefill if API is unavailable.
Diff Context Protocol
When a diff exceeds internal size limits, Commiti clips and summarizes using file-aware rules:
- Keeps full
diff --gitfile headers where possible. - Preserves
@@ ... @@hunk headers before clipping hunk bodies. - Includes as many complete files/hunks as fit in the limit, then appends a clipping notice.
- Summarizes large chunks asynchronously and in batches to reduce total LLM round trips.
- Falls back to deterministic file-level summaries if model summarization times out.
This improves semantic quality for AI generation compared with naive truncation.
Examples
Generate commit message and commit interactively:
bundle exec ruby -Ilib bin/commiti --type commit
Generate multiple commit message candidates and pick one:
bundle exec ruby -Ilib bin/commiti --type commit --candidates 3
Generate PR description against develop:
bundle exec ruby -Ilib bin/commiti --type pr --base develop
Print only, do not copy to clipboard:
bundle exec ruby -Ilib bin/commiti --type pr --no-copy
Implementation Overview
Main entrypoint and flow orchestration:
bin/commiti: CLI parsing and flow dispatchlib/flows/base_flow.rb: shared generation pipeline and quality checkslib/flows/commit_flow.rb: commit-specific staging/edit/commit interactionslib/flows/pr_flow.rb: PR-specific URL generation/open flow
Core services:
lib/services/git_reader.rblib/services/git/git_reader.rb: Reads staged diff and branch diff, applies file-aware clipping, provides recent commits helper.lib/services/git/git_writer.rb: Reads status/staged state, stages (git add -A), commits with message file (git commit --file), reads branch and origin remote.lib/services/git/diff_parser.rb: Parses diff blocks and derives change metadata.lib/services/git/pr/pr_opener.rb: Parses GitHub/GitLab/GitBucket remotes, builds provider-specific PR/MR URL, opens browser cross-platform.
lib/services/google_client.rb: Sends generation requests to Google Generative Language API.lib/services/diff_summarization/diff_summarizer.rb: Orchestrates large-diff summarization and summary combine.lib/services/diff_summarization/batch_runner.rb: Runs asynchronous, batched per-file summarization jobs.lib/services/diff_summarization/fallback_builder.rb: Builds deterministic summaries when model summarization fails or times out.
lib/services/helpers/config_loader.rb: Loads environment config plus secure project-level text-generation styling.lib/services/helpers/prompt_builder.rb: Builds strict system/user prompts for commit and PR modes.lib/services/helpers/interactive_prompt.rb: Handles confirmation prompts, candidate selection, editor loop, and commit message validation.lib/services/helpers/clipboard.rb: Provides cross-platform clipboard support.lib/services/helpers/spinner.rb: Displays a spinner for long-running operations.
lib/services/message_generator.rb: Generates commit and PR messages with quality checks.lib/services/message_presenter.rb: Presents generated messages to the user.lib/services/flow_context_builder.rb: Builds the context for different Commiti flows.lib/services/git/commit/commit_staging.rb: Handles staging changes for a commit.lib/services/git/commit/commit_execution.rb: Executes the git commit command.
Service loading:
lib/commiti.rbrequires all service modules.
Error Handling
The CLI reports user-friendly errors for common cases such as:
- No changes/staged changes
- Invalid or missing Git data
- Google AI API connectivity/authentication failures
- Summarization timeouts on large diffs (automatically falls back to a deterministic summary and continues)
- Browser open failures
Notes
- The default model is
gemma-4-31b-itinGoogleClient. - PR browser URL body payloads are URL-encoded with
URI.encode_www_form. - You can tune summarization worker concurrency with
DIFF_SUMMARY_WORKERS.