Agent skill
gitlab
GitLab API for repos and CI/CD. Use when user mentions "GitLab", "gitlab.com", shares a GitLab link, "GitLab repo", or asks about GitLab projects.
Install this agent skill to your Project
npx add-skill https://github.com/vm0-ai/vm0-skills/tree/main/gitlab
SKILL.md
GitLab API
Use the GitLab REST API via direct curl calls to manage projects, issues, merge requests, and pipelines.
Official docs:
https://docs.gitlab.com/ee/api/
When to Use
Use this skill when you need to:
- Manage projects - list, create, get project details
- Handle issues - create, update, close, list issues
- Work with merge requests - create, list, merge MRs
- Check pipelines - list jobs, view pipeline status
- Manage users - search users, get user info
Prerequisites
- Go to GitLab → User Settings → Access Tokens
- Create a personal access token with
apiscope - Copy the generated token
export GITLAB_HOST="gitlab.com" # Or your self-hosted GitLab domain
export GITLAB_TOKEN="glpat-xxxxxxxxxxxx" # Personal access token with api scope
Rate Limits
GitLab.com has rate limits of ~2000 requests per minute for authenticated users. Self-hosted instances may vary.
How to Use
All examples below assume GITLAB_HOST and GITLAB_TOKEN are set.
Base URL: https://${GITLAB_HOST}/api/v4
Note: Project IDs can be numeric (e.g.,
123) or URL-encoded paths (e.g.,mygroup%2Fmyproject).
1. Get Current User
Verify your authentication:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/user" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '{id, username, name, email, state}'
2. List Projects
Get projects accessible to you:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects?membership=true&per_page=20" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '.[] | {id, path_with_namespace, visibility, default_branch}'
Filter options:
membership=true- Only projects you're a member ofowned=true- Only projects you ownsearch=keyword- Search by namevisibility=public|internal|private- Filter by visibility
3. Get Project Details
Get details for a specific project. Replace <project-id> with the numeric project ID or URL-encoded path (e.g., mygroup%2Fmyproject):
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '{id, name, path_with_namespace, default_branch, visibility, web_url}
4. List Project Issues
Get issues for a project. Replace <project-id> with the numeric project ID or URL-encoded path:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues?state=opened&per_page=20" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '.[] | {iid, title, state, author: .author.username, labels, web_url}'
Filter options:
state=opened|closed|all- Filter by statelabels=bug,urgent- Filter by labelsassignee_id=123- Filter by assigneesearch=keyword- Search in title/description
5. Get Issue Details
Get a specific issue. Replace <project-id> and <issue-iid> with actual values:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues/<issue-iid>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '{iid, title, description, state, author: .author.username, assignees: [.assignees[].username], labels, created_at, web_url}'
6. Create Issue
Create a new issue in a project. Replace <project-id> with the actual project ID:
Write to /tmp/gitlab_request.json:
{
"title": "Bug: Login page not loading",
"description": "The login page shows a blank screen on mobile devices.",
"labels": "bug,frontend"
}
Then run:
curl -s -X POST "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, web_url}'
7. Create Issue with Assignee and Milestone
Create issue with additional fields. Replace <project-id>, <assignee-id>, and <milestone-id> with actual IDs:
Write to /tmp/gitlab_request.json:
{
"title": "Implement user profile page",
"description": "Create a user profile page with avatar and bio.",
"assignee_ids": [<assignee-id>],
"milestone_id": <milestone-id>,
"labels": "feature,frontend"
}
Then run:
curl -s -X POST "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, web_url}'
8. Update Issue
Update an existing issue. Replace <project-id> and <issue-iid> with actual values:
Write to /tmp/gitlab_request.json:
{
"title": "Updated: Bug fix for login page",
"labels": "bug,frontend,in-progress"
}
Then run:
curl -s -X PUT "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues/<issue-iid>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, labels, updated_at}'
9. Close Issue
Close an issue. Replace <project-id> and <issue-iid> with actual values:
Write to /tmp/gitlab_request.json:
{
"state_event": "close"
}
Then run:
curl -s -X PUT "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues/<issue-iid>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, state}'
Use "state_event": "reopen" to reopen a closed issue.
10. Add Comment to Issue
Add a note/comment to an issue. Replace <project-id> and <issue-iid> with actual values:
Write to /tmp/gitlab_request.json:
{
"body": "Investigating this issue. Will update soon."
}
Then run:
curl -s -X POST "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues/<issue-iid>/notes" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{id, body, author: .author.username, created_at}'
11. List Merge Requests
Get merge requests for a project. Replace <project-id> with the actual project ID:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/merge_requests?state=opened&per_page=20" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '.[] | {iid, title, state, source_branch, target_branch, author: .author.username, web_url}'
Filter options:
state=opened|closed|merged|all- Filter by statescope=created_by_me|assigned_to_me|all- Filter by involvementlabels=review-needed- Filter by labels
12. Get Merge Request Details
Get a specific merge request. Replace <project-id> and <mr-iid> with actual values:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/merge_requests/<mr-iid>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '{iid, title, state, source_branch, target_branch, author: .author.username, merge_status, has_conflicts, web_url}'
13. Create Merge Request
Create a new merge request. Replace <project-id> with the actual project ID:
Write to /tmp/gitlab_request.json:
{
"source_branch": "feature/user-profile",
"target_branch": "main",
"title": "Add user profile page",
"description": "This MR adds a new user profile page with avatar support."
}
Then run:
curl -s -X POST "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/merge_requests" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, web_url}'
14. Merge a Merge Request
Merge an MR (if it's ready). Replace <project-id> and <mr-iid> with actual values:
Write to /tmp/gitlab_request.json:
{
"merge_when_pipeline_succeeds": true
}
Then run:
curl -s -X PUT "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/merge_requests/<mr-iid>/merge" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{iid, title, state, merged_by: .merged_by.username}'
Options:
merge_when_pipeline_succeeds=true- Auto-merge when pipeline passessquash=true- Squash commits before mergingshould_remove_source_branch=true- Delete source branch after merge
15. List Pipelines
Get pipelines for a project. Replace <project-id> with the actual project ID:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/pipelines?per_page=10" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '.[] | {id, status, ref, sha: .sha[0:8], created_at, web_url}'
16. Get Pipeline Details
Get details of a specific pipeline. Replace <project-id> and <pipeline-id> with actual values:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/pipelines/<pipeline-id>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '{id, status, ref, duration, finished_at, web_url}'
17. List Pipeline Jobs
Get jobs in a pipeline. Replace <project-id> and <pipeline-id> with actual values:
curl -s "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/pipelines/<pipeline-id>/jobs" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" | jq '.[] | {id, name, stage, status, duration}'
18. Search Users
Search for users:
Write to /tmp/gitlab_search.txt:
john
curl -s -G "https://$(printenv GITLAB_HOST)/api/v4/users" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --data-urlencode "search@/tmp/gitlab_search.txt" | jq '.[] | {id, username, name, state}'
19. Create Project
Create a new project:
Write to /tmp/gitlab_request.json:
{
"name": "my-new-project",
"visibility": "private",
"initialize_with_readme": true
}
Then run:
curl -s -X POST "https://$(printenv GITLAB_HOST)/api/v4/projects" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" --header "Content-Type: application/json" -d @/tmp/gitlab_request.json | jq '{id, path_with_namespace, web_url}'
20. Delete Issue
Delete an issue (requires admin or owner permissions). Replace <project-id> and <issue-iid> with actual values:
curl -s -X DELETE "https://$(printenv GITLAB_HOST)/api/v4/projects/<project-id>/issues/<issue-iid>" --header "PRIVATE-TOKEN: $(printenv GITLAB_TOKEN)" -w "\nHTTP Status: %{http_code}"
Returns 204 No Content on success.
Project ID Encoding
When using project paths instead of numeric IDs, URL-encode the path:
mygroup/myproject→mygroup%2Fmyprojectmygroup/subgroup/myproject→mygroup%2Fsubgroup%2Fmyproject
# Using numeric ID
PROJECT_ID="123"
# Using encoded path
PROJECT_ID="mygroup%2Fmyproject"
Guidelines
- Use IID for issues/MRs: Within a project, use
iid(internal ID like #1, #2) not the globalid - URL-encode project paths: If using paths instead of numeric IDs, encode slashes as
%2F - Handle pagination: Use
per_pageandpageparams for large result sets - Check merge status: Before merging, verify
merge_statusiscan_be_merged - Rate limiting: Implement backoff if you receive 429 responses
- Self-hosted GitLab: Set
GITLAB_HOSTto your instance domain (without https://)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
brave-search
Brave Search API for web search. Use when user says "search web", "Brave search", or asks to "find on web" without specifying Google.
supadata
Supadata API for YouTube/web data. Use when user mentions "Supadata", "YouTube data", "channel stats", or web scraping data.
roadmap-planning
Build and prioritize product roadmaps using scoring models like RICE, ICE, and value-effort matrices. Activate when creating a product roadmap, prioritizing features, sequencing initiatives, mapping dependencies, balancing team capacity, choosing between Now/Next/Later or quarterly planning, or communicating roadmap tradeoffs to executives and stakeholders.
qdrant
Qdrant API for vector search. Use when user mentions "Qdrant", "vector database", "semantic search", or embeddings storage.
calendly
Calendly scheduling API. Use when user mentions "Calendly", "calendly.com", "schedule a meeting", "booking link", "event types", or asks about interview scheduling.
stripe
Stripe API for payments. Use when user mentions "Stripe", "payment", "subscription", "billing", "invoice", or asks about payment processing.
Didn't find tool you were looking for?