| name | gitlab-mr-review |
| description | Manually triggered skill that harvests merge request review comments from a GitLab project using MCP tools, classifies them for playbook relevance, and auto-invokes packmind-update-playbook with structured findings. Use when wanting to mine merged MR discussions for recurring patterns, missing conventions, or stale rules that should be captured in the Packmind playbook. Supports non-interactive mode via `CI=true` or `--non-interactive` for scheduled runs. |
GitLab MR Review Mining
Harvest discussion notes from merged GitLab merge requests, classify them for playbook relevance, and feed actionable findings into the packmind-update-playbook workflow.
Workflow: Phase 0 → 1 → 2 → 3 → 4 → 5. Follow every phase in order.
Prerequisite: The GitLab MCP server must be available. Load references/gitlab-mcp-tools.md for tool signatures and parameters.
Phase 0: Collect Parameters
Gather the required inputs before fetching any data.
Execution Mode Detection
Determine the execution mode before collecting any parameters:
- Check
CI env var: run echo $CI. If the value is true, set non_interactive = true.
- Check skill arguments: if the skill was invoked with
--non-interactive, set non_interactive = true.
- Parse optional arguments:
--days N — override the default time period (default: 7 days)
--project namespace/project — override git remote inference
If neither condition is met, non_interactive = false (interactive mode — original behavior).
Collect Parameters
-
Infer project_path from the git remote:
git remote get-url origin
Parse the GitLab project path (namespace/project or group/subgroup/project) from the URL. Handle both SSH (git@gitlab.com:namespace/project.git) and HTTPS (https://gitlab.com/namespace/project.git) formats. Strip .git suffix if present.
- Interactive: If the remote is unavailable or ambiguous, ask the user.
- Non-interactive: If
--project was provided, use it. Otherwise abort with error: "Could not infer project path from git remote. Use --project namespace/project."
-
Gather time_period:
- Interactive: Ask the user how far back to look (default: 7 days, max: 90 days).
- Non-interactive: Use
--days value if provided, otherwise default to 7 days silently.
Compute the cutoff date as today - time_period in YYYY-MM-DD format.
-
Confirm before proceeding:
- Interactive: Display and BLOCK until the user confirms:
"Mining MR review comments for project_path merged in the last N days (since YYYY-MM-DD). Proceed?"
- Non-interactive: Log the parameters and proceed automatically:
"Non-interactive mode: mining MR review comments for project_path merged in the last N days (since YYYY-MM-DD)."
Phase 1: Fetch MRs
Use mcp__gitlab__search with:
scope: "merge_requests"
state: "merged" (run a second search with state: "opened" to also include open MRs)
project_id: project_path
search: "*" (must use "*", not "" — an empty string causes a 500 error)
Paginate using page and per_page (max 100 per page). Collect MR IIDs, titles, and web URLs.
For merged MRs, call mcp__gitlab__get_merge_request to get full details including merged_at. Filter out MRs where merged_at is before the cutoff date. For open MRs, use created_at or updated_at from the search results for the time filter.
- If no MRs remain within the time window, inform the user and stop.
- Display progress: "Found N MRs to analyze (M merged, K open)."
Phase 2: Fetch Review Comments & Filter
Use mcp__gitlab__search with scope: "notes" and project_id: project_path to fetch all discussion notes. Then correlate notes to MRs using noteable_type: "MergeRequest" and noteable_iid.
Important: Do NOT use mcp__gitlab__get_workitem_notes for MR notes — it only supports work item URLs (/-/work_items/<iid>), not merge request URLs. MR IIDs are not work item IIDs.
Filtering
Apply these filters to discard noise:
System note filtering — discard notes where the system flag is true. These are auto-generated by GitLab for:
- Label changes
- Assignee changes
- Milestone changes
- Pipeline status updates
- Branch operations (merge, rebase)
- Reviewer assignments
Low-value filtering — discard comments that:
- Are shorter than 15 characters
- Match low-value patterns: consists only of "LGTM", "+1", thumbs-up emoji variants, "nit", "thanks", ":thumbsup:", ":+1:"
Thread deduplication — when a note has a discussion_id, group notes by discussion. Keep only the root note unless a reply adds substantive new feedback (>30 chars and not a simple acknowledgment).
Display progress: "Collected N review comments from M MRs (after filtering)."
If no comments remain after filtering, inform the user and stop.
Phase 3: Classify Comments
Categorize each remaining comment by playbook relevance:
High relevance (keep)
- convention — Enforces or suggests a naming, structure, or organizational pattern
- best-practice — Recommends a better approach for correctness, performance, or maintainability
- recurring-feedback — Same feedback appears across 2+ different MRs
- bug-prevention — Points out a pattern that could lead to bugs
Low relevance (discard)
- style — Pure formatting preference
- clarification — Asks a question without suggesting a change
- nitpick — Minor, one-off preference
Retain only High-relevance comments.
Recurring Theme Detection
Group retained comments by semantic similarity. A recurring theme is 2+ comments across different MRs that address the same underlying pattern. For each theme:
- Assign a short descriptive label
- List all contributing comments
- Note the occurrence count
Codebase Relevance Gate
After classification, apply a strict codebase relevance filter to all high-relevance findings. GitLab MR notes can include CI/CD pipeline chatter, process comments, and DevOps discussions that aren't relevant to code.
Litmus test: "Would an AI coding agent need to know this when writing, reviewing, or shipping code in this repository?" — if no, discard the signal.
| Signal | Verdict | Why |
|---|
| "All API endpoints must validate input" | KEEP | Coding convention |
| "Use factory pattern for test data" | KEEP | Best practice |
| "Always add DB migration for schema changes" | KEEP | Dev workflow |
| "Run linter before pushing" | KEEP | Affects how agent ships code |
| "Pipeline passed on retry" | DISCARD | CI/CD operational noise |
| "Assigned to @user for review" | DISCARD | Process management |
| "Moved to staging environment" | DISCARD | Deployment operations |
| "Updated the .gitlab-ci.yml timeout" | DISCARD | CI/CD configuration chatter |
Edge cases: When a signal straddles both worlds (e.g., "update CI to run new test suite"), apply the litmus test strictly — does it change how an AI agent writes or ships code? If not, discard.
Display progress: "Retained N codebase-relevant findings (discarded M non-relevant signals)."
Phase 4: Build Findings Report
Choose the output path based on execution mode:
- Interactive:
.claude/tmp/gitlab-mr-review-findings.md
- Non-interactive:
.claude/reports/gitlab-mr-review-findings-YYYY-MM-DD.md (using today's date, timestamped for CI artifact upload)
Create the target directory if needed.
Report Structure
# GitLab MR Review Findings Report
**Project**: project_path
**Period**: YYYY-MM-DD to YYYY-MM-DD
**MRs analyzed**: N
**Comments collected**: N (after filtering)
**Actionable findings**: N
**Codebase-relevant findings**: N (of M high-relevance signals)
---
## Recurring Themes
### Theme: <label>
**Occurrences**: N across N MRs
| MR | File | Author | Comment |
|----|------|--------|---------|
| [!123](url) | path/to/file.ts | @author | Summary of comment |
| [!456](url) | path/to/other.ts | @author | Summary of comment |
**Suggested playbook action**: <Create standard | Update standard X | Create skill | ...>
**Rationale**: <Why this theme warrants a playbook change>
---
## Individual Findings
### Finding: <short description>
- **MR**: [!123](url)
- **File**: path/to/file.ts (if available from diff context)
- **Author**: @author
- **Comment**: Full comment text
- **Category**: convention | best-practice | bug-prevention
- **Suggested playbook action**: <action>
---
## Discarded Signals (non-relevant)
> Optional section for transparency. Lists signals that passed high-relevance classification but were filtered by the Codebase Relevance Gate.
| Signal summary | Reason discarded |
|---------------|-----------------|
| <one-line summary> | <CI/CD noise / process management / deployment ops / ...> |
URL Requirements
Every MR reference in the report MUST include the full, navigable GitLab URL (e.g., https://gitlab.com/namespace/project/-/merge_requests/123). This is critical because packmind-update-playbook extracts source URLs from the findings report for its packmind-cli diff --submit -m source attribution. The expected attribution format is:
<topic>: <summary> (source: MR !N https://gitlab.com/namespace/project/-/merge_requests/N, MR !M https://gitlab.com/namespace/project/-/merge_requests/M)
Use the web_url field returned by mcp__gitlab__get_merge_request for each MR. Never use placeholder (url) — always substitute the real URL.
Phase 5: Present and Hand Off
Interactive mode
-
Display a summary to the user:
- Number of recurring themes found
- Number of individual findings
- List of suggested playbook actions
-
Ask the user:
"Found N recurring themes and M individual findings. Review the full report at .claude/tmp/gitlab-mr-review-findings.md. Proceed to update the playbook with these findings?"
-
On confirm: Invoke the packmind-update-playbook skill with the full report content as the intent. This maps to Case B (explicit intent) of that skill's Phase 0. Frame the intent as:
"Update the Packmind playbook based on the following GitLab MR review findings report: "
-
On decline: Inform the user the report is available at .claude/tmp/gitlab-mr-review-findings.md for manual review.
Non-interactive mode
-
Display a summary (same as interactive: themes count, findings count, suggested actions).
-
Log the report output path:
"Report written to .claude/reports/gitlab-mr-review-findings-YYYY-MM-DD.md."
-
Invoke packmind-update-playbook with the full report content as the intent, passing along non-interactive mode. Frame the intent as:
"Update the Packmind playbook based on the following GitLab MR review findings report: "
The packmind-update-playbook skill will auto-approve all changes and delegate creation of new artifacts to the corresponding creation skills (packmind-create-standard, packmind-create-command, packmind-create-skill), all running in non-interactive mode.
Resources
references/
gitlab-mcp-tools.md — GitLab MCP tool signatures and parameters used by this skill