ai-mr-comment
A command-line tool written in Go that generates professional GitLab Merge Request (MR) or GitHub Pull Request (PR) comments based on git diffs using AI (OpenAI, Anthropic, Gemini, Ollama, or local CLI tools — Claude Code, Gemini CLI, or Codex).
Features
- Reads git diffs from current repo or from a file
- Auto-detects branch diff against
origin/mainororigin/masterwhen no flags are given - Staged-only diff (
--staged) for reviewing changes before committing - Exclude files from the diff by glob pattern (
--exclude) - Smart chunking (
--smart-chunk) for large diffs: summarizes each file, then synthesizes a final comment - Optional MR/PR title generation (
--title) alongside the comment, printed as a distinct section - Generate comments directly from a GitHub PR or GitLab MR URL (
--pr) — no local checkout needed - Supports public github.com, GitHub Enterprise, public gitlab.com, and self-hosted GitLab instances
- Supports OpenAI, Anthropic (Claude), Google Gemini, and Ollama APIs
- Local CLI providers — delegate auth to locally installed CLI tools, no API key management needed:
claude-cli— uses the localclaudebinary (Claude Code session), no API key requiredgemini-cli— uses the localgeminibinary (Google OAuth), no API key requiredcodex-cli— uses the localcodexbinary (quiet mode), requiresOPENAI_API_KEY
- Customizable API endpoints and models via
--modelflag or config - Multiple prompt styles —
default,conventional,technical,user-focused,emoji,sassy,monday,jira,commit,commit-emoji,commit-conventional,chaos,haiku,roast,intern,shakespeare,manager,yoda,excuse - Jira-aware template (
--template=jira) — extracts ticket key from branch name and places it first so Jira auto-links - Commit message generation (
--commit-msg) — outputs a single conventional-style line ready forgit commit -m quick-commitsubcommand — stages all changes, generates a conventional commit message (type and scope derived from the diff), commits, and pushes in one step- Gitmoji support (
--emojionquick-commit) — appends a type-matched emoji to the commit subject (✨ feat, 🐛 fix, ♻️ refactor, etc.) - Opt-out conventional commits (
--no-conventionalonquick-commit) — skips conventional format enforcement for free-form messages - Chaos mode (
--chaos) — chaotic/absurd conventional commit onquick-commit; unhinged-but-accurate MR/PR description on the root command - Haiku mode (
--haiku) — commit description as a 5-7-5 haiku onquick-commit; full MR/PR description in haiku form on the root command - Roast mode (
--roast) — passive-aggressive commit onquick-commit; sardonically judgmental MR/PR description on the root command - Fortune trailer (
--fortuneonquick-commit) — appends a dev-wisdom fortune-cookie quote as a commit body - Monday mode (
--mondayonquick-commit) — casual, low-energy “pre-coffee” commit message - Jira commit mode (
--jiraonquick-commit) — prefixes the commit message with the Jira ticket key extracted from the branch name - Emoji commit mode (
--emoji-commitonquick-commit) — appends a type-matched gitmoji to the commit description - Sassy mode (
--sassyonquick-commit) — sassy but technically accurate commit message - Technical mode (
--technicalonquick-commit) — maximum technical precision; references exact function/struct names from the diff - Intern mode (
--intern) — written by an overly enthusiastic junior developer who is SO excited about everything; works on both root cmd andquick-commit - Shakespeare mode (
--shakespeare) — Early Modern English, iambic cadence, dramatic flair; works on both root cmd andquick-commit - Manager mode (
--manager) — passive-aggressive corporate non-speak, “per our earlier discussion”; works on both root cmd andquick-commit - Yoda mode (
--yoda) — inverted syntax, object before subject, strong with this one the force is; works on both root cmd andquick-commit - Excuse mode (
--excuse) — technically accurate but every section has a built-in justification for why it had to be this way; works on both root cmd andquick-commit - CI/CD gate (
--exit-code) — exits with code 2 when the AI flags critical issues, enabling pipeline enforcement - Auto-post comments (
--post) — publishes the generated comment directly to the GitHub PR or GitLab MR via API - Update remote PR/MR metadata (
--update-title,--update-description) — writes the generated title and/or description back to GitHub or GitLab - Named config profiles (
--profile) — switch between providers/models/templates with a single flag; define profiles in~/.ai-mr-comment.tomlunder[profile.<name>] - Configuration file support (
~/.ai-mr-comment.toml) - Environment variable configuration
- Outputs to a file (
--output) or the system clipboard (--clipboard=title|description|commit-msg|all); when--outputis set, stdout is suppressed — output goes to the file only --outputwrites JSON when--format=jsonis set — ideal for saving structured review artifacts- Structured JSON output for scripting and CI (
--format json) - Verbose debug logging to stderr (
--verbose) — API timing, diff stats, config details - Live streaming output to the terminal — tokens appear as they are generated
- Bootstrap a config file with
init-config(never edit TOML by hand again) - All prompt templates stored as editable files in
internal/prompts/templates/— embedded at build time, overridable at~/.config/ai-mr-comment/templates/<name>.tmpl - Shell completions for bash, zsh, fish, and PowerShell (
completionsubcommand) - Shell aliases (
gen-aliases) — printsamcandamc-*convenience aliases ready to source into your shell profile - Changelog generation (
changelog) — produces a user-facing Keep a Changelog entry from a commit range, grouped by Added / Fixed / Breaking Changes etc. - Custom system prompt (
--system-prompt) — supply an ad-hoc prompt inline or from a file (@path), overriding the active template for a single run - Precise token counting for Gemini and heuristic estimation for others
- Estimated cost calculation in debug mode
- Native binary with no runtime dependencies
Installation
Prerequisites
- Git
- API key for your preferred provider (OpenAI, Anthropic, or Google Gemini) — not required when using
claude-cli,gemini-cli, orollama
macOS (Homebrew)
brew tap pbsladek/tap
brew install ai-mr-comment
Or install directly in one command:
brew install pbsladek/tap/ai-mr-comment
Upgrade later with:
brew upgrade ai-mr-comment
Other Platforms
Download the latest binary for your OS from the Releases page. Release archives are published for Linux, macOS, and Windows on both x86_64 and arm64.
For Linux/macOS script installation, download and inspect scripts/install.sh from the repository, then run it directly. The script verifies the downloaded archive against the release checksums.txt (and optionally the cosign signature) before installing.
Building from Source
Requires Go 1.26+.
# Clone the repository
git clone https://github.com/pbsladek/ai-mr-comment.git
cd ai-mr-comment
# Build
make build
# The binary will be available at ./dist/ai-mr-comment
# Build and run on current diff
make test-run
# Fetch latest tags first so --version shows the correct release tag
make fetch-tags build
Docker
No Go toolchain required. The image includes git so all diff and commit commands work. Published image: pwbsladek/ai-mr-comment on Docker Hub. Release images are published as multi-arch Linux manifests for amd64 and arm64. FIPS variant tag: pwbsladek/ai-mr-comment:<version>-fips.
If you build locally, log in to DHI first (base images are pulled from dhi.io):
docker login dhi.io
# Build the image
make docker-build
# Scan for fixable critical/high CVEs
make docker-scout
# Run against the current repo diff (mounts PWD, passes API keys from env)
make docker-run ARGS="--provider openai"
# Run quick-commit
make docker-quick-commit ARGS="--dry-run"
# Pull a specific version (replace v0.18.1 with the version you want)
docker pull pwbsladek/ai-mr-comment:v0.18.1
docker pull pwbsladek/ai-mr-comment:v0.18.1-fips
# Or use docker directly
docker run --rm -it \
-v "$(pwd):/repo" -w /repo \
-e OPENAI_API_KEY \
pwbsladek/ai-mr-comment:v0.18.1 --provider openai
Mounting your config file:
docker run --rm -it \
-v "$(pwd):/repo" -w /repo \
-v "$HOME/.ai-mr-comment.toml:/home/nonroot/.ai-mr-comment.toml:ro" \
-e OPENAI_API_KEY \
pwbsladek/ai-mr-comment:v0.18.1
Fetching a PR/MR by URL (no repo mount needed):
docker run --rm \
-e OPENAI_API_KEY \
-e GITHUB_TOKEN \
pwbsladek/ai-mr-comment:v0.18.1 --pr https://github.com/owner/repo/pull/42
Note:
--clipboardis not available inside a container. Use--outputor--format jsoninstead to capture the output.
Configuration File
The tool looks for .ai-mr-comment.toml in your home directory or the current directory.
Generating the config file
Run init-config to write a fully-commented template to ~/.ai-mr-comment.toml:
ai-mr-comment init-config
# Write to a custom path instead
ai-mr-comment init-config --output ./ai-mr-comment.toml
The command refuses to overwrite an existing file. Remove the old file first if you want to regenerate it.
# Choose which provider to use: "openai", "anthropic", "gemini", "ollama", "claude-cli", "gemini-cli", or "codex-cli"
provider = "anthropic"
# === Anthropic Settings ===
anthropic_api_key = "xxxx"
anthropic_model = "claude-sonnet-4-6"
anthropic_endpoint = "https://api.anthropic.com/"
# Other Anthropic models: claude-opus-4-7, claude-opus-4-6, claude-haiku-4-5-20251001
# === Claude CLI Settings ===
# No API key needed — auth is delegated to the local claude CLI process.
# Requires Claude Code to be installed (https://claude.ai/code).
# claude_cli_path = "" # auto-detected: ~/.claude/local/claude, then PATH
claude_cli_model = "claude-sonnet-4-6"
# === OpenAI Settings ===
openai_api_key = "xxxx"
openai_model = "gpt-5.5"
openai_endpoint = "https://api.openai.com/v1/"
# Other OpenAI models: gpt-5.5-pro, gpt-5.4, gpt-5.4-pro, gpt-5.4-mini, gpt-5.4-nano, gpt-5.3-codex
# === Gemini Settings ===
gemini_api_key = "xxxx"
gemini_model = "gemini-2.5-flash"
# Other Gemini models: gemini-3.1-pro-preview, gemini-3-flash-preview, gemini-3.1-flash-lite, gemini-2.5-pro, gemini-2.5-flash-lite
# === Gemini CLI Settings ===
# No API key needed — auth is delegated to the local gemini CLI process (Google OAuth).
# Requires the Gemini CLI to be installed (https://github.com/google-gemini/gemini-cli).
# gemini_cli_path = "" # auto-detected from PATH
gemini_cli_model = "gemini-2.5-flash"
# === Codex CLI Settings ===
# No API key needed — auth is delegated to the local codex CLI process.
# Requires the OpenAI Codex CLI to be installed (https://github.com/openai/codex).
# codex_cli_path = "" # auto-detected from PATH
# codex_cli_model = "" # uses codex default when empty
# === Ollama Settings ===
ollama_model = "llama3.2"
ollama_endpoint = "http://localhost:11434/api/generate"
# === GitHub / GitHub Enterprise ===
github_token = "xxxx" # or set GITHUB_TOKEN env var (required for private repos)
# github_base_url = "" # set for GitHub Enterprise, e.g. https://github.mycompany.com
# === GitLab / Self-Hosted GitLab ===
gitlab_token = "xxxx" # or set GITLAB_TOKEN env var (required for private projects)
# gitlab_base_url = "" # set for self-hosted GitLab, e.g. https://gitlab.mycompany.com
# === Template Settings ===
# Options: default, conventional, technical, user-focused, emoji, sassy, monday,
# jira, commit, commit-emoji, commit-conventional,
# chaos, haiku, roast, intern, shakespeare, manager, yoda, excuse
template = "default"
# === Named Profiles ===
# Switch with: ai-mr-comment --profile <name>
# A profile overrides any top-level setting for that invocation only.
[profile.fast]
provider = "openai"
openai_model = "gpt-5.4-nano"
template = "conventional"
[profile.openai]
provider = "openai"
openai_model = "gpt-5.5"
[profile.anthropic]
provider = "anthropic"
anthropic_model = "claude-opus-4-7"
template = "technical"
[profile.gemini]
provider = "gemini"
gemini_model = "gemini-2.5-flash"
[profile.claude-cli]
provider = "claude-cli"
claude_cli_model = "claude-sonnet-4-6"
[profile.gemini-cli]
provider = "gemini-cli"
gemini_cli_model = "gemini-2.5-flash"
[profile.codex-cli]
provider = "codex-cli"
[profile.local]
provider = "ollama"
ollama_model = "llama3.2"
Example Output
Text mode (--title):
── Title ────────────────────────────────
feat: Add user authentication system
── Description ──────────────────────────
## Summary
Adds a complete user authentication system using JWT tokens and bcrypt password hashing. Required to protect API endpoints and support user identity across sessions.
## Key Changes
- Added user model with bcrypt password hashing
- Implemented JWT authentication middleware
- Created login and registration API endpoints
- Added comprehensive unit tests for auth logic
## Why These Changes
Provides a secure foundation for user identity, allowing protected access to API resources.
JSON mode (--format json):
{
"title": "feat: Add user authentication system",
"description": "## Key Changes\n\n- Added user model...",
"comment": "## Key Changes\n\n- Added user model...",
"provider": "openai",
"model": "gpt-5.5"
}
description and comment carry the same value; comment is kept for backwards compatibility. When --exit-code is set, a "verdict": "PASS" or "verdict": "FAIL" field is also included.
Commit message mode (--commit-msg --format json):
{"commit_message":"feat(auth): add JWT refresh token support"}
Usage
# Generate comment for the full branch diff (auto-detects merge base with origin/main)
ai-mr-comment
# Generate comment for staged changes only
ai-mr-comment --staged
# Exclude generated or vendored files
ai-mr-comment --exclude "vendor/**" --exclude "*.sum"
# Use smart chunking for large diffs (summarizes per-file, then combines)
ai-mr-comment --smart-chunk
# Use a specific provider and template
ai-mr-comment --provider anthropic --template technical
# Override the model for a single run
ai-mr-comment --model gpt-5.5
# Generate comment for a specific commit range
ai-mr-comment --commit "HEAD~3..HEAD"
# Pipe a diff through stdin
git diff | ai-mr-comment --file=- --plain
gh pr diff 42 | ai-mr-comment --quiet
# Generate a comment from a GitHub PR URL (no local checkout needed)
ai-mr-comment --pr https://github.com/owner/repo/pull/42
# Generate a comment from a GitLab MR URL
ai-mr-comment --pr https://gitlab.com/group/project/-/merge_requests/5
# Generate a comment from a GitHub Enterprise or self-hosted GitLab URL
# (set github_base_url / gitlab_base_url in config or env)
GITHUB_BASE_URL=https://github.mycompany.com \
ai-mr-comment --pr https://github.mycompany.com/owner/repo/pull/42
GITLAB_BASE_URL=https://gitlab.mycompany.com \
ai-mr-comment --pr https://gitlab.mycompany.com/group/project/-/merge_requests/5
# Generate a title and comment together (shown as separate sections)
ai-mr-comment --title
# Output structured JSON for CI/scripting
# Always includes title, description, provider, and model fields
ai-mr-comment --format json
# Generate only a git commit message (conventional commits style)
ai-mr-comment --commit-msg --staged
# Generate a commit message as JSON
ai-mr-comment --commit-msg --format json | jq -r '.commit_message'
# Copy the description to clipboard
ai-mr-comment --clipboard=description
# Copy the title to clipboard
ai-mr-comment --title --clipboard=title
# Copy a commit message to clipboard
ai-mr-comment --commit-msg --clipboard=commit-msg
# Gate CI on AI review — exits 2 if critical issues are detected
ai-mr-comment --exit-code --pr https://github.com/owner/repo/pull/42
# Generate and immediately post the comment back to the PR/MR
ai-mr-comment --pr https://github.com/owner/repo/pull/42 --post
# Generate and update the actual PR/MR title and description
ai-mr-comment --pr https://github.com/owner/repo/pull/42 --update-title --update-description
# Save JSON review to a file (for artifact upload in CI)
ai-mr-comment --format json --output /tmp/review.json --pr https://github.com/owner/repo/pull/42
# Enable verbose debug logging to stderr (API timing, diff stats, config)
ai-mr-comment --verbose
# Show token and cost estimation without calling the API
ai-mr-comment --debug
# Print the exact prompt/request for agent debugging without calling the API
git diff | ai-mr-comment --file=- --print-prompt
git diff | ai-mr-comment --file=- --print-request | jq .
# Preview planned work without calling the provider or writing files
git diff | ai-mr-comment --dry-run --file=-
# Inspect changed files and diff stats without spending tokens
ai-mr-comment --changed-files
ai-mr-comment --summary-only --format=json | jq .
# Inspect resolved config, tokens, git state, and local CLI binaries
ai-mr-comment doctor
ai-mr-comment config-dump --format=json | jq .
# Apply a built-in preset
ai-mr-comment --preset ci --pr https://github.com/owner/repo/pull/42
ai-mr-comment --preset local-fast --file=-
ai-mr-comment --preset security
ai-mr-comment changelog --preset release-notes --commit="v1.2.0..HEAD"
# Override the system prompt for a single run (inline)
ai-mr-comment --system-prompt="Focus only on security vulnerabilities."
# Override the system prompt from a file
ai-mr-comment --system-prompt=@~/prompts/security-review.txt
# Chaos mode — unhinged but accurate MR/PR description
ai-mr-comment --chaos
# Haiku mode — entire description as 5-7-5 haikus
ai-mr-comment --haiku
# Roast mode — sardonically judgmental but correct
ai-mr-comment --roast
# Generate a user-facing changelog entry from the last 10 commits
ai-mr-comment changelog --commit="HEAD~10..HEAD"
# Generate a changelog entry for a release range, output as JSON
ai-mr-comment changelog --commit="v1.2.0..HEAD" --format=json
# Print shell aliases (amc, amc-qc, amc-cl, …) and add to profile
ai-mr-comment gen-aliases >> ~/.zshrc
# Or evaluate on every shell start to always stay up to date
# eval "$(ai-mr-comment gen-aliases)"
# Generate shell completion script
ai-mr-comment completion bash >> ~/.bash_completion
ai-mr-comment completion zsh > ~/.zsh/completions/_ai-mr-comment
# Bootstrap a config file (writes ~/.ai-mr-comment.toml)
ai-mr-comment init-config
# Use a named profile (provider/model/template preset)
ai-mr-comment --profile fast
ai-mr-comment --profile anthropic --title
Agent and Pipe Integration
ai-mr-comment can be used as a Unix-style filter:
git diff | ai-mr-comment --file=- --plain
git show HEAD | ai-mr-comment commit-message --file=-
gh pr diff 42 | ai-mr-comment review --quiet
git diff | ai-mr-comment verdict --file=-
For structured agent input, pass JSON on stdin:
printf '%s' '{
"title": "Add auth flow",
"description": "Implements token refresh",
"branch": "feat/AUTH-123-refresh",
"diff": "diff --git a/auth.go b/auth.go\n+..."
}' | ai-mr-comment review --input=json --quiet
Agent-oriented commands:
ai-mr-comment review --file=-
ai-mr-comment title --file=-
ai-mr-comment commit-message --file=-
ai-mr-comment verdict --file=-
ai-mr-comment estimate --file=-
Machine-friendly output modes:
ai-mr-comment --quiet
ai-mr-comment --plain
ai-mr-comment --stream=jsonl
ai-mr-comment --print-prompt
ai-mr-comment --print-request
ai-mr-comment --dry-run
ai-mr-comment --summary-only
Exit codes are stable for automation: 0 success/pass, 1 tool or runtime error, 2 AI verdict fail, 3 no diff/input, 4 invalid usage.
Options
--pr <URL>: GitHub PR or GitLab MR URL — fetches diff and metadata remotely, no local checkout needed. Works withgithub.com, GitHub Enterprise,gitlab.com, and self-hosted GitLab. Mutually exclusive with--staged,--commit, and--file.--commit <COMMIT>: Specific commit or range--staged: Diff staged changes only (git diff --cached); mutually exclusive with--commit--exclude <PATTERN>: Exclude files matching glob pattern (e.g.vendor/**,*.sum). Can be repeated.--smart-chunk: Split large diffs by file, summarize each, then synthesize a final comment--title: Generate a concise MR/PR title alongside the comment; printed as a distinct── Title ──section in text mode. When--format=jsonis used, title is always generated automatically (no need for--title). Mutually exclusive with--commit-msg.--commit-msg: Generate a single-line git commit message instead of a full MR/PR description. Output is clean text or{"commit_message":"..."}in JSON mode. Mutually exclusive with--title.--multi-line: Generate a multi-line commit message (subject + blank line + markdown body) when used with--commit-msgorquick-commit. GitHub and GitLab use this format to pre-fill the PR/MR title and description automatically.--exit-code: Exit with code 2 when the AI detects critical issues (bugs, security vulnerabilities, data loss risks). Mutually exclusive with--commit-msg.--post: Post the generated comment back to the GitHub PR or GitLab MR via API (requires--pr). Uses the same token as diff fetching.--update-title: Update the GitHub PR title or GitLab MR title with the generated title (requires--pr). Mutually exclusive with--commit-msg.--update-description: Update the GitHub PR body or GitLab MR description with the generated description (requires--pr). Mutually exclusive with--commit-msgand--title-only.--dry-run: Print the resolved plan and diff stats without calling the provider, writing output files, copying to clipboard, posting comments, or updating PR/MR metadata.--changed-files: Print changed file paths and exit without calling the provider.--summary-only: Print diff stats and changed files and exit without calling the provider.--file <FILE>: Read diff from file instead of git. Use--file=-to read from stdin.--output <FILE>: Write output to file instead of stdout — suppresses all terminal output. Writes JSON when--format=jsonis set; writes the commit message when--commit-msgis set.--clipboard <WHAT>: Copy to system clipboard —title,description(orcomment),commit-msg, orall(title + description separated by a blank line)--format <FORMAT>: Output format —text(default) orjson--input <FORMAT>: Input format —text(default) orjsonfor structured agent input (title,description,branch,diff)--quiet: Force strict JSON output on stdout for agents and scripts--plain,--no-decorate: Suppress text section headers and decorative separators--stream=jsonl: Emit JSON Lines events (start,token,done) instead of decorated text--print-prompt: Print the resolved system prompt and exit without calling the provider--print-request: Print the resolved provider request as JSON and exit without calling the provider--preset <NAME>: Apply built-in defaults:ci(JSON + exit-code + technical),local-fast(Ollama + plain),security(security-focused technical review), orrelease-notes(user-focused title/description).--provider <PROVIDER>: Provider (openai,anthropic,gemini,ollama,claude-cli,gemini-cli,codex-cli)--model <NAME>: Override the model for this run (e.g.gpt-5.5,claude-opus-4-7,gemini-3.1-pro-preview)-t, --template <NAME>: Template style —default,conventional,technical,user-focused,emoji,sassy,monday,jira,commit,commit-emoji,commit-conventional,chaos,haiku,roast,intern,shakespeare,manager,yoda,excuse(commit,commit-emoji, andcommit-conventionalrequire--commit-msg; style templates cannot be combined with--commit-msg)--system-prompt <TEXT|@FILE>: Override the system prompt for this run. Pass the prompt inline (--system-prompt="Focus on security") or read it from a file with an@prefix (--system-prompt=@review.txt). Mutually exclusive with--template.--chaos: Generate a chaotic, dramatically over-the-top MR/PR description (still technically accurate). Mutually exclusive with--template,--system-prompt,--commit-msg.--haiku: Generate the entire MR/PR description as a sequence of haikus (5-7-5). Mutually exclusive with--template,--system-prompt,--commit-msg.--roast: Generate a technically accurate but sardonically judgmental MR/PR description. Mutually exclusive with--template,--system-prompt,--commit-msg.--profile <NAME>: Activate a named config profile defined under[profile.<name>]in~/.ai-mr-comment.toml. Overrides top-level provider, model, template, and other settings for this run only.--debug: Show precise token usage and cost estimation without calling the generation API--verbose: Print detailed debug lines to stderr — config file path, diff stats, template source, streaming decision, and per-API-call timing and response size--version: Print version, commit SHA, and repository URL inkey=valueformat and exit-h, --help: Print help
Diagnostics
doctor and its alias config-dump inspect local readiness without making a live provider request:
ai-mr-comment doctor
ai-mr-comment doctor --provider openai
ai-mr-comment doctor --preset local-fast --format=json
Use check when you want a live provider ping.
Subcommands
quick-commit [flags]: Stage all changes, generate an AI commit message, commit, and push in one step. See Quick Commit below.publish [flags]: Generate and sync a PR/MR title, description, managed summary comment, labels, and reviewers in one step. See Publish below.changelog [flags]: Generate a user-facing changelog entry from a commit range or diff file. See Changelog below.gen-aliases [--shell bash|zsh] [--output FILE]: Printamcandamc-*shell aliases to stdout. See Shell Aliases below.models [--provider <NAME>]: List known model names for a provider.init-config [--output <PATH>]: Write a default config file to~/.ai-mr-comment.toml(or the given path). Refuses to overwrite an existing file.completion [bash|zsh|fish|powershell]: Print a shell completion script to stdout.
GitHub & GitLab Integration (--pr)
Point --pr at any GitHub pull request or GitLab merge request URL to generate a comment without needing the repository checked out locally.
# GitHub (public)
ai-mr-comment --pr https://github.com/owner/repo/pull/42
# GitLab (public)
ai-mr-comment --pr https://gitlab.com/group/project/-/merge_requests/5
Authentication
Public repos and projects work without a token (subject to API rate limits). For private repos set the token via environment variable or config file:
| Platform | Env var | Config key |
|---|---|---|
| GitHub / GitHub Enterprise | GITHUB_TOKEN | github_token |
| GitLab / Self-Hosted GitLab | GITLAB_TOKEN | gitlab_token |
Self-Hosted Instances
For GitHub Enterprise or self-hosted GitLab, pass the instance base URL. The SDKs automatically append the correct API path (/api/v3/ for GitHub, /api/v4/ for GitLab).
Environment variables:
# GitHub Enterprise
GITHUB_BASE_URL=https://github.mycompany.com \
ai-mr-comment --pr https://github.mycompany.com/owner/repo/pull/42
# Self-hosted GitLab
GITLAB_BASE_URL=https://gitlab.mycompany.com \
ai-mr-comment --pr https://gitlab.mycompany.com/group/project/-/merge_requests/5
Config file (.ai-mr-comment.toml):
github_base_url = "https://github.mycompany.com"
gitlab_base_url = "https://gitlab.mycompany.com"
Templates
Select a template with -t / --template. All templates receive the branch name as context (useful for ticket key extraction).
All built-in templates live in internal/prompts/templates/ in the repository and are embedded into the binary at build time. You can override any template by placing a file at ~/.config/ai-mr-comment/templates/<name>.tmpl.
| Name | Description |
|---|---|
default | Professional description with Summary, Key Changes, Why, Checklist, Notes |
conventional | Conventional Commits body with optional BREAKING CHANGE and Refs |
technical | Deep technical focus — Summary, Implementation Details, Rationale, Testing Strategy |
user-focused | Non-technical perspective — What’s New, Why Important, Impact |
emoji | Fun emoji-rich format with Summary section |
sassy | Dry-wit tone, technically accurate |
monday | Casual “pre-coffee” tone |
jira | Puts the Jira ticket key from the branch name first so Jira auto-links; includes Summary section |
commit | Single-line conventional commit message (requires --commit-msg) |
commit-emoji | Single-line gitmoji-style commit message (requires --commit-msg) |
commit-conventional | Full Conventional Commits message with optional body, BREAKING CHANGE footer, and Refs (requires --commit-msg) |
chaos | Chaotic, dramatically over-the-top description (still technically accurate) |
haiku | Entire description as a sequence of haikus |
roast | Sardonically judgmental, dry-wit tone |
intern | Overly enthusiastic junior-developer energy |
shakespeare | Shakespearean Early Modern English |
manager | Passive-aggressive corporate non-speak |
yoda | Inverted Yoda syntax |
excuse | Technically accurate with built-in excuses for every decision |
Jira Integration
The jira template extracts the ticket key from your branch name (e.g. feat/ABC-123-add-login → ABC-123) and places it at the very start of the description so Jira’s branch/commit linking picks it up automatically.
ai-mr-comment --template jira --staged
# Output starts with: "ABC-123 Add login endpoint\n\n## Key Changes..."
This works because the current branch name is automatically prepended to the diff context for all local git operations (not --file or --pr).
Custom System Prompt
Use --system-prompt to replace the active template prompt for a single run — no template file needed.
# Inline prompt
ai-mr-comment --system-prompt="Focus only on security vulnerabilities."
# Read from a file (@ prefix)
ai-mr-comment --system-prompt=@~/prompts/security-review.txt
# Works on the changelog subcommand too
ai-mr-comment changelog --commit="v1.2.0..HEAD" \
--system-prompt="List only breaking changes in one sentence each."
--system-prompt and --template are mutually exclusive — use one or the other per run.
When --exit-code is also set, the verdict preamble is still prepended on top of the custom prompt (same behaviour as with templates).
Commit Messages
Use --commit-msg to generate a single conventional-style commit message instead of a full PR description.
# Print the message (text mode)
ai-mr-comment --commit-msg --staged
# JSON output — single key, pipeline-friendly
ai-mr-comment --commit-msg --format json
# {"commit_message":"feat(auth): add JWT refresh token support"}
# Pipe directly into git commit
git commit -m "$(ai-mr-comment --commit-msg --staged)"
# Copy to clipboard
ai-mr-comment --commit-msg --staged --clipboard=commit-msg
# Gitmoji style
ai-mr-comment --commit-msg --template commit-emoji --staged
# Multi-line message: subject + blank line + markdown body
# GitHub/GitLab use this to pre-fill the PR/MR title and description
ai-mr-comment --commit-msg --multi-line --staged
# Use it with quick-commit too
ai-mr-comment quick-commit --multi-line
--commit-msg and --title are mutually exclusive. In JSON mode, the response contains only commit_message (no description or title fields).
Quick Commit
quick-commit is a one-command shortcut for the full stage → AI message → commit → push workflow.
# Full workflow
ai-mr-comment quick-commit
# Preview the generated message without touching git
ai-mr-comment quick-commit --dry-run
# Generate a long multi-section commit body
ai-mr-comment quick-commit --long
# Aim for a specific body length
ai-mr-comment quick-commit --body-lines=32
# Commit but skip the push
ai-mr-comment quick-commit --no-push
# Open the generated message in your editor before committing
ai-mr-comment quick-commit --edit
# Force conventional commit type and scope
ai-mr-comment quick-commit --type fix --scope api
# Apply a message template style
ai-mr-comment quick-commit --message-template detailed
ai-mr-comment quick-commit --message-template release
ai-mr-comment quick-commit --message-template ticket
# Stage only tracked modified/deleted files
ai-mr-comment quick-commit --tracked-only
# Append a DCO signoff trailer from git user config
ai-mr-comment quick-commit --signoff
# Use a specific provider or model
ai-mr-comment quick-commit --provider anthropic --model claude-opus-4-7
# Use a named profile
ai-mr-comment quick-commit --profile anthropic
# Force a breaking-change commit (feat!) for a major version bump
ai-mr-comment quick-commit --breaking
# Append a type-matched gitmoji to the subject
ai-mr-comment quick-commit --emoji
# e.g. feat(cli): add flag ✨
# Skip conventional commits format — free-form message
ai-mr-comment quick-commit --no-conventional
# Chaos mode — random funny/absurd conventional commit (great for pipeline trigger commits)
ai-mr-comment quick-commit --chaos
# e.g. ci(gremlins): ask nicely that the gremlins stop eating the cache
# Haiku mode — commit description as a 5-7-5 haiku about the diff
ai-mr-comment quick-commit --haiku
# e.g. feat(auth): tokens flow in / sessions find their rightful home / login works at last
# Roast mode — technically accurate but passive-aggressively judgmental
ai-mr-comment quick-commit --roast
# e.g. refactor(naming): rename 'x' to something a human might understand
# Fortune trailer — appends a dev-wisdom quote as a commit body
ai-mr-comment quick-commit --fortune
# commit subject + blank line + "The best code is the code you didn't have to write."
# Combine chaos + fortune for maximum vibes
ai-mr-comment quick-commit --chaos --fortune
# Monday mode — casual, low-energy "pre-coffee" commit
ai-mr-comment quick-commit --monday
# e.g. chore(deps): update the packages, it is what it is
# Jira mode — prefix with ticket key extracted from branch name
ai-mr-comment quick-commit --jira
# e.g. feat(auth): ABC-123 add JWT refresh token support
# Emoji-commit mode — append a type-matched gitmoji to the description
ai-mr-comment quick-commit --emoji-commit
# e.g. feat(auth): add refresh token rotation ✨
# Sassy mode — accurate but with attitude
ai-mr-comment quick-commit --sassy
# e.g. fix(auth): handle the edge case that definitely should have been handled
# Technical mode — maximum precision, references exact names from the diff
ai-mr-comment quick-commit --technical
# e.g. refactor(api): replace O(n²) scan with hash-map lookup in resolveUser
# Intern mode — SO excited about this commit!!
ai-mr-comment quick-commit --intern
# e.g. feat(auth): add the login thing everyone was asking about!!
# Shakespeare mode — hark, the diff doth speak
ai-mr-comment quick-commit --shakespeare
# e.g. fix(parser): hark, the null doth crash our noble code no more
# Manager mode — per our earlier alignment session
ai-mr-comment quick-commit --manager
# e.g. feat(auth): action item from last sprint re: token refresh, going forward
# Yoda mode — inverted syntax, strong with this commit it is
ai-mr-comment quick-commit --yoda
# e.g. fix(cache): stale data, purge we must
# Excuse mode — it happened for reasons, there were constraints
ai-mr-comment quick-commit --excuse
# e.g. fix(parser): handle empty input, which apparently nobody tested before
# JSON output — only commit_message is printed, all status lines suppressed
ai-mr-comment quick-commit --format json
# {"commit_message":"feat(cli): add login endpoint"}
Steps performed:
git add .— stages all changes by default;--tracked-onlyusesgit add -u- Reads the staged diff; prepends branch name for ticket key context
- Calls AI with the conventional commits prompt
- Optionally edits, signs off, and commits the generated message
git push --set-upstream origin <branch>— works for new branches too
| Flag | Description |
|---|---|
--dry-run | Generate and print the message, skip all git operations |
--no-push | Commit but skip the push |
--edit | Open the generated commit message in $GIT_EDITOR, $VISUAL, or $EDITOR before committing |
--type | Force a conventional commit type (feat, fix, docs, style, refactor, test, chore, perf, ci, build, or revert) |
--scope | Force a conventional commit scope |
--message-template | Apply a commit message template style: short, detailed, release, or ticket |
--include-untracked | Explicitly stage tracked and untracked changes, matching the default behavior |
--tracked-only | Stage only tracked modified/deleted files with git add -u |
--signoff | Append a Signed-off-by: trailer using local git user.name and git user.email |
--breaking | Force feat! conventional commit type to signal a breaking change (major version bump) |
--multi-line | Generate a multi-line message (subject + body) that pre-fills the PR/MR title and description |
--long | Generate a longer multi-section body; implies --multi-line |
--body-lines | Target body line count for long multi-line commits; implies --multi-line |
--emoji | Append a type-matched gitmoji to the subject (✨ feat, 🐛 fix, ♻️ refactor, 💥 breaking, etc.) |
--no-conventional | Skip conventional commits format — AI generates a free-form message instead |
--chaos | Generate a random funny/absurd conventional commit (ignores the real diff; great for pipeline trigger commits) |
--haiku | Write the commit description as a 5-7-5 haiku about the actual diff |
--roast | Technically accurate but passive-aggressively judgmental commit message |
--fortune | Append a dev-wisdom fortune-cookie quote as a commit body (git log shows it as a trailer) |
--monday | Casual, low-energy “pre-coffee” tone; accurate but undemanding |
--jira | Prefix the message with the Jira ticket key extracted from the branch name |
--emoji-commit | Append a type-matched gitmoji to the commit description |
--sassy | Sassy but technically accurate commit message |
--technical | Maximum technical precision; references exact function/struct names from the diff |
--intern | Overly enthusiastic junior-developer commit message |
--shakespeare | Commit description in Shakespearean Early Modern English |
--manager | Passive-aggressive corporate non-speak commit message |
--yoda | Commit description in Yoda’s inverted syntax |
--excuse | Technically accurate commit message with a built-in excuse |
--format json | Output {"commit_message":"..."} only; suppress status lines |
--provider | Override the AI provider |
--model | Override the model |
--profile | Activate a named config profile |
Publish
publish is the one-shot remote PR/MR workflow. It generates a title and description, updates the remote title/body, preserves manual description text by syncing only a managed section, and creates or updates one managed summary comment.
# Existing GitHub PR or GitLab MR
ai-mr-comment publish --pr https://github.com/owner/repo/pull/42
# Add labels, request reviewers, and mark the title as Draft: if the generated text looks risky
ai-mr-comment publish \
--pr https://gitlab.com/group/project/-/merge_requests/5 \
--auto-labels \
--label=release-notes \
--reviewer=12345 \
--draft-if-risky
# From a local branch: find an existing PR/MR or create one from origin
ai-mr-comment publish
# Preview without writing remote changes
ai-mr-comment publish --pr https://github.com/owner/repo/pull/42 --dry-run --format=json
| Flag | Description |
|---|---|
--pr | Existing GitHub PR or GitLab MR URL. If omitted, publish uses the current branch and origin remote to find or create a PR/MR |
--no-update-title | Skip updating the remote title |
--no-update-description | Skip updating the remote PR body / MR description |
--replace-description | Replace the full description instead of syncing the managed ai-mr-comment section |
--post-summary | Create or update one managed summary comment. Defaults to true; use --post-summary=false to disable |
--auto-labels | Apply simple labels inferred from changed files and generated text, such as docs, tests, ci, dependencies, or security |
--label | Add an explicit label. Can be repeated or comma-separated |
--reviewer | Request a reviewer. GitHub uses usernames; GitLab uses numeric user IDs |
--draft-if-risky | Prefix the generated title with Draft: when generated text indicates high risk |
--dry-run | Generate and print the planned remote changes without writing them |
--format | text (default) or json |
Changelog
changelog generates a user-facing changelog entry from any diff source. Output follows the Keep a Changelog format, grouped under the headings that apply: Added, Changed, Deprecated, Removed, Fixed, Security, Breaking Changes.
# Last 10 commits (Makefile default)
make changelog
# Specific release range
ai-mr-comment changelog --commit="v1.2.0..HEAD"
# From a diff file
ai-mr-comment changelog --file=my.diff --provider=anthropic
# JSON output for CI pipelines
ai-mr-comment changelog --commit="v1.2.0..HEAD" --format=json
# Write directly to a file
ai-mr-comment changelog --commit="v1.2.0..HEAD" --output=CHANGELOG.md
# Override the prompt for a custom format
ai-mr-comment changelog --commit="v1.2.0..HEAD" \
--system-prompt="List only breaking changes."
| Flag | Description |
|---|---|
--commit | Commit or commit range (e.g. v1.2.0..HEAD) |
--file | Read diff from a file instead of git |
--format | text (default) or json ({"changelog":"...","provider":"...","model":"..."}) |
--output | Write output to a file instead of stdout |
--provider | AI provider override |
--model | Model override |
--profile | Activate a named config profile |
--system-prompt | Override the changelog system prompt |
Shell Aliases
gen-aliases prints a block of ready-to-source shell alias definitions.
# Append once to your profile
ai-mr-comment gen-aliases >> ~/.zshrc
# Or evaluate on every shell start (always up-to-date)
eval "$(ai-mr-comment gen-aliases)"
# Write directly to a file
ai-mr-comment gen-aliases --output=~/.bashrc
# Via make
make gen-aliases
Aliases defined:
| Alias | Expands to |
|---|---|
amc | ai-mr-comment |
amc-staged | ai-mr-comment --staged |
amc-commit | ai-mr-comment --commit-msg --staged |
amc-commit-multi | ai-mr-comment --commit-msg --multi-line --staged |
amc-title | ai-mr-comment --title |
amc-json | ai-mr-comment --format=json |
amc-debug | ai-mr-comment --debug |
amc-chaos | ai-mr-comment --chaos |
amc-haiku | ai-mr-comment --haiku |
amc-roast | ai-mr-comment --roast |
amc-intern | ai-mr-comment --intern |
amc-shakespeare | ai-mr-comment --shakespeare |
amc-manager | ai-mr-comment --manager |
amc-yoda | ai-mr-comment --yoda |
amc-excuse | ai-mr-comment --excuse |
amc-conventional | ai-mr-comment --template=conventional |
amc-emoji | ai-mr-comment --template=emoji |
amc-jira | ai-mr-comment --template=jira |
amc-monday | ai-mr-comment --template=monday |
amc-sassy | ai-mr-comment --template=sassy |
amc-technical | ai-mr-comment --template=technical |
amc-user | ai-mr-comment --template=user-focused |
amc-qc | ai-mr-comment quick-commit |
amc-qc-dry | ai-mr-comment quick-commit --dry-run |
amc-qc-edit | ai-mr-comment quick-commit --edit |
amc-qc-local | ai-mr-comment quick-commit --no-push |
amc-qc-tracked | ai-mr-comment quick-commit --tracked-only |
amc-qc-signoff | ai-mr-comment quick-commit --signoff |
amc-qc-fix | ai-mr-comment quick-commit --type=fix |
amc-qc-docs | ai-mr-comment quick-commit --type=docs |
amc-qc-detailed | ai-mr-comment quick-commit --message-template=detailed |
amc-qc-release | ai-mr-comment quick-commit --message-template=release |
amc-qc-ticket | ai-mr-comment quick-commit --message-template=ticket |
amc-qc-breaking | ai-mr-comment quick-commit --breaking |
amc-qc-chaos | ai-mr-comment quick-commit --chaos |
amc-qc-haiku | ai-mr-comment quick-commit --haiku |
amc-qc-roast | ai-mr-comment quick-commit --roast |
amc-qc-fortune | ai-mr-comment quick-commit --fortune |
amc-qc-monday | ai-mr-comment quick-commit --monday |
amc-qc-jira | ai-mr-comment quick-commit --jira |
amc-qc-emoji | ai-mr-comment quick-commit --emoji-commit |
amc-qc-sassy | ai-mr-comment quick-commit --sassy |
amc-qc-technical | ai-mr-comment quick-commit --technical |
amc-qc-intern | ai-mr-comment quick-commit --intern |
amc-qc-shakespeare | ai-mr-comment quick-commit --shakespeare |
amc-qc-manager | ai-mr-comment quick-commit --manager |
amc-qc-yoda | ai-mr-comment quick-commit --yoda |
amc-qc-excuse | ai-mr-comment quick-commit --excuse |
amc-cl | ai-mr-comment changelog |
amc-models | ai-mr-comment models |
amc-init | ai-mr-comment init-config |
| Flag | Description |
|---|---|
--shell | bash (default) or zsh — both use identical alias syntax |
--output | Also write aliases to this file |
Local CLI Providers
Three providers delegate AI calls and authentication to a locally installed CLI tool — no API key management in ai-mr-comment is required. These are useful on machines where auth is handled by the CLI’s own session (SSO, OAuth, Claude Code session).
claude-cli — Claude Code
Delegates to the claude binary. Auth is managed by Claude Code — no ANTHROPIC_API_KEY needed.
provider = "claude-cli"
claude_cli_model = "claude-sonnet-4-6"
Binary lookup order:
claude_cli_pathin config (if set)~/.claude/local/claudeclaudeon$PATH
| Key | Description | Default |
|---|---|---|
claude_cli_path | Explicit path to the claude binary | auto-detected |
claude_cli_model | Model passed via --model | claude-sonnet-4-6 |
gemini-cli — Google Gemini CLI
Delegates to the gemini binary. Auth uses Google OAuth — no GEMINI_API_KEY needed.
Install: npm install -g @google/gemini-cli
provider = "gemini-cli"
gemini_cli_model = "gemini-2.5-flash"
| Key | Description | Default |
|---|---|---|
gemini_cli_path | Explicit path to the gemini binary | auto-detected via $PATH |
gemini_cli_model | Model passed via --model | gemini-2.5-flash |
codex-cli — OpenAI Codex CLI
Delegates to the codex binary in quiet/non-interactive mode. Still requires OPENAI_API_KEY but handles its own session and approval flow.
Install: npm install -g @openai/codex
provider = "codex-cli"
# codex_cli_model = "" # leave empty to use codex default
| Key | Description | Default |
|---|---|---|
codex_cli_path | Explicit path to the codex binary | auto-detected via $PATH |
codex_cli_model | Model passed via --model | empty (codex default) |
Profiles
All three have built-in profiles:
ai-mr-comment --profile claude-cli
ai-mr-comment --profile gemini-cli
ai-mr-comment --profile codex-cli
Named Profiles
Define named profiles in ~/.ai-mr-comment.toml under [profile.<name>] sections. Each profile can override any top-level setting — provider, model, template, endpoint, etc.
provider = "anthropic"
anthropic_model = "claude-sonnet-4-6"
template = "default"
[profile.fast]
provider = "openai"
openai_model = "gpt-5.4-nano"
template = "conventional"
[profile.openai]
provider = "openai"
openai_model = "gpt-5.5"
template = "technical"
[profile.anthropic]
provider = "anthropic"
anthropic_model = "claude-opus-4-7"
template = "technical"
[profile.gemini]
provider = "gemini"
gemini_model = "gemini-3.1-pro-preview"
template = "technical"
[profile.local]
provider = "ollama"
ollama_model = "llama3.2"
[profile.claude-cli]
provider = "claude-cli"
claude_cli_model = "claude-sonnet-4-6"
[profile.gemini-cli]
provider = "gemini-cli"
gemini_cli_model = "gemini-2.5-flash"
[profile.codex-cli]
provider = "codex-cli"
Activate a profile by passing --profile <name> to any command:
# Quick review with the fast profile
ai-mr-comment --profile fast
# Deep technical review with Anthropic Opus
ai-mr-comment --profile anthropic --title
# Generate a changelog with Gemini Pro
ai-mr-comment changelog --profile gemini --commit="v1.2.0..HEAD"
# Commit with Ollama (no API key needed)
ai-mr-comment quick-commit --profile local --dry-run
# Use Claude CLI session auth (no API key needed)
ai-mr-comment --profile claude-cli
# Use Gemini CLI with Google OAuth (no API key needed)
ai-mr-comment --profile gemini-cli
# Use Codex CLI
ai-mr-comment --profile codex-cli
Run ai-mr-comment init-config to generate a config file pre-populated with the standard profiles above.
CI/CD Usage
Three flags are designed specifically for pipeline integration:
--exit-code — Gate merges on AI review
Instruct the AI to output a VERDICT: PASS or VERDICT: FAIL line before its review. If FAIL, the process exits with code 2, failing your pipeline step.
# Fail the pipeline if the AI detects critical issues
ai-mr-comment --exit-code --pr "$PR_URL"
echo $? # 0 = PASS, 2 = FAIL, 1 = tool error
# JSON includes the verdict field for downstream processing
ai-mr-comment --exit-code --format json --pr "$PR_URL" | jq .verdict
GitHub Actions example:
- name: AI Code Review
run: ai-mr-comment --exit-code --pr "$"
env:
OPENAI_API_KEY: $
GITHUB_TOKEN: $
# Step fails (exit 2) if AI detects critical issues
--post — Auto-post comments to PRs/MRs
After generating the comment, post it directly to the PR or MR via the GitHub/GitLab API. Uses the same token as diff fetching — no extra setup needed.
# Generate and post in one step
ai-mr-comment --pr "$PR_URL" --post
# Combine with exit-code: review, post, and gate in one command
ai-mr-comment --exit-code --post --pr "$PR_URL"
GitHub Actions example:
- name: AI Review & Comment
run: ai-mr-comment --post --pr "$"
env:
OPENAI_API_KEY: $
GITHUB_TOKEN: $
--output with --format json — Save review artifacts
Write the full JSON review to a file. Useful for artifact upload, audit trails, or passing data between pipeline jobs.
# Write JSON to file
ai-mr-comment --format json --output review.json --pr "$PR_URL"
# Upload as artifact (GitHub Actions)
# - uses: actions/upload-artifact@v4
# with: { name: ai-review, path: review.json }
# Read in a later job
cat review.json | jq -r '.description'
cat review.json | jq -r '.verdict' # when --exit-code was used
When --commit-msg is set, --output writes the commit message (with a trailing newline) rather than JSON.
Streaming Output
When running interactively (stdout is a TTY), the tool streams tokens directly to the terminal as the model generates them, so you see the comment appear word by word rather than waiting for the full response.
Streaming is automatically disabled and the output is fully buffered when:
--format jsonis set (the full response is needed before encoding)--smart-chunkis set (multi-stage summarise + synthesise calls)--output <file>is set (writing to a file)- stdout is not a TTY (piped output, CI, redirected to file)
If a streaming call fails mid-flight, the tool transparently falls back to a standard buffered request and outputs the full comment normally.
Token & Cost Estimation
When running with the --debug flag, the tool provides a detailed breakdown of the expected usage:
- Gemini: Uses official SDK token counting (100% accurate).
- OpenAI/Anthropic/Ollama: Uses a conservative character-based heuristic (~3.5 chars per token).
- Cost: Calculates estimated input cost in USD based on current model pricing (Ollama is free).
Development
Project Structure
cmd/ai-mr-comment/: Executable entry pointinternal/app/: Cobra command orchestration and embedded prompt templatesinternal/: Internal packages for config, providers, remote hosts, git diffs, prompts, estimates, and commit helperstestdata/: Sample git diffs for testingdist/: Compiled binaries (after build)
Testing
# Run unit tests
make test
# Run deterministic compiled-binary e2e smoke tests
make test-e2e-smoke
# Run deterministic Docker smoke tests
make docker-smoke
# Run all provider integration tests (provider tests skip when keys are missing)
make test-integration
# Run one provider integration lane
make test-integration-openai
make test-integration-gemini
make test-integration-anthropic
# Run Ollama-only integration tests (CPU-friendly small model)
OLLAMA_ENDPOINT=http://127.0.0.1:11434/api/generate \
OLLAMA_MODEL=llama3.2:1b \
make test-integration-ollama
# Run fuzz tests (30s per target)
make test-fuzz
# Run response-quality evals on curated diff fixtures (promptfoo)
make eval-quality
# Run writing-quality evals for commit messages + PR title/description
make eval-quality-writing
# Install/update pinned eval dependencies only
make eval-quality-deps
# Run linter
make lint
CI coverage on PRs includes unit/lint checks plus deterministic binary e2e smoke checks. Docker smoke also runs when DHI registry credentials are available to pull the hardened base images. Provider e2e tests run after merge to main or by manual dispatch when credentials are available. Long Ollama integration + promptfoo quality eval lanes run from a separate manual workflow: Ollama Integration (Manual). Open GitHub Actions, select that workflow, then click Run workflow.
Response Quality Evals
make eval-quality runs end-to-end evals against fixture diffs in evals/ and scores the generated review for recall, severity coverage, actionability, and false positives. In CI, evals write a compact JSON report to evals/promptfoo-results.json and print a short summary. CI uses serialized eval calls and extended per-test timeout for CPU models (PROMPTFOO_MAX_CONCURRENCY=1, PROMPTFOO_EVAL_TIMEOUT_MS=300000).
Prerequisites:
- Node.js +
npm - A reachable model provider (defaults to local Ollama)
- Built binary (handled automatically by
make eval-quality) - Pinned eval dependencies (including
promptfoo) are installed fromevals/package-lock.json
Useful overrides:
AMC_EVAL_PROVIDER(defaultollama)AMC_EVAL_MODEL(defaultllama3.2:1b)AMC_EVAL_TEMPLATE(defaulttechnical)AMC_EVAL_FLAGS(additional CLI flags)
# Example: run evals against local Ollama 1B model
AMC_EVAL_PROVIDER=ollama AMC_EVAL_MODEL=llama3.2:1b make eval-quality
# Example: run commit + PR writing evals against local Ollama 8B model
AMC_EVAL_PROVIDER=ollama AMC_EVAL_MODEL=llama3.1:8b AMC_EVAL_TEMPLATE=default make eval-quality-writing
# Open the latest promptfoo report UI
make eval-quality-view
Dependency Updates
Dependabot opens grouped PRs weekly (Monday) for Go modules, npm packages in evals/, and GitHub Actions.
To approve and auto-merge all open Dependabot PRs at once:
gh pr list --author "app/dependabot" --json number --jq '.[].number' | \
xargs -I {} gh pr merge {} --auto --squash
--autoqueues each PR to merge once all required status checks pass. Requires auto-merge to be enabled in the repo settings. Drop--autoand use--squashalone to merge immediately without waiting for CI.
Shell Completions
# Install bash completions
make install-completion-bash
# Install zsh completions
make install-completion-zsh
# Or generate manually for any shell
ai-mr-comment completion [bash|zsh|fish|powershell]
Contributing
Commit Convention
This project uses Conventional Commits to drive automatic semantic versioning. Every commit merged to main must follow the format:
<type>[optional scope]: <description>
| Type | Description | Version bump |
|---|---|---|
fix: | Bug fix | patch (0.0.x) |
feat: | New feature | minor (0.x.0) |
feat!: or BREAKING CHANGE: footer | Breaking change | major (x.0.0) |
chore:, docs:, ci:, test:, refactor:, style:, perf: | Non-functional | none |
Examples:
fix: handle empty diff gracefully
feat: add clipboard output support
feat!: redesign config file format
chore: update dependencies
Release Process
Merging to main automatically creates a version tag (e.g. v0.2.0) based on the commits since the last release — no GitHub Release is created yet.
When ready to publish a release:
- Go to GitHub → Releases → Draft a new release
- Pick the pre-created tag from the dropdown
- Click Publish release — GoReleaser builds and attaches signed binaries automatically
- Release workflow dispatches the source tarball metadata to
pbsladek/homebrew-tapfor Homebrew validation/update automation
License
MIT
Acknowledgements
This project is a Go rewrite of mr-comment originally created by Robert Kozak.