Automate GitLab merge requests with Claude Code
This document explains how the merge request (GitLab) and pull request (GitHub) creation functionality works after Claude Code makes edits to your repository.
The system can create merge requests (GitLab) or pull requests (GitHub) after Claude Code makes changes to your workspace. The provider is automatically detected from the repository URL.
For edit requests submitted via POST /api/edit with createMR: true, git workflow + MR/PR creation runs inside the queue job.
Add these to your .env file depending on your git provider:
For GitLab repositories:
GITLAB_TOKEN=your_gitlab_personal_access_token GITLAB_URL=https://gitlab.com
Note: Use your GitLab instance URL if self-hosted
For GitHub repositories:
GITHUB_TOKEN=your_github_personal_access_token
api (full API access)write_repository (push code, create MRs)repo (full repository access)The system automatically detects your git provider from the repository URL:
github.com or github. → GitHub (creates Pull Request)gitlab.com or gitlab. → GitLab (creates Merge Request)After Claude Code completes any changes to your workspace:
The system automatically detects:
sourceBranch === targetBranch, the system will create a unique feature branch automaticallysourceBranchMR metadata is generated automatically by the server (title/description include timestamps and commit info).
If you need fully custom MR metadata, that would be a follow-up enhancement to pass title/description through the /api/edit payload.
import { createMergeRequest } from '@/lib/gitlab';
const result = await createMergeRequest({
projectId: 'your-project-id',
title: 'Your MR Title',
description: 'Your detailed description of changes',
sourceBranch: 'feature-branch',
targetBranch: 'main',
labels: ['enhancement', 'claude-code'],
});
import { createPullRequest } from '@/lib/github';
const result = await createPullRequest({
owner: 'repository-owner',
repo: 'repository-name',
title: 'Your PR Title',
body: 'Your detailed description of changes',
head: 'feature-branch',
base: 'main',
});
| Option | Type | Description | Default |
|---|---|---|---|
projectId | string | GitLab project ID | Required |
title | string | Manual MR title | Required |
description | string | Manual MR description | Required |
sourceBranch | string | Source branch name | Required |
targetBranch | string | Target branch for MR | main |
removeSourceBranch | boolean | Delete source branch after merge | true |
squash | boolean | Squash commits when merging | false |
assigneeId | number | GitLab user ID to assign | none |
labels | string[] | Labels to add to MR | [] |
| Option | Type | Description | Default |
|---|---|---|---|
owner | string | Repository owner/org | Required |
repo | string | Repository name | Required |
title | string | Pull request title | Required |
body | string | Pull request description | Required |
head | string | Source branch name | Required |
base | string | Target branch for PR | main |
draft | boolean | Create as draft PR | false |
token | string | GitHub token (if not in UI) | none |
The system gracefully handles errors:
If GitLab token is missing (for GitLab repos):
{
"autoMRDisabled": true,
"warning": "GitLab token not configured - merge request creation skipped"
}
If GitHub token is missing (for GitHub repos):
{
"autoMRDisabled": true,
"warning": "GitHub token not configured - pull request creation skipped"
}
If MR/PR creation fails but Claude Code succeeds:
{
"success": true,
"response": "Claude response...",
"postExecution": {
"hasChanges": true,
"pushedBranch": "feature/branch",
"mergeRequestUrl": null
}
}
"GitLab token not configured"
GITLAB_TOKEN is set in environment or configured via Dashboard UIapi and write_repository scopes"GitHub token not configured"
GITHUB_TOKEN is set in environment or configured via Dashboard UIrepo scope"Auto mode is deprecated"
"Failed to extract project ID" (GitLab)
"Could not extract owner/repo" (GitHub)
https://github.com/owner/repo)"No current branch found"
auto parameter in createMergeRequest is deprecated