> For the complete documentation index, see [llms.txt](https://docs.tessl.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tessl.io/tutorials/setting-up-agentic-code-review/code-review-in-gitlab.md).

# Run Code Review with GitLab

Review GitLab merge requests locally or integrate the Tessl CLI into your own GitLab CI pipeline.

GitLab support is part of the Tessl CLI, available in version 0.113.0 and later. It isn't a GitLab app or a managed integration. You run `tessl code review` locally or add it to a GitLab CI pipeline you own. You configure the runner, credentials, and review cadence.

## Review locally

Install the [Tessl CLI](/introduction-to-tessl/set-up-tessl/installation.md), sign in with `tessl login`, and authenticate GitLab with `glab`:

```sh
glab auth login --hostname gitlab.com
```

From a checkout of the repository, review a merge request by URL:

```sh
tessl code review --pr https://gitlab.com/engteam/my-project/-/merge_requests/42
```

The CLI collects the title, description, commits, notes, inline discussions, replies, and discussion resolution state. It reviews the merge request's source commit, including when a CI checkout contains a merged result.

In a GitLab checkout, you can also use its merge request number:

```sh
tessl code review --pr 42
```

`--pr` selects both GitHub pull requests and GitLab merge requests. An explicit URL selects the provider and project. If your local fetch or push remotes include both GitHub and GitLab, use a full URL instead of a number. In GitLab merge request pipelines, `GITLAB_CI=true` and `CI_MERGE_REQUEST_PROJECT_PATH` select GitLab even with mixed remotes. Outside those pipelines, use a full URL when remotes are mixed.

For self-managed GitLab, use the full URL for your host, or set `GITLAB_HOST` to the checkout's host when using a number. Authenticate `glab` against that same host. Explicit Git ranges with `--base` and `--head` remain available without GitLab access.

## Publish findings and review again

By default, the review prints its result without publishing. Add `--publish comment` to post a summary and inline discussions:

```sh
tessl code review --pr 42 --publish comment
```

Findings GitLab can't anchor to the diff stay in the summary. Answer a finding in its discussion: addressed, refuted, or declined. Later reviews read the replies, reconcile earlier findings, and resolve or reopen discussions where appropriate. Rerunning against the same source commit and target diff reuses existing finding threads. Replies are read when you run the CLI again; comments alone don't trigger another review.

Publication checks the source and target revisions before writes. If either changes during the review, run a fresh review against the current merge request. When a review is asked to consult linked documents, its summary includes a collapsed record of which sources were fetched and which weren't.

`--publish verdict` currently falls back to a comment with an explicit notice. It doesn't submit native GitLab approvals or request-changes decisions, create a Tessl-owned status check, or configure merge gating. Your CI job decides whether the review result should fail the pipeline.

## Add a job to your GitLab CI pipeline

Configure these variables in **Settings > CI/CD > Variables** before adding the job:

| Variable       | Purpose                                                                                                                                          |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `TESSL_TOKEN`  | A [Tessl API key](/reference/cli-commands.md#tessl-api-key-create) for the workspace running the review.                                         |
| `GITLAB_TOKEN` | A GitLab access token that can read the merge request and publish discussions. Use the `api` scope for publication. `GL_TOKEN` is also accepted. |

A read-only review can use `read_api` instead of `api`. Fetching missing Git objects also requires repository read access through the checkout's Git credentials or the token. `CI_JOB_TOKEN` alone can't provide the full merge request context and discussion publication.

{% hint style="warning" %}
**This example is for trusted code only.** A merge request pipeline reads its CI configuration from the source branch. Starting a job manually and masking its output don't prevent that configuration from sending tokens elsewhere.

Store both tokens as **masked and protected** variables. Protect both the source and target branches, and restrict permission to push to them to people you trust with these credentials. Don't expose either token to fork pipelines or unprotected source branches. The job rules below select the intended pipelines; GitLab's protected-variable permissions enforce the credential boundary even if someone changes those rules.

For untrusted merge requests, use a separate review workflow whose CI configuration and runner setup come from a trusted branch. Supply the merge request URL as data. The example below doesn't implement that workflow.
{% endhint %}

This example requires GitLab 18.1 or later and the **Allow merge request pipelines to access protected variables and runners** setting. GitLab permits that access only when both branches are protected and belong to the same project, and the triggering user has push or merge access to the target branch. See [Control access to protected variables and runners](https://docs.gitlab.com/ci/pipelines/merge_request_pipelines/#control-access-to-protected-variables-and-runners).

Add this job to `.gitlab-ci.yml`, and add the `review` stage to your existing `stages` list:

```yaml
stages:
  - review

tessl_code_review:
  image: node:22
  stage: review
  variables:
    GIT_DEPTH: '0'
  rules:
    - if: >-
        $CI_PIPELINE_SOURCE == "merge_request_event" &&
        $CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED == "true" &&
        $CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED == "true" &&
        $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_MERGE_REQUEST_TARGET_PROJECT_ID
      when: manual
      allow_failure: true
  before_script:
    - curl -fsSL --connect-timeout 10 --max-time 120 https://install.tessl.io/scripts/0.113.0.sh -o /tmp/install-tessl.sh
    - timeout --kill-after=10s 120s sh /tmp/install-tessl.sh
    - export PATH="$HOME/.local/bin:$PATH"
  script:
    - tessl code review --publish comment --json > tessl-code-review.json
  artifacts:
    when: always
    paths:
      - tessl-code-review.json
```

This example makes the job manual and optional for protected source and target branches in the same project, so it doesn't hold a merge while waiting for a run. Start it from GitLab when you want a review. Remove `when: manual` to run it on every matching trusted pipeline. Keep the protected-branch and same-project restrictions. Your GitLab configuration must allow [merge request pipelines](https://docs.gitlab.com/ci/pipelines/merge_request_pipelines/).

No `--pr` is needed in a GitLab merge request pipeline: the CLI selects the MR from GitLab's predefined metadata. An explicit URL remains useful for jobs outside an MR pipeline. The job calls the CLI directly and doesn't use the GitHub Action or install a GitLab app.

The installer-script download has a 10-second connection limit and a 120-second transfer limit. The installer, including its own binary downloads, has a 120-second limit with a 10-second termination grace period. An installation failure can occur before the review JSON artifact exists.

`GIT_DEPTH: '0'` supplies complete history for merge-base calculation. In shallow checkouts, the CLI retrieves the selected ancestry without a depth limit; fetching has a 60-second timeout.

A completed review with findings can still exit successfully. This example publishes comments without gating on findings. If you want a gate, set `allow_failure: false`, inspect the JSON `status` first, then `outcome.approved` and `outcome.findings[].requiresChanges`, and configure the job's failure behavior yourself. A skipped review isn't an approval. A publication failure exits nonzero and preserves the completed outcome alongside its failure details.

To configure lenses and finding policy, pass `--profile ./.tessl-code-review.yml` in the job. The CLI doesn't discover that file automatically. See the [Code Review configuration reference](/reference/configuration.md#tessl-code-review-yml) and the [CLI reference](/reference/cli-commands.md#tessl-code-review).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.tessl.io/tutorials/setting-up-agentic-code-review/code-review-in-gitlab.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
