---
title: GitLab SCM
description: Merge requests, discussions, and pipelines via the glab CLI.
---

<div style={{ display: "flex", alignItems: "center", gap: "0.75rem", margin: "0.5rem 0 1.25rem" }}>
	<Logo name="gitlab" size={28} color />
	<span style={{ fontSize: "0.8125rem", color: "var(--color-fd-muted-foreground)" }}>
		Slot: <code>scm</code> · Name: <code>gitlab</code>
	</span>
</div>

<PlatformSupport macos="full" linux="full" windows="full" />

## Setup

```bash
glab auth login
```

```yaml title="agent-orchestrator.yaml"
scm: gitlab
scmConfig:
  host: gitlab.com # default; override for self-hosted
```

## Mapping

| Concept        | GitHub term  | GitLab term       |
| -------------- | ------------ | ----------------- |
| Review request | Pull request | Merge request     |
| Review         | Review       | Discussion / note |
| CI status      | Check runs   | Pipelines / jobs  |

AO normalises these internally — the dashboard and lifecycle state machine don't know which you use.

## Webhook endpoint

AO's dashboard receives webhook events at:

```
POST /api/webhooks
```

The absolute URL is `https://<your-ao-host>/api/webhooks`. To expose your local dashboard publicly, see [Remote access](/docs/configuration/remote-access).

### GitLab project settings

In your GitLab project go to **Settings → Webhooks → Add new webhook**:

- **URL**: `https://<your-ao-host>/api/webhooks`
- **Secret token**: the value of your `secretEnvVar` environment variable
- **Trigger events**: Merge request events, Pipeline events, Push events, Note events (review comments)

### Config

```yaml
scm: gitlab
projects:
  myproject:
    repo: group/project
    scm:
      webhook:
        secretEnvVar: GITLAB_WEBHOOK_TOKEN # env var holding the token
```

Full `webhook.*` sub-object:

| Field             | Default               | Description                              |
| ----------------- | --------------------- | ---------------------------------------- |
| `enabled`         | `true`                | Enable or disable webhook processing     |
| `path`            | `/api/webhooks`       | Override the receive path                |
| `secretEnvVar`    | —                     | Name of the env var holding the token    |
| `signatureHeader` | `x-gitlab-token`      | Header carrying the secret token         |
| `eventHeader`     | `x-gitlab-event`      | Header carrying the event type           |
| `deliveryHeader`  | `x-gitlab-event-uuid` | Header carrying the delivery UUID        |
| `maxBodyBytes`    | unlimited             | Reject payloads larger than this (bytes) |

**Verification**: GitLab sends the configured secret as a literal string in `X-Gitlab-Token`. AO compares this value directly (no HMAC — unlike GitHub's SHA-256 approach).

Polling is still active as a fallback — webhooks are a latency optimisation, not a hard dependency.

## Automated review authors

AO ignores review comments from known bot accounts so they don't block the merge-readiness check. The full list:

**Hardcoded bots:**

| Username           |
| ------------------ |
| `gitlab-bot`       |
| `ghost`            |
| `dependabot[bot]`  |
| `renovate[bot]`    |
| `sast-bot`         |
| `codeclimate[bot]` |
| `sonarcloud[bot]`  |
| `snyk-bot`         |

**Runtime catch-all:** any username matching `/^project_\d+_bot/` (GitLab project access tokens) or ending in `[bot]`.

See [Review loop — bot detection](/docs/guides/review-loop#automated-review-bugbot-detection) for how AO uses this list during the review-pending → mergeable transition.
