| name | glab |
| description | Automate GitLab issue, merge request, epic, and work-item workflows with glab. Use for viewing or updating GitLab metadata, creating or editing issues and MRs, handling epic comments through GraphQL, and other CLI or API-driven GitLab operations in the GitLab repo workflow. |
| license | MIT |
| compatibility | opencode |
| metadata | {"audience":"developers","author":"pedropombeiro","keywords":"gitlab, glab, merge-requests, issues, epics, work-items","workflow":"gitlab"} |
GitLab Workflow Skill
GitLab workflow management using glab CLI for merge requests, issues, and Git best practices.
For standard GitLab.com MR creation, prefer gpsup from the mr-workflow skill — it
applies project defaults like milestone and labels automatically. Run it via
run-in-tmux-pane.
Creating Merge Requests
run-in-tmux-pane gpsup
glab mr create --title "feat: add feature" --description "Brief description"
glab mr create --title "feat: add feature" --description "$(cat /tmp/mr-description.md)"
Templates: Check .gitlab/merge_request_templates/ for project-specific templates.
Use glab mr create only when gpsup is unavailable or the remote is not GitLab.com.
Updating Merge Requests
glab mr update <number> --description "$(cat /tmp/description.md)"
glab mr view <number> -R <owner>/<repo>
Issue Management
glab issue view <number>
glab issue view <number> --comments -R <owner>/<repo>
glab issue note <number> -m "comment" -R <owner>/<repo>
glab issue note <number> -m "$(cat /tmp/comment.md)" -R <owner>/<repo>
glab issue list --label "priority::P1,status::doing" -R <owner>/<repo>
glab issue list --closed -R <owner>/<repo>
glab issue list --all -R <owner>/<repo>
glab issue create --title "Bug: title" --description "$(cat /tmp/issue-description.md)"
glab issue update 123 --label "new-label"
glab issue update 123 --unlabel "old-label"
glab issue update 123 --label "status::doing"
Issue State Transitions and Notes
glab api --method PUT "projects/<project_id>/issues/<iid>" -f state_event=close
glab api --method PUT "projects/<project_id>/issues/<iid>" -f state_event=reopen
glab api --method POST "projects/<project_id>/issues/<iid>/notes" -f "body=Your comment"
glab api --method POST "projects/<project_id>/issues/<iid>/notes" \
-f "body=$(cat /tmp/comment.md)"
Work Items
GitLab is migrating issues to work items. The URL shows /work_items/<iid> but the REST API is the same.
glab api "projects/org%2Fproject/issues/<iid>"
glab api "projects/<project_id>/issues/<iid>/notes"
glab api "projects/org%2Fproject/work_items/<iid>"
URL parsing: https://gitlab.com/org/project/-/work_items/539076
→ glab api "projects/org%2Fproject/issues/539076"
Full details, GraphQL alternative, and group-level work items: references/work-items.md
Issue Links and Epics
Epics — Critical Notes
⚠️ Epic comments require GraphQL — the REST /notes endpoint returns 404.
Quickest path — use the wrapper scripts:
- From the repo root, use
.opencode/skills/glab/scripts/....
- From this skill's base directory,
scripts/... is equivalent.
- Do not assume bundled scripts are on
PATH.
.opencode/skills/glab/scripts/epic-notes.sh <group-path> <epic-iid>
.opencode/skills/glab/scripts/epic-notes.sh gitlab-org 16428
.opencode/skills/glab/scripts/create-epic-note.sh <group-id> <epic-iid> "body"
.opencode/skills/glab/scripts/create-epic-note.sh 9970 16428 "My comment"
Scripts are in scripts/; GraphQL templates in assets/graphql/.
Manual GraphQL (when you need more control):
glab api graphql -f query='
{
group(fullPath: "gitlab-org") {
workItem(iid: "16428") {
widgets {
type
... on WorkItemWidgetNotes {
discussions(first: 100) {
pageInfo { hasNextPage endCursor }
nodes {
notes {
nodes { id body author { username } createdAt }
}
}
}
}
}
}
}
}'
Epic close/reopen — REST works fine, no GraphQL needed:
glab api --method PUT "groups/<group_id>/epics/<iid>" -f state_event=close
glab api --method PUT "groups/<group_id>/epics/<iid>" -f state_event=reopen
Nested groups — REST requires %2F; GraphQL uses plain /:
glab api "groups/gitlab-org%2Ffoundations/epics"
glab api "groups/gitlab-org/foundations/epics"
glab api graphql -f query='{ group(fullPath: "gitlab-org/foundations") { ... } }'
MR Listing and Filtering
glab mr list -R <owner>/<repo>
glab mr list -R <owner>/<repo> --assignee <user>
glab mr list -R <owner>/<repo> --all
glab mr list -R <owner>/<repo> --merged
glab mr list -R <owner>/<repo> --closed
glab mr list -R <owner>/<repo> --author <user>
Note: glab mr list has no --state or --status flag. Use --all, --merged, --closed.
Pipeline Monitoring
glab ci status
glab ci view
glab ci list
glab ci get <pipeline-id>
glab ci trace <job-id>
In non-interactive environments (e.g. AI agents): Use the gitlab_get_pipeline MCP tool to poll pipeline status, since glab ci view requires a TTY.
GLQL Queries
To query issues, MRs, or epics across projects/groups, load the glab-glql skill.
Git Best Practices
git checkout -b feat/description
git checkout -b fix/description
Agent Guidelines
- Read context first —
glab issue view / glab mr view before implementing
- Use project templates — check
.gitlab/issue_templates/ and .gitlab/merge_request_templates/
- Write descriptions to files — use
$(cat /tmp/description.md) not inline strings
- Reference with full URLs —
Closes https://gitlab.com/org/project/-/issues/123
- Descriptive commits — focus on the "why"
- Single quotes for special chars —
git commit -m 'fix: from MR !123'
- Label syntax —
--label to add, --unlabel to remove; never +label/-label
- Scoped labels —
--label "status::doing" auto-removes old status::*; no --unlabel needed
- No
--jq flag — glab has no --jq; use | jq '...' pipe
- No
--state/--status on mr list — use --all, --merged, --closed
- Work items use the issues API —
/work_items/<iid> URLs → projects/.../issues/<iid>
- Epic comments need GraphQL — REST
/notes → 404; use epic-notes.sh or manual GraphQL with first: 100 + pagination
- No
-R for group-level API — -R expects OWNER/REPO; group endpoints use glab api "groups/..." directly
- Nested groups REST:
%2F — groups/org%2Fsubgroup/epics; unencoded slashes → 404
- GraphQL iid is a String —
workItem(iid: "16428") not workItem(iid: 16428)
groups/<id>/work_items is 404 — use groups/<id>/epics (REST) or GraphQL
project.workItems not project.workItem — singular doesn't exist; use workItems(first: 1, iid: "IID"); no filter: argument
- Epic close/reopen via REST —
state_event=close/reopen on PUT groups/<id>/epics/<iid> works; no GraphQL needed
- Prefer
gpsup for MR creation — see scm.md for details; applies milestone/labels automatically
- Fill in the MR description after creation — open the new MR and update it using the default template in
.gitlab/merge_request_templates/
- Prefer structured output for agents — use
glab api or JSON-capable commands when you need fields, not human-oriented terminal presentation