Integrations
Every integration runs the same command and reads the same JSON. What differs between them is how a diff arrives and where comments go — a few dozen lines of API calls each, nothing more.
GitHub#
# .github/workflows/groundtruth.yml
on: pull_request
concurrency:
group: groundtruth-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions:
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with: { fetch-depth: 0 }
- uses: groundtruth-code-review/groundtruth-code-review/adapters/github@main
with: { model: anthropic/claude-sonnet-5 }
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
To use a different endpoint, set it in the workflow's env beside the key it goes with:
env:
NVIDIA_NIM_API_KEY: ${{ secrets.NVIDIA_NIM_API_KEY }}
GROUNDTRUTH_BASE_URL: https://integrate.api.nvidia.com/v1
To verify with a different provider, set verify_model in .groundtruth.yml and pass both keys:
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
fetch-depth: 0is required — the default shallow clone has no base commit to diff against.pull-requests: writeis required for the job's ownGITHUB_TOKENto post.concurrencycancels the review still running for a pull request when a new push arrives, instead of letting two runs race to write the same summary comment.- Findings post as review comments on the line; the summary is an issue comment, edited in place on later pushes.
GitLab#
Copy adapters/gitlab/gitlab-ci.example.yml into your .gitlab-ci.yml.
CI_JOB_TOKEN cannot post notes on a merge request. You need a project access token with the api scope, exposed to the job as GROUNDTRUTH_GITLAB_TOKEN. This is the single most common reason a GitLab setup runs clean and posts nothing.- Set
GIT_DEPTH: 0in the job, for the same reason GitHub needsfetch-depth: 0. - Findings post as positioned discussions, which need both the base and head SHAs — the adapter reads them from
CI_MERGE_REQUEST_DIFF_BASE_SHAandCI_COMMIT_SHA. - The summary is a note, edited in place.
interruptible: trueopts the job into GitLab's auto-cancel-redundant-pipelines behaviour, the same race protection GitHub'sconcurrencygives — enable it once per project under Settings → CI/CD → General pipelines.
Bitbucket Cloud#
Copy adapters/bitbucket_cloud/bitbucket-pipelines.example.yml into your bitbucket-pipelines.yml.
- Set
clone: depth: full. - Pipelines gives you the merge target as a branch name, not a SHA, so the step fetches
origin/$BITBUCKET_PR_DESTINATION_BRANCHbefore reviewing. - Authentication is an app password or repository access token over Basic auth, as
GROUNDTRUTH_BITBUCKET_USERandGROUNDTRUTH_BITBUCKET_APP_PASSWORD. - Findings post as inline-anchored comments; the summary is a plain comment on the pull request.
- Pipelines has no concurrency-group equivalent to cancel a superseded run on a fast second push — the fingerprint marker is the only protection against a duplicate comment there.
Kubernetes, Tekton, Argo, Jenkins#
There is no Helm chart, because there is no workload to install — a review starts, reads a diff and exits. What in-cluster CI needs is the image:
image: ghcr.io/groundtruth-code-review/groundtruth-code-review:0.1.0
args: ["review", "--repo", "/workspace", "--base", "origin/main", "--format", "json"]
env:
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef: { name: groundtruth, key: api-key }
The image carries git and ripgrep, runs as an unprivileged user, and ships for both amd64 and arm64. Its Dockerfile is multi-stage: the runtime stage installs a wheel that only exists if lint, both test suites and the eval thresholds passed first, so a failing suite cannot produce a shippable image.
What every adapter shares#
- One JSON contract. Adapters read what
groundtruth review --format jsonprints and nothing else. None of them import the package. - One memory. The fingerprints of everything already posted are carried in a hidden HTML comment inside the summary comment, so the next push does not repeat itself. No database, and it works anywhere comments can be edited.
- One failure mode. If a single finding cannot be placed — a force-push race, a line the platform does not consider part of the diff — that comment is skipped with a warning and the rest of the review still posts.