| name | glab-cli |
| description | GitLab CLI (glab) integration for managing repositories, merge requests, CI/CD pipelines, variables, and runners on self-managed GitLab instances. Use when working with GitLab - authentication issues ("token expired", "unauthorized"), repo operations ("create repo", "clone"), merge requests ("create MR", "view MR", "code review"), CI/CD pipelines ("check CI", "view job logs", "trigger job", "download artifacts"), variables ("list variables", "set variable"), or runners ("list runners"). |
GitLab CLI (glab) Integration
Manage GitLab repositories, merge requests, CI/CD, variables, and runners with glab CLI.
Prerequisites
glab auth status
If authentication fails, see Authentication Setup.
General Rules
- Prefer native
glab commands over glab api — native commands handle URL encoding via -R <repo>.
- Strip ANSI codes when analyzing job logs:
| sed 's/\x1b\[[0-9;]*m//g'
- Avoid TUI commands (
glab ci view) — crashes in non-interactive environments.
- URL encoding: When using
glab api, encode / as %2F in project paths.
- JSON output: Use
--output=json or -F json with jq for scripting and automation.
- API pagination: Use
glab api --paginate "endpoint?per_page=100" to auto-fetch all pages.
- Repo context: glab auto-detects repo from git remote; use
-R owner/repo when outside a repo directory.
Quick Reference
| Task | Command |
|---|
| Auth status | glab auth status |
| Check token expiry | glab api personal_access_tokens/self | jq '{name, expires_at}' |
| Rotate token | ~/.claude/skills/glab-cli/scripts/rotate-gitlab-token --yes |
| Create repo | glab repo create <name> --group <group> |
| Clone repo | glab repo clone <owner/repo> |
| Create MR | glab mr create |
| List MRs | glab mr list |
| View MR | glab mr view <id> |
| Add MR comment | glab mr note <id> -m "comment" |
| List pipelines | glab ci list -R <repo> |
| Pipeline info | glab ci get -p <id> -R <repo> -F json |
| Pipeline jobs | glab ci get -p <id> -R <repo> --with-job-details -F json |
| View job log | glab ci trace <job-id> -R <repo> |
| Trigger manual job | glab ci trigger <job-id> -R <repo> (find job ID from pipeline first) |
| Download artifacts (latest) | glab job artifact <branch> <job-name> -R <repo> |
| Download artifacts (by job ID) | glab api /projects/<path>/jobs/<id>/artifacts > file.zip |
| List variables | glab variable list |
| Set variable | glab variable set <key> <value> |
| List runners | glab api projects/:fullpath/runners (no native cmd) |
Authentication Setup
Check Status
glab auth status
Token Expired or Not Initialized
If you see token expired, unauthorized, or failed to authenticate:
Step 1: Create a Personal Access Token
- Open: https://gitlab.domain.com/-/user_settings/personal_access_tokens
- Create token with scopes:
api and write_repository
- Copy the token immediately
Step 2: Authenticate
echo "<YOUR_TOKEN>" | glab auth login --hostname gitlab.domain.com --stdin --git-protocol ssh
Step 3: Verify
glab auth status
Token Rotation (Auto-Renew Before Expiry)
IMPORTANT — Proactive Token Rotation:
When any glab command fails with token expired, 401 Unauthorized, or failed to authenticate, first attempt to rotate the token automatically before asking the user to manually create one.
Check token expiry:
glab api personal_access_tokens/self --hostname gitlab.domain.com | jq '{name, expires_at, active, scopes}'
Rotate using the bundled script:
~/.claude/skills/glab-cli/scripts/rotate-gitlab-token --hostname gitlab.domain.com --yes
- The
--yes flag skips the interactive confirmation (required for agent use).
- The script rotates the current token, sets a new expiry date 1 year from today, and automatically updates
glab auth.
- The old token is immediately revoked after rotation.
- Requires GitLab 16.0+ for the Rotation API.
When rotation fails (token already expired or GitLab < 16.0), fall back to the manual flow above.
Refresh OAuth Token
glab auth refresh --hostname gitlab.domain.com
Note: Only works for OAuth (interactive login), not PAT (--stdin).
Repository Management
Create Repository
IMPORTANT: Correct syntax for nested groups
glab repo create my-project --group parent/child/subgroup --private
glab repo create parent/child/subgroup/my-project
Examples:
glab repo create my-project
glab repo create my-project --group my-group
glab repo create packer-lab \
--group my-org/my-team/my-subgroup \
--description "Project description" \
--private \
--defaultBranch main
After creating, glab initializes a new git repo in ./my-project/. If you already have a local repo:
rm -rf ./my-project
git remote add origin git@gitlab.domain.com:group/my-project.git
git push -u origin main
Visibility: --private | --public | --internal
Find Available Groups
glab api "groups?search=devops" | jq -r '.[] | "\(.full_path) (id: \(.id))"'
glab api groups --paginate | jq -r '.[] | .full_path'
Clone Repository
glab repo clone owner/repo
glab repo clone owner/repo target-dir
glab repo clone -g group-name
Fork & View
glab repo fork owner/repo
glab repo view
glab repo view --web
Merge Request Operations
Create MR
glab mr create
glab mr create --title "feat: add feature" --description "desc"
glab mr for 123
List MRs
glab mr list
glab mr list --assignee=@me
glab mr list --reviewer=@me
glab mr list --state merged --author @me
View & Checkout
glab mr view 123
glab mr view 123 --web
glab mr diff 123
glab mr checkout 123
Code Review (CE Compatible)
glab mr note 123 -m "LGTM! Nice work."
glab mr merge 123
glab mr merge 123 --squash
glab mr merge 123 --when-pipeline-succeeds
glab mr close 123
glab mr reopen 123
Inline Comment (via API)
glab api projects/:fullpath/merge_requests/123/discussions \
--method POST \
-f body="Comment here" \
-f "position[base_sha]=<base>" \
-f "position[head_sha]=<head>" \
-f "position[start_sha]=<start>" \
-f "position[position_type]=text" \
-f "position[new_path]=file.go" \
-f "position[new_line]=42"
Get SHA values: glab mr view 123 --json diffRefs
Premium/EE Only
glab mr approve 123
glab mr revoke 123
CI/CD Pipeline & Jobs
For complete reference including all commands, monitoring patterns, artifacts, and debugging workflows, see references/cicd-pipelines.md.
Triggering Jobs — Correct Workflow
IMPORTANT: Do NOT use glab ci run to trigger jobs. glab ci run creates a brand new pipeline via API, which is commonly blocked by workflow:rules (e.g., rules that only allow push or schedule sources). This results in 400 Pipeline filtered out by workflow rules errors.
Instead, always follow this sequence:
-
Check if a pipeline already exists (push events auto-create pipelines):
glab ci list --per-page 3 -F json | jq '.[] | {id, status, ref}'
-
Find the target job in the latest pipeline:
glab ci get -p <pipeline-id> --with-job-details -F json | jq '.jobs[] | {id, name, status, stage}'
-
Trigger the manual job by job ID:
glab ci trigger <job-id>
When to use glab ci run: Only when you need to create a pipeline on a branch that has no recent pipeline AND the project's workflow:rules allow API-triggered pipelines. This is rare — most projects restrict pipeline creation to push/schedule/MR events.
Most Common Operations
glab ci list --per-page 5
glab ci get -p <pipeline-id> -R <repo> -F json
glab ci get -p <pipeline-id> -R <repo> --with-job-details -F json | jq '.jobs[] | {id, name, status, stage}'
glab ci trace <job-id> -R <repo> | sed 's/\x1b\[[0-9;]*m//g'
glab ci trigger <job-id> -R <repo>
glab ci retry <job-id> -R <repo>
glab job artifact <branch> <job-name> -R <repo>
glab api /projects/<url-encoded-path>/jobs/<job-id>/artifacts > artifacts.zip
glab ci lint
Note: glab job artifact only downloads from the latest pipeline of a branch. For specific job IDs, use the API.
CI/CD Variables
glab variable list
glab variable get MY_VAR
glab variable set MY_VAR "value"
glab variable delete MY_VAR
glab variable set MY_VAR "value" --protected
glab variable set MY_VAR "value" --masked
glab variable set MY_VAR "value" --scope production
glab variable set MY_CERT --value-file /path/to/cert.pem
glab variable export > variables.json
glab variable import < variables.json
Runner Status (via API)
No native runner command exists. Use glab api.
glab api projects/:fullpath/runners | jq '.[] | {id, description, status, is_shared}'
glab api projects/:fullpath/runners --field status=online
glab api runners/<runner-id>
glab api runners/<runner-id>/jobs
glab api groups/<group-id>/runners
Errors & Debugging
For common error solutions (401, HTTP 405, namespace not found, TUI panic, URL encoding), see references/troubleshooting.md.
For CI/CD failure debugging workflow (list pipelines -> find failed jobs -> view logs -> retry), see references/cicd-pipelines.md.