GitHub¶
Detailed guide for integration with GitHub Actions.
Permissions¶
Minimum Permissions¶
GITHUB_TOKEN in Actions¶
In GitHub Actions, GITHUB_TOKEN is automatically available:
Automatic token permissions:
| Permission | Status | Note |
|---|---|---|
contents: read |
Default | |
pull-requests: write |
Must be specified in permissions |
Fork PRs
For PRs from fork repositories, GITHUB_TOKEN has read-only permissions.
AI Review cannot post comments for fork PRs.
How to Get a Personal Access Token¶
For local runs, you need a Personal Access Token (PAT):
- Go to
Settings โ Developer settings โ Personal access tokens - Choose Fine-grained tokens (recommended) or Classic
- Click Generate new token
Fine-grained token (recommended):
| Setting | Value |
|---|---|
| Repository access | Only select repositories โ your repository |
| Permissions | Pull requests: Read and write |
Classic token:
| Scope | Description |
|---|---|
repo |
Full access to repository |
- Click Generate token
- Copy the token and save it as
GITHUB_TOKEN
Save the token
GitHub shows the token only once. Save it immediately.
Triggers¶
Recommended Trigger¶
| Type | When it triggers |
|---|---|
opened |
PR created |
synchronize |
New commits in PR |
reopened |
PR reopened |
File Filtering¶
Run review only for specific files:
Branch Filtering¶
Secrets¶
Adding Secrets¶
Settings โ Secrets and variables โ Actions โ New repository secret
| Secret | Required | Description |
|---|---|---|
AI_REVIEWER_GOOGLE_API_KEY |
When using Google provider | Gemini API key |
AI_REVIEWER_MISTRAL_API_KEY |
When using Mistral provider | Mistral API key |
At least one LLM API key is required (for the primary provider).
Usage¶
# Google (default provider)
env:
AI_REVIEWER_GOOGLE_API_KEY: ${{ secrets.AI_REVIEWER_GOOGLE_API_KEY }}
# Mistral as primary, Google as fallback
env:
AI_REVIEWER_MISTRAL_API_KEY: ${{ secrets.AI_REVIEWER_MISTRAL_API_KEY }}
AI_REVIEWER_GOOGLE_API_KEY: ${{ secrets.AI_REVIEWER_GOOGLE_API_KEY }}
AI_REVIEWER_LLM_PROVIDER: mistral
AI_REVIEWER_LLM_FALLBACK_PROVIDER: google
Never hardcode secrets
Always use ${{ secrets.* }} โ never paste keys directly in YAML.
Workflow Examples¶
Minimal¶
name: AI Code Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: KonstZiv/ai-code-reviewer@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
google_api_key: ${{ secrets.AI_REVIEWER_GOOGLE_API_KEY }}
About GITHUB_TOKEN
secrets.GITHUB_TOKEN is an automatic token that GitHub creates for each workflow run. You don't need to add it to secrets manually โ it's already available.
Token permissions are defined by the permissions section in the workflow file.
With Concurrency (recommended)¶
name: AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ai-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
pull-requests: write
steps:
- uses: KonstZiv/ai-code-reviewer@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
google_api_key: ${{ secrets.AI_REVIEWER_GOOGLE_API_KEY }}
language: uk
language_mode: adaptive
What concurrency does:
- If a new commit is pushed while review is still running โ the old review is cancelled
- Saves resources and API calls
With Fork PR Filtering¶
jobs:
review:
runs-on: ubuntu-latest
# Don't run for fork PRs (no access to secrets)
if: github.event.pull_request.head.repo.full_name == github.repository
GitHub Action Inputs¶
| Input | Description | Default |
|---|---|---|
google_api_key |
Google Gemini API key | (required for Google) |
mistral_api_key |
Mistral API key | (required for Mistral) |
llm_provider |
Primary LLM provider (google, mistral) |
google |
llm_fallback_provider |
Fallback LLM provider | (none) |
github_token |
GitHub token | ${{ github.token }} |
gemini_model |
Gemini model | gemini-2.5-flash |
gemini_model_fallback |
Gemini fallback model chain | gemini-3-flash-preview,... |
mistral_model |
Mistral model | mistral-large-latest |
mistral_model_fallback |
Mistral fallback model chain | (none) |
mistral_api_url |
Custom Mistral API URL (e.g. https://codestral.mistral.ai) |
(none) |
language |
Response language | en |
language_mode |
Language mode | adaptive |
log_level |
Log level | INFO |
review_max_comment_chars |
Max MR comment chars in prompt | 3000 |
review_include_bot_comments |
Include bot comments in prompt | true |
review_post_inline_comments |
Post inline comments on lines | true |
review_enable_dialogue |
Group comments into dialogues | true |
discovery_enabled |
Enable project discovery | true |
discovery_verbose |
Always post discovery comment | false |
discovery_timeout |
Discovery timeout in seconds | 30 |
Environment variables
The Action maps inputs to AI_REVIEWER_* environment variables internally. When running outside the Action, use AI_REVIEWER_* env vars directly (old names like GOOGLE_API_KEY still work as fallback).
Variable-Driven Configuration¶
Use Repository Variables to switch between LLM providers and models without changing the workflow file. This is useful for comparing review quality across different models on the same PR.
Setup¶
Secrets (set once, do not change):
| Secret | Description |
|---|---|
AI_REVIEWER_GOOGLE_API_KEY |
Gemini API key |
AI_REVIEWER_MISTRAL_API_KEY |
Mistral API key |
Variables (Settings โ Secrets and variables โ Actions โ Variables tab):
| Variable | Description | Default |
|---|---|---|
LLM_PROVIDER |
Primary provider (google, mistral) |
google |
LLM_FALLBACK_PROVIDER |
Fallback provider | (empty) |
MISTRAL_MODEL |
Mistral model to use | mistral-large-latest |
MISTRAL_API_URL |
Custom API URL (for Codestral free tier) | (empty) |
Workflow¶
name: AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
concurrency:
group: ai-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: github.event.pull_request.head.repo.full_name == github.repository
permissions:
contents: read
pull-requests: write
steps:
- uses: KonstZiv/ai-code-reviewer@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
google_api_key: ${{ secrets.AI_REVIEWER_GOOGLE_API_KEY }}
mistral_api_key: ${{ secrets.AI_REVIEWER_MISTRAL_API_KEY }}
llm_provider: ${{ vars.LLM_PROVIDER || 'google' }}
llm_fallback_provider: ${{ vars.LLM_FALLBACK_PROVIDER || '' }}
mistral_model: ${{ vars.MISTRAL_MODEL || 'mistral-large-latest' }}
mistral_api_url: ${{ vars.MISTRAL_API_URL || '' }}
Switching Presets¶
Change Variables in the GitHub UI, then Re-run the workflow on the same PR:
| Preset | LLM_PROVIDER |
MISTRAL_MODEL |
MISTRAL_API_URL |
LLM_FALLBACK_PROVIDER |
|---|---|---|---|---|
| Gemini (default) | google |
(empty) | (empty) | (empty) |
| Mistral Large | mistral |
mistral-large-latest |
(empty) | google |
| Codestral free | mistral |
codestral-latest |
https://codestral.mistral.ai |
google |
| Devstral | mistral |
devstral-latest |
(empty) | google |
Codestral free tier key
For the "Codestral free" preset, AI_REVIEWER_MISTRAL_API_KEY must contain a key from codestral.mistral.ai, not from console.mistral.ai.
Variables vs Secrets
Secrets are encrypted and hidden in logs โ use for API keys. Variables are visible in logs โ use for non-sensitive config like model names.
Review Result¶
Inline Comments¶
AI Review posts comments directly on code lines:
CRITICAL โ critical issues (security, bugs)
WARNING โ recommendations
INFO โ educational notes
Apply Suggestion¶
Each comment with a code suggestion has an "Apply suggestion" button:
GitHub automatically renders this as an interactive button.
Summary¶
At the end of the review, a Summary is posted with:
- Overall issue statistics
- Metrics (time, tokens, cost)
- Good practices (positive feedback)
Troubleshooting¶
Review Not Posting Comments¶
Check:
permissions: pull-requests: writeis in the workflowAI_REVIEWER_GOOGLE_API_KEYsecret is set- PR is not from a fork repository
"Resource not accessible by integration"¶
Cause: Insufficient permissions.
Solution: Add permissions:
Rate Limit from Gemini¶
Cause: Free tier limit exceeded (15 RPM).
Solution:
- Wait a minute
- Add
concurrencyto cancel old runs - Consider paid tier