Platforms
Getting Started

Platforms

Merlin AI Code Review auto-detects the VCS platform from CI environment variables. No manual config needed.

PlatformAuto-detected env varToken env varComments appear as
GitHubGITHUB_ACTIONS=trueGITHUB_TOKENgithub-actions[bot]
GitLabGITLAB_CI=trueGITLAB_TOKENGitLab project bot
BitbucketBITBUCKET_PIPELINE_UUIDBITBUCKET_TOKENPipelines build service
Azure DevOpsTF_BUILD=TrueAZURE_DEVOPS_TOKENProject Collection Build Service
GiteaGITEA_ACTIONS=trueGITEA_TOKENgitea-actions[bot]

GitHub Actions

Option A — Docker container (simplest, recommended):

.github/workflows/merlin-review.yml
yaml
name: Merlin AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
merlin-review:
runs-on: ubuntu-latest
container:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Merlin Review
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: merlin review

Option B — Binary install (with RAG index caching):

.github/workflows/merlin-review.yml
yaml
name: Merlin AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
merlin-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Cache RAG index
uses: actions/cache@v4
with:
path: merlin-rag.jsonl
key: merlin-rag-${{ hashFiles('src/**', 'lib/**') }}
restore-keys: merlin-rag-
- name: Install Merlin
run: |
curl -fsSL \
https://github.com/Arunachalamkalimuthu/merlin-ai-code-review/releases/latest/download/install.sh \
| sh
- name: Build RAG index (first run only)
run: test -f merlin-rag.jsonl || merlin rag index .
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Run Merlin Review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: merlin review

Webhook bot mode (GitHub)

Allow PR commenters to trigger commands by mentioning @merlin.

.github/workflows/merlin-bot.yml
yaml
on:
issue_comment:
types: [created]
jobs:
merlin-bot:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- run: merlin webhook --port 8080
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
MERLIN_GITHUB_SECRET: ${{ secrets.MERLIN_GITHUB_SECRET }}

GitLab CI

Docker image (simplest):

.gitlab-ci.yml
yaml
merlin-review:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
stage: review
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GITLAB_TOKEN: $CI_JOB_TOKEN
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
script:
- merlin review

With RAG index caching:

.gitlab-ci.yml
yaml
merlin-review:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
stage: review
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
cache:
key: merlin-rag-$CI_DEFAULT_BRANCH
paths:
- merlin-rag.jsonl
variables:
GITLAB_TOKEN: $CI_JOB_TOKEN
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
OPENAI_API_KEY: $OPENAI_API_KEY
script:
- test -f merlin-rag.jsonl || merlin rag index .
- merlin review

Bitbucket Pipelines

bitbucket-pipelines.yml
yaml
pipelines:
pull-requests:
'**':
- step:
name: Merlin AI Review
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
caches:
- merlin-rag
script:
- test -f merlin-rag.jsonl || merlin rag index .
- merlin review
variables:
BITBUCKET_TOKEN: $BITBUCKET_STEP_TOKEN
ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
OPENAI_API_KEY: $OPENAI_API_KEY
definitions:
caches:
merlin-rag:
key:
files:
- src/**
path: merlin-rag.jsonl

Azure DevOps

One-time setup

In the Azure DevOps pipeline editor, click … → Triggers → YAML → Get sources and tick "Allow scripts to access the OAuth token".

azure-pipelines.yml
yaml
trigger: none
pr:
branches:
include:
- '*'
pool:
vmImage: ubuntu-latest
container:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
steps:
- checkout: self
fetchDepth: 0
- script: merlin review
displayName: Merlin AI Review
env:
AZURE_DEVOPS_TOKEN: $(System.AccessToken)
ANTHROPIC_API_KEY: $(ANTHROPIC_API_KEY)
SYSTEM_TEAMFOUNDATIONCOLLECTIONURI: $(System.TeamFoundationCollectionUri)
SYSTEM_TEAMPROJECT: $(System.TeamProject)
BUILD_REPOSITORY_NAME: $(Build.Repository.Name)
BUILD_SOURCEBRANCH: $(Build.SourceBranch)
SYSTEM_PULLREQUEST_PULLREQUESTID: $(System.PullRequest.PullRequestId)

Gitea Actions

.gitea/workflows/merlin-review.yml
yaml
name: Merlin AI Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
merlin-review:
runs-on: ubuntu-latest
container:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Merlin Review
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: merlin review

Docker (local or self-hosted CI)

shell
docker run --rm \
-e GITHUB_TOKEN=... \
-e ANTHROPIC_API_KEY=... \
-e GITHUB_ACTIONS=true \
-e GITHUB_REPOSITORY=owner/repo \
-e PR_NUMBER=42 \
-e REPO=owner/repo \
ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest merlin review

Running as a persistent webhook service:

docker-compose.yml
yaml
services:
merlin:
image: ghcr.io/arunachalamkalimuthu/merlin-ai-code-review:latest
command: webhook --port 8080
ports:
- "8080:8080"
environment:
GITHUB_TOKEN: your-token
ANTHROPIC_API_KEY: your-key
MERLIN_GITHUB_SECRET: your-secret
restart: unless-stopped