--- name: gitlab-ops user-invocable: false tags: [reference, vcs, gitlab, github, issues] model: haiku model-preference: sonnet model-preference-codex: gpt-5.4-mini model-preference-cursor: claude-sonnet-4-6 description: Use this skill when performing VCS operations on GitLab or GitHub repositories — creating, updating, or closing issues and MRs, applying label taxonomy, running `glab`/`gh` CLI commands, or resolving project IDs dynamically. Acts as the single source of truth for CLI command syntax and label conventions; consuming skills reference this rather than duplicating logic. Triggers: "create a GitLab issue", "list open MRs", "apply priority label", "how do I resolve the project ID", "what's the carryover issue template". Context: session-end needs to file a carryover issue for an incomplete task. user: "/close" assistant: "Creating carryover issue via glab with the Carryover Template from gitlab-ops — labels: carryover, priority:high." --- # VCS Operations Reference ## VCS Auto-Detection Detect which VCS platform the current repo uses and select the right CLI: ```bash # Check git remote REMOTE_URL=$(git remote get-url origin 2>/dev/null) if echo "$REMOTE_URL" | grep -q "github.com"; then VCS=github # use `gh` else VCS=gitlab # use `glab` fi ``` **Session Config overrides:** - `vcs: github|gitlab` — force a specific platform - `gitlab-host: ` — override auto-detected GitLab host (glab reads host from git remote by default) ## How Other Skills Reference This **Directive:** Consuming skills MUST NOT duplicate VCS auto-detection logic or CLI command syntax inline. This skill is the single source of truth for all VCS operations. When a skill needs VCS operations, include this reference block in its instructions: > **VCS Reference:** Detect the VCS platform per the "VCS Auto-Detection" section of the gitlab-ops skill. > Use CLI commands per the "Common CLI Commands" section. For cross-project queries, see "Dynamic Project Resolution." **Canonical commands:** All `glab` and `gh` command syntax — flags, output formats, pagination options — is defined in the "Common CLI Commands" section below. Consuming skills must reference that section rather than redefining commands. If a skill needs a command variant not listed there, add it to this file first, then reference it. **What consuming skills should include:** - The reference block above (copy-paste it verbatim) - Any skill-specific *parameters* they pass to commands (e.g., label names, issue templates) - They should NOT include raw `glab`/`gh` invocations or detection snippets ## Dynamic Project Resolution Never hardcode project IDs. Resolve them at runtime. ### Current project ```bash # GitLab — get numeric project ID glab repo view --output json | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])" # GitHub — get owner/name identifier gh repo view --json nameWithOwner -q '.nameWithOwner' ``` ### Cross-project queries When a skill needs to reference other projects (e.g., from `cross-repos` in Session Config): ```bash # GitLab — resolve project ID by name glab api "projects?search=" | python3 -c "import json,sys; [print(p['id'], p['path_with_namespace']) for p in json.load(sys.stdin)]" # GitHub — resolve repo details gh api "repos//" --jq '.full_name' ``` **Note:** Some API calls require numeric project IDs (GitLab) or `owner/repo` slugs (GitHub). Always resolve dynamically from the project name. ## Label Taxonomy ### Priority Labels - `priority:critical` — blocking production or users - `priority:high` — important, schedule this sprint - `priority:medium` — plan for next sprint - `priority:low` — backlog, nice-to-have ### Status Labels - `status:ready` — defined, ready to pick up - `status:in-progress` — actively being worked on - `status:review` — MR/PR created, awaiting review - `status:blocked` — waiting on external dependency ### Area Labels - `area:frontend` | `area:backend` | `area:database` - `area:ai` | `area:security` | `area:testing` - `area:ci` | `area:infrastructure` | `area:compliance` ### Type Labels - `bug` | `feature` | `enhancement` | `refactor` - `chore` | `documentation` | `epic` | `discovery` | `carryover` - `carryover` — auto-created for 2×SPIRAL or FAILED agent tasks; see `scripts/lib/spiral-carryover.mjs`. ## Common CLI Commands ### GitLab (glab) ```bash # Issues glab issue list --per-page 50 # All open issues glab issue list --label "status:ready" --per-page 10 # Ready to work on glab issue list --label "priority:high" --per-page 10 # High priority glab issue list --closed --per-page 10 # Recently closed glab issue view # View issue details glab issue view --comments # With comments glab issue create --title "title" --label "priority:high,status:ready" glab issue update --label "status:in-progress" glab issue close glab issue note -m "Comment text" # Add comment # MRs glab mr list # Open MRs glab mr create --fill --draft # Create draft MR glab mr merge # Merge MR # Pipelines glab pipeline list --per-page 5 # Recent pipelines glab pipeline status # Pipeline details # API (reads host from git remote automatically) glab api "projects/$(glab repo view --output json | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")/issues?state=opened&per_page=50" glab api "projects/$(glab repo view --output json | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")/milestones?state=active" ``` ### GitHub (gh) ```bash # Issues gh issue list --limit 50 # All open issues gh issue list --label "status:ready" --limit 10 # Ready to work on gh issue list --label "priority:high" --limit 10 # High priority gh issue list --state closed --limit 10 # Recently closed gh issue view # View issue details gh issue view --comments # With comments gh issue create --title "title" --label "priority:high,status:ready" gh issue edit --add-label "status:in-progress" gh issue close gh issue comment --body "Comment text" # Add comment # PRs gh pr list --state open # Open PRs gh pr create --fill --draft # Create draft PR gh pr merge # Merge PR # Workflows (CI equivalent) gh run list --limit 5 # Recent workflow runs gh run view # Run details # API gh api "repos/{owner}/{repo}/issues?state=open&per_page=50" gh api "repos/{owner}/{repo}/milestones?state=open" ``` ## Issue Templates ### Bug Template ``` ## Description What happens vs. what should happen. ## Steps to Reproduce 1. 2. ## Root Cause (if known) ## Acceptance Criteria - [ ] ``` ### Feature Template ``` ## Goal What should be achieved and why. ## Tasks - [ ] ## Acceptance Criteria - [ ] ## Session Type [housekeeping|feature|deep] ``` ### Carryover Template (from /close) ``` ## [Carryover] Original Task Description ### What was completed - [completed items] ### What remains - [ ] [remaining task 1] - [ ] [remaining task 2] ### Context for next session [relevant context, file paths, decisions made] ### Original Issue Relates to #ORIGINAL_IID ``` ### Discovery Finding ```markdown ## [Discovery] **Probe:** **Severity:** **Category:** ### Finding ### Evidence - **File:** `` - **Line:** - **Code:** ``` ``` ### Impact ### Recommended Fix ### Acceptance Criteria - [ ] - [ ] Quality gates pass after fix ``` Labels: `type:discovery`, `priority:`, `area:`, `status:ready` ## Template-First Enforcement (PSA-005 + #519) Pattern 3 of the gsd Pattern Adoption (Issue #519) registers a PreToolUse hook `hooks/pre-bash-templates-first.mjs` that **blocks** `gh|glab pr|mr|issue create|new` Bash calls when the current session contains no prior `Read` on a matching template file. **When this matters:** before you or a subagent opens an MR, PR, or issue via CLI, a matching template must have been read in the current session: - GitHub: `.github/PULL_REQUEST_TEMPLATE.md` / `.github/ISSUE_TEMPLATE*` - GitLab: `.gitlab/merge_request_templates/Default.md` / `.gitlab/issue_templates/*` Accepted template paths are configured in `.orchestrator/policy/templates-policy.json` (versioned, operator-editable). Default behaviour: - `enforcement: "block"` — hook exits 2 when no prior template Read is found - Allow-list of host-specific template globs (GitHub + GitLab by default) - `bypass_patterns` — list of command substrings that skip the hook (e.g. CI/bot calls) **Bypass options for the current session** (when the hook blocks unexpectedly): 1. **Read the template first** — re-run the `create` call after a `Read` on the template path; the hook re-evaluates and sees the Read. 2. **Session acknowledgement** — write `.orchestrator/runtime/templates-acknowledged.json` containing `{ sessionId, acknowledgedAt }`; the hook allows all subsequent `create` calls in this session. **What the hook mechanically enforces** (what this skill previously documented as convention only): - "Template-first" for every new MR/PR/issue - Prevents convention drift across repos by turning the documentation requirement into a hard gate — the same shift from rule to mechanism that PSA-003 made for destructive commands **If the hook blocks incorrectly**, follow this sequence: 1. Read the template — retry the `create` call. 2. If the hook still blocks, open a bug issue against `hooks/pre-bash-templates-first.mjs` with reproduce steps (command, session ID, template path that should have matched). ### Issue/MR Creation Checklist (with template-first gate active) ```bash # 1. Read the relevant template first (satisfies the hook) # GitLab MR Read .gitlab/merge_request_templates/Default.md # GitHub PR Read .github/PULL_REQUEST_TEMPLATE.md # 2. Then create — hook now passes glab mr create --title "..." --description "..." gh pr create --title "..." --body "..." ``` ### Cross-References - Hook implementation: `hooks/pre-bash-templates-first.mjs` - Read-history helper: `hooks/_lib/transcript-history.mjs` (checks session transcript for prior Reads) - Enforcement policy: `.orchestrator/policy/templates-policy.json` - Session acknowledgement: `.orchestrator/runtime/templates-acknowledged.json` - Sister hook (destructive-command model): `hooks/pre-bash-destructive-guard.mjs` - PRD: `docs/prd/2026-05-22-gsd-pattern-adoption-quickwins.md` § Pattern 3 + § 3 Gherkin Pattern 3