MR Eval Gate
Gate merge requests on evaluation regressions — set up with a ready-made merge request or by hand.
The MR Eval Gate runs your LLM app over a pinned dataset on every merge request, scores the outputs with a metric collection, and posts a GitLab commit status (plus a note on the merge request) that passes, fails, or is neutral depending on whether your metric scores regressed against your target branch (within your configured tolerance).
It needs two things in your project:
.gitlab-ci.yml— includes Confident's published CI/CD component, which sets up your app (Python + dependencies) and runs the gate on every merge request.confident_eval.py— arun(input)function that calls your app and returns its output as a string. Confident calls this once per golden in your dataset.
Configure the gate
Connect GitLab and configure
Go to Settings → Integrations → MR Eval Gate, connect GitLab, then choose the project, dataset, metric collection, and regression tolerance (the maximum average score drop per metric before the gate fails). Click Save.
Open the setup merge request
Click Open setup merge request. Saving only stores your configuration; this step is what wires the two files into your project and adds the
CONFIDENT_API_KEYCI/CD variable for you.
Setup methods
Setup merge request
Confident opens a merge request that adds the CI/CD component include and a confident_eval.py stub — no AI reads your code. You fill in run() and adjust the component inputs before merging.
Fully manual
Add the two files (and the CI/CD variable) yourself. Confident never opens a merge request for you — the connection only posts commit statuses and notes. Follow the steps below.
Set it up yourself
If you'd rather Confident never open a merge request for you, add everything by hand. This is the most locked-down option; you also add the API key variable yourself.
Include the CI/CD component
Add Confident's component to your
.gitlab-ci.yml. Setimageandinstall_commandto match your app's runtime..gitlab-ci.yml include: - component: gitlab.com/confident-ai/eval-gate/eval-gate@v1 inputs: base_url: "<your-region-api-base-url>" dataset_alias: "<your-dataset-alias>" dataset_version: "latest" image: "python:3.12" # match your app's runtime install_command: "pip install -r requirements.txt" # match your project (poetry/uv/etc.)Add the eval callback
Create
confident_eval.pyat the repository root.run(input)receives one dataset input, calls your app, and returns its output — Confident runs it for every golden in your dataset and scores the results.confident_eval.py def run(input): """Return your LLM app's output for a single dataset input.""" from my_app import agent # import your application return agent(input) # return the output as a stringAdd the CI/CD variables
Create a project API key in Settings → API Keys, then add it as a CI/CD variable named
CONFIDENT_API_KEY(Settings → CI/CD → Variables in GitLab). Mask it, and leave Protect variable unchecked — protected variables are invisible to the merge-request pipelines where the gate runs. Add any runtime secrets your app needs (for exampleOPENAI_API_KEY) the same way.
Once the component include and confident_eval.py are on your default branch, every future merge request runs the gate and posts the Confident MR Eval Gate commit status (and a note with the score comparison) against your target branch.
Troubleshooting
Most misconfigurations fail loudly — the runner reports the reason on the Confident MR Eval Gate commit status and in the pipeline job logs. A few fail silently; those are called out below.
| Symptom | Likely cause | Fix |
|---|---|---|
| Gate never runs on an MR (silent) | The component include: was removed, or the project's workflow:rules exclude merge-request pipelines | Keep the component include and allow merge_request_event pipelines |
| Scores look meaningless — everything compared against "None" (silent) | run() returned None or a non-string value | Return your app's output as a string from run() |
could not import confident_eval.run | confident_eval.py isn't at the repo root, or the function isn't named run | Keep the file at the repository root and the function named run |
app raised while producing outputs | run() doesn't take a single input argument, or an app runtime secret is missing | Match the run(input) signature; add your app's secrets (e.g. OPENAI_API_KEY) as CI/CD variables |
could not pull dataset | CONFIDENT_API_KEY is missing/rotated/revoked, or the dataset alias, version, or base_url is wrong | Re-add the variable and verify the dataset alias, version, and region base_url |
CONFIDENT_API_KEY is empty in the job (silent) | The variable is Protected, so it's hidden from the merge-request pipeline | Edit the variable and uncheck Protect variable (keep Masked) |
| The project doesn't appear in the picker | You're not a Maintainer on the project | Managing CI/CD variables requires Maintainer — ask an owner to grant it |
| Errors on some or all rows | The dataset contains multi-turn goldens | v1 supports single-turn datasets — point the gate at a single-turn dataset |
Last updated on