# GitLab

## What it does

The GitLab integration connects Speedwave to a GitLab instance so it can read repositories, work on merge requests, run and inspect pipelines, and manage issues, branches, and releases. It works with both GitLab.com and self-hosted GitLab, for tasks like [code review](/docs/features/code-review/) on merge requests, checking why a pipeline failed, or opening an issue from a conversation.

## What it consists of

GitLab is a built-in worker: Speedwave enables it per project from the Desktop app and runs it in its own container. You authenticate with a GitLab Personal Access Token and give the instance URL, so the same integration can point at GitLab.com or your own server. The token and URL are the only credentials it holds.

## How it works

Speedwave stores the URL and token under `~/.speedwave/tokens/<project>/gitlab/` and mounts them into the GitLab worker container, read-only. Credentials and target server travel together with the project. See [How credentials are handled](/docs/security/credentials/) for how this mount stays isolated from other workers.

When something fails, the worker maps common GitLab errors to plain guidance: `401` means an invalid or expired token, `403` means insufficient permission, `404` means the item wasn't found, `5xx` means a GitLab server error, and a network error means the worker couldn't reach the configured URL.

## What it can do

The worker exposes 46 tools. Destructive ones ask for confirmation before they run.

| Tool | What it does |
| --- | --- |
| `listProjectIds`, `getProjectFull` | List accessible projects, then fetch full details for one. |
| `searchCode` | Search code across every project you can access, or inside one. |
| `getTree`, `getFile` | Browse a repository's file tree and read a file's content. |
| `getBlame` | Return line-level git blame, one place GitLab goes further than GitHub. |
| `listBranches`, `getBranch`, `compareBranches` | List branches, inspect one, or diff two branches or commits. |
| `createBranch` | Create a branch from a ref. |
| `deleteBranch` (destructive) | Delete a branch. Fails on a protected branch. |
| `listCommits`, `listBranchCommits`, `getCommitDiff` | List commits with filters, list commits on a branch, or get one commit's diff. |
| `searchCommits` | Search commit messages. Filters client-side, since GitLab has no direct commit-search API. |
| `listMrIds`, `getMrFull`, `getMrChanges` | List merge request IDs, fetch full MR data, or get its diff. |
| `createMergeRequest`, `updateMergeRequest` | Open a merge request or edit an existing one. |
| `approveMergeRequest` (destructive) | Approve a merge request. |
| `mergeMergeRequest` (destructive) | Merge a merge request, with options to squash commits, remove the source branch, and set auto-merge. |
| `listMrCommits`, `listMrPipelines` | List the commits or pipelines tied to a merge request. |
| `listMrNotes`, `createMrNote` | List or add comments on a merge request. |
| `listMrDiscussions`, `createMrDiscussion` | List or start a threaded discussion on a merge request. |
| `listPipelineIds`, `getPipelineFull` | List pipeline IDs, then fetch full pipeline data. |
| `getJobLog` | Return a job's log inline: the last 100 lines by default, or the whole log with `0`. |
| `retryPipeline` | Retry a failed pipeline. |
| `triggerPipeline` (destructive) | Start a new pipeline run on a ref, with optional variables. |
| `listArtifacts`, `downloadArtifact` | List a pipeline's job artifacts, or fetch one. `downloadArtifact` has the worker fetch the content itself (today the job's log, not the artifact archive), returned as filename and size. |
| `deleteArtifacts` (destructive) | Delete a job's artifacts. |
| `listIssues`, `getIssue` | List project issues or fetch one. |
| `createIssue`, `updateIssue`, `closeIssue` | Open, edit, or close an issue. |
| `listLabels`, `createLabel` | List project labels or create one. |
| `createTag` | Create a Git tag. |
| `deleteTag` (destructive) | Delete a Git tag. |
| `createRelease` | Build a release from an existing tag. Create the tag first with `createTag`. |

## Set it up

1. In the Desktop app, open the project where you want GitLab, then open its integrations and select **GitLab**.

2. Enter the **GitLab URL**: `https://gitlab.com` for GitLab.com, or your server's address for a self-hosted instance, for example `https://gitlab.example.com`. Leave it blank and the worker defaults to `https://gitlab.com`.

   The worker resolves the host in this order: the stored URL file first, then a `GITLAB_URL` environment variable, then the `https://gitlab.com` default. If pipelines hit the wrong instance, check which of these set the URL.

3. Paste your **Personal Access Token** (it starts with `glpat-`). Create one from your GitLab profile's **Access Tokens** page: set a name and expiry, select scopes, and copy the token, since GitLab shows it only once.

4. Save. Speedwave stores the credentials and enables the integration. The first time you turn it on, Speedwave builds the GitLab worker image, so that start takes longer.

<DesktopFrame screen="integrations" />

If you reopen the credentials form and leave the token field blank, Speedwave keeps the token already stored. Type a new one only to replace it.
**Token scopes:** Create the token with the scopes the integration needs: setup guidance recommends `api`, `read_repository`, and `write_repository`. Speedwave does not validate scopes when you save the token, so a missing scope shows up later as a `403` from GitLab. Scope names vary by GitLab version, so check your instance's token documentation first.

## Security boundaries

The GitLab worker holds nothing but its own credentials, mounted read-only into its container. [The hub holds zero tokens; it just routes calls to the right worker.](/docs/under-the-hood/tool-gateway/) The integration is bound by whatever the Personal Access Token's scopes allow, so a read-only token cannot merge requests or push changes, and `deleteBranch` still respects GitLab's own branch protection.