Skip to main content

backlog-management

Backlog management — MoSCoW prioritization, WSJF scoring, value-effort analysis, backlog health monitoring, grooming workflows. Use when prioritizing backlog, grooming items, or assessing backlog health.

Source facts

Repository
Agents-Store/opencode-plugins
Last source activity
October 3, 2026 at 23:16
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
backlog-management
description
Backlog management — MoSCoW prioritization, WSJF scoring, value-effort analysis, backlog health monitoring, grooming workflows. Use when prioritizing backlog, grooming items, or assessing backlog health.
# Backlog Management This skill covers backlog prioritization, grooming, and health monitoring using established Agile frameworks — MoSCoW, WSJF, Value vs Effort analysis. ## Tool Name Resolution Plane MCP exposes one tool per resource and the operation goes into the `action` parameter: `workitem(action=list, ...)`. This skill writes calls in that form. Resolve the real tool names (`mcp__<server>__<resource>`) for your current Plane connection through the `connector-bootstrap` skill - never assume a server prefix. ## Available Tools | Call | Description | |------|-------------| | `workitem(action=list)` | List backlog items (paginated), filterable with `pql` | | `workitem(action=count)` | Count backlog items without listing them: `pql`, `group_by` | | `workitem(action=update)` | Update priority, labels, estimates | | `workitem(action=search)` | Search items by text (workspace-wide) | | `workitem(action=archive)` | Archive a stale completed or cancelled item | | `label(action=list)` / `label(action=create)` | Existing labels / prioritization labels | | `state(action=list)` | State definitions | | `workitem_relation(action=list)` | Check blocking dependencies | | `get_pql_reference` | Syntax of the `pql` filter | ## Filtering the Backlog with PQL Server-side filters replace listing everything and filtering client-side. The `pql` parameter of `workitem(action=list)` and `workitem(action=count)` takes Plane Query Language; call `get_pql_reference` for the full syntax. Useful backlog filters (at most 5 conditions per query): | Question | `pql` | |----------|-------| | Backlog and planned items | `stateGroup IN ("backlog","unstarted")` | | Nobody owns it | `hasNoAssignee()` | | No priority set | `priority = "none"` | | No label | `hasNoLabel()` | | Untouched for 6 weeks | `updatedAt < daysAgo(42)` | | Overdue and still open | `isOverdue()` | | Mentions a keyword in the title | `title ~ "export"` | There is no PQL field for story points or description text: unestimated, oversized and no-description items are found from the listed `point` and `description_stripped` fields. `state__group` is a `group_by` key for counts, not a filter field - filter with `stateGroup`. ## MoSCoW Prioritization Map MoSCoW categories directly to Plane priority values: | MoSCoW | Plane Priority | Description | |--------|---------------|-------------| | **Must Have** | `urgent` or `high` | Critical for current release, non-negotiable | | **Should Have** | `medium` | Important but can be deferred if needed | | **Could Have** | `low` | Nice-to-have, adds value if time permits | | **Won't Have** | `none` | Explicitly out of scope for now | ### MoSCoW Workflow ``` 1. workitem(action=list, project_id=<id>, pql='stateGroup IN ("backlog","unstarted")') → Get all backlog items (follow next_cursor) 2. For each item, classify: - Does the product fail without this? → Must Have (urgent/high) - Is it important but not critical? → Should Have (medium) - Would users appreciate it but won't miss it? → Could Have (low) - Is it out of scope for now? → Won't Have (none) 3. Update priorities: workitem(action=update, project_id=<id>, workitem_id=<item_id>, priority="high") 4. Target distribution for a healthy backlog: Must Have: ~60% of sprint capacity Should Have: ~20% of sprint capacity Could Have: ~20% of sprint capacity (buffer items) ``` ## WSJF (Weighted Shortest Job First) **Formula:** `WSJF = (Business Value + Time Criticality + Risk Reduction) / Job Size` Higher WSJF = Higher priority (do first). ### WSJF Scoring Guide | Factor | 1 (Low) | 5 (Medium) | 10 (High) | |--------|---------|-----------|------------| | **Business Value** | Minor improvement | Important feature | Revenue/growth critical | | **Time Criticality** | No deadline | Needed soon | Urgent deadline | | **Risk Reduction** | No risk addressed | Moderate risk | Critical risk mitigated | | **Job Size** | XL (13+ pts) | M (3-5 pts) | S (1-2 pts) | ### WSJF Workflow ``` 1. workitem(action=list, project_id=<id>, pql='stateGroup IN ("backlog","unstarted")') → Get backlog items with estimates (follow next_cursor); skip items whose `point` is null - they cannot be scored until estimated 2. For each item, score (with user input): Business Value: [1-10] Time Criticality: [1-10] Risk Reduction: [1-10] Job Size (points): use existing story points 3. Calculate WSJF: WSJF = (BV + TC + RR) / points 4. Sort by WSJF descending 5. Update priorities: Top 25% → priority: "urgent" 25-50% → priority: "high" 50-75% → priority: "medium" Bottom 25% → priority: "low" 6. Present ranked list: | Rank | Item | BV | TC | RR | Size | WSJF | Priority | |------|------|----|----|-----|------|------|----------| | 1 | Quick win feature | 8 | 7 | 5 | 2 | 10.0 | urgent | | 2 | Critical fix | 9 | 9 | 8 | 5 | 5.2 | high | ``` ## Value vs Effort Matrix Plot items on a 2x2 grid: ``` HIGH VALUE │ ┌───────────────────┼───────────────────┐ │ Quick Wins │ Big Bets │ │ (Do First) │ (Plan Carefully) │ │ priority: urgent│ priority: high │ LOW ├───────────────────┼───────────────────┤ HIGH EFF │ Fill-ins │ Money Pit │ EFFORT │ (Do If Time) │ (Avoid/Defer) │ │ priority: low │ priority: none │ └───────────────────┼───────────────────┘ LOW VALUE ``` ### Value-Effort Workflow ``` 1. For each backlog item: Value: rate 1-10 (user impact, revenue, strategic) Effort: use story points 2. Classify: High Value (≥6) + Low Effort (≤5 pts) → Quick Win (urgent) High Value (≥6) + High Effort (>5 pts) → Big Bet (high) Low Value (<6) + Low Effort (≤5 pts) → Fill-in (low) Low Value (<6) + High Effort (>5 pts) → Money Pit (none) ``` ## Backlog Health Metrics ### Health Check Workflow ``` 1. Count what PQL can filter (one call each, read total_count): workitem(action=count, project_id=<id>, pql='stateGroup IN ("backlog","unstarted")') → total_items workitem(action=count, project_id=<id>, pql='stateGroup IN ("backlog","unstarted") AND hasNoAssignee()') → unassigned workitem(action=count, project_id=<id>, pql='stateGroup IN ("backlog","unstarted") AND priority = "none"') → no_priority Or the whole priority distribution in one call: workitem(action=count, project_id=<id>, pql='stateGroup IN ("backlog","unstarted")', group_by=priority) 2. List once for the metrics PQL cannot filter: workitem(action=list, project_id=<id>, pql='stateGroup IN ("backlog","unstarted")', fields="id,name,point,estimate_point,priority,description_stripped", per_page=100) → follow next_cursor, then calculate: unestimated = count where point is null no_description = count where description_stripped is empty/minimal large_items = count where point > 8 (total_items, unassigned and no_priority come from step 1; recompute them from the list only if the counts and the list disagree) 3. Health score: ready_items = items with: point set + priority set + description exists health_score = (ready_items / total_items) × 100 Stale items (candidates to archive or cancel): workitem(action=list, project_id=<id>, pql='stateGroup IN ("backlog","unstarted") AND updatedAt < daysAgo(42)') → untouched for ~3 two-week sprints 4. Present report: ┌─────────────────────────────────────┐ │ BACKLOG HEALTH REPORT │ ├─────────────────────────────────────┤ │ Total items: 45 │ │ Ready for sprint: 28 (62%) │ │ Unestimated: 12 (27%) [!] │ │ No priority: 8 (18%) [!] │ │ No assignee: 15 (33%) │ │ Oversized (>8pt): 3 (7%) [!] │ │ No description: 5 (11%) [!] │ ├─────────────────────────────────────┤ │ Health Score: 62% — Needs Grooming │ └─────────────────────────────────────┘ Recommendations: 1. Estimate 12 unestimated items (use /estimate) 2. Split 3 oversized items (use /decompose) 3. Set priorities for 8 items (use /wsjf-prioritize) ``` ### Health Score Interpretation | Score | Status | Action | |-------|--------|--------| | 90-100% | Healthy | Ready for sprint planning | | 70-89% | Good | Light grooming needed | | 50-69% | Needs Work | Dedicate a grooming session | | < 50% | Unhealthy | Urgent grooming required | ## Backlog Grooming Workflow ### Full Grooming Session ``` 1. Review from top of backlog (highest priority first) 2. For each item: a. Is this still relevant? → If not, move to a cancelled state (an item in a completed or cancelled state can then be archived with workitem(action=archive)) b. Is it clear enough? → If not, add description/acceptance criteria c. Is it estimated? → If not, estimate (see estimation skill) d. Is it the right size? → If > 8 points, decompose e. Is priority correct? → Adjust if business context changed f. Are dependencies identified? → workitem_relation(action=list) / (action=create) 3. After grooming, re-check health metrics ``` ## Recommended Labels for Backlog Management Use the labels defined in the **project-setup** skill. Key labels for backlog triage: - `ready` — item meets Definition of Ready, can enter sprint - `needs-refinement` — item needs more detail before sprint - `blocked` — item has unresolved dependency - `quick-win` — low effort, high value (see Value vs Effort matrix) To create these labels, refer to the project-setup skill for full label definitions with colors. ## Best Practices 1. **Groom regularly** — mid-sprint for 30-60 minutes, not before sprint planning 2. **Top-down review** — start with highest priority items 3. **Keep backlog lean** — if an item hasn't moved in 3+ sprints (`updatedAt < daysAgo(42)` for two-week sprints), cancel it, then archive it (`workitem(action=archive)` accepts only completed or cancelled items); delete only after confirmation 4. **One prioritization method** — pick MoSCoW or WSJF, don't mix 5. **Involve the team** — grooming is a team activity, not just PM 6. **Limit backlog size** — aim for 2-3 sprints worth of refined items 7. **Use labels for triage** — "ready", "needs-refinement", "blocked" for at-a-glance status
View on GitHub