skills/groom-backlog/SKILL.md
Groom the backlog by closing completed tickets, removing redundant/stale tickets, reprioritizing, and assigning agents
npx skillsauth add gioe/tusk groom-backlogInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Grooms the local task database by identifying completed, redundant, incorrectly prioritized, or unassigned tasks.
Use
/create-taskfor task creation — handles decomposition, deduplication, criteria, and deps. Usetusk task-insertonly for bulk/automated inserts.
Record the start of this groom run so cost can be captured at the end:
tusk skill-run start groom-backlog
This prints {"run_id": N, "started_at": "..."}. Capture run_id — you will need it in Step 7.
Early-exit cleanup: If any check below causes the skill to stop before Step 7b (e.g.,
tusk setup/tusk backlog-scanfails, the backlog is empty with nothing to groom, or the user declines the Step 4 approval prompt), first calltusk skill-run cancel <run_id>to close the open row, then stop. Otherwise the row lingers as(open)intusk skill-run listforever.
Before grooming, fetch everything needed in a single call:
tusk setup
This returns a JSON object with two keys:
config — full project config (domains, agents, task_types, priorities, complexity, etc.). Use these values (not hardcoded ones) throughout the grooming process.backlog — all open tasks as an array of objects. Use this as the primary backlog data for Step 1 (you still need the dependency queries below).Run the auto-close check for moot contingent tasks:
tusk autoclose
This returns a JSON summary with counts and task IDs per category:
moot_contingent — tasks contingent on upstream work that closed as wont_do/expired (closed as wont_do)If total_closed is 0, report "No auto-close candidates found" and proceed to Step 1. Otherwise, report the counts before continuing.
The backlog tasks are already available from the tusk setup call above. Fetch dependency data to supplement:
tusk deps blocked
tusk deps all
On-demand descriptions: This query intentionally omits the description column to keep context lean. When you identify action candidates in Step 2 (tasks to close, delete, reprioritize, or assign), fetch full details for just those tasks:
tusk -header -column "SELECT id, summary, description FROM tasks WHERE id IN (<comma-separated ids>)"
Run the consolidated pre-flight scan to gather all grooming signals in a single call:
tusk backlog-scan
This returns JSON with four categories — hold onto the result, it replaces several individual queries throughout the workflow:
duplicates — Heuristic duplicate pairs among open tasks (feeds Step 2a)unassigned — Open tasks with no assignee (feeds Category D)unsized — Open tasks without a complexity estimate (feeds Step 6)expired — Open tasks past their expires_at date; if non-empty, report those task IDs alongside the tusk autoclose results from the Pre-Check step as additional candidates for manual reviewUse the duplicates array from the tusk backlog-scan result (Step 1b). Each entry is:
{"task_a": {"id": N, "summary": "..."}, "task_b": {"id": N, "summary": "..."}, "similarity": 0.N}
Any pairs found should be included in Category B with reason "duplicate".
Analyze each task and categorize. In addition to the heuristic scan results from Step 2a, look for semantic duplicates — tasks that cover the same intent but use different wording (e.g., "Implement password reset flow" vs. "Add forgot password endpoint"). The heuristic catches textual near-matches; you should catch conceptual overlap that differs in phrasing.
Tasks where the work has already been completed in the codebase:
tusk task-done <id> --reason completed
Before recommending deletion, check dependents:
tusk deps dependents <id>
Tasks without an agent assignee. Use the unassigned array from the tusk backlog-scan result (Step 1b) — each entry includes id, summary, and domain.
Assign based on project agents (from tusk config).
Correctly prioritized, assigned, and relevant. No action needed.
Present analysis in this format:
## Backlog Grooming Analysis
### Total Tasks Analyzed: X
### Ready for Done (W tasks)
| ID | Summary | Evidence |
### Recommended for Deletion (Y tasks)
| ID | Summary | Reason |
### Recommended for Reprioritization (Z tasks)
| ID | Summary | Current | Recommended | Reason |
### Unassigned Tasks (U tasks)
| ID | Summary | Recommended Agent | Reason |
### No Action Needed (V tasks)
IMPORTANT: Before making any changes, explicitly ask the user to approve each category.
If the user declines approval (or no actions were proposed), run tusk skill-run cancel <run_id> and stop — do not proceed to Step 5. This closes the open skill_runs row instead of leaving it pending forever.
Only after user approval:
tusk task-done <id> --reason completed
# Duplicates:
tusk task-done <id> --reason duplicate
# Obsolete/won't-do:
tusk task-done <id> --reason wont_do
tusk task-update <id> --priority "<New Priority>"
tusk task-update <id> --assignee "<agent-name>"
Verify all modifications in a single batch query:
tusk -header -column "SELECT id, summary, status, priority, assignee FROM tasks WHERE id IN (<comma-separated ids of all changed tasks>)"
Before computing priority scores, check for tasks without complexity estimates. Use the unsized array from the tusk backlog-scan result (Step 1b) — each entry includes id, summary, domain, and task_type.
If the unsized array is empty, skip to Step 7.
If unsized tasks are found, read the reference file for the sizing workflow:
Read file: <base_directory>/REFERENCE.md
Follow Steps 6b–6d from the reference, then continue to Step 7 below.
Generate the summary report:
## Backlog Grooming Complete
### Actions Taken:
- **Moved to Done**: W tasks
- **Deleted**: X tasks
- **Reprioritized**: Y tasks
- **Assigned**: U tasks
- **Unchanged**: Z tasks
Show the final backlog state (this also serves as WSJF score verification):
tusk -header -column "
SELECT id, summary, status, priority, complexity, priority_score, domain, assignee
FROM tasks
WHERE status <> 'Done'
ORDER BY priority_score DESC, id
"
Record cost for this groom run. Replace <run_id> with the value captured in Step 0, and fill in the actual counts from the actions taken:
tusk skill-run finish <run_id> --metadata '{"tasks_done":<W>,"tasks_deleted":<X>,"tasks_reprioritized":<Y>,"tasks_assigned":<U>}'
This reads the Claude Code transcript for the time window of this run and stores token counts and estimated cost in the skill_runs table.
To view cost history across all groom runs:
tusk skill-run list groom-backlog
/groom-backlog can be run unattended via claude -p (non-interactive print mode):
claude -p /groom-backlog
Caveats for unattended runs:
Keep the backlog lean (< 20 open tasks): The full backlog dump scales at ~700 tokens/task and is repeated across ~15+ agentic turns during grooming. A 30-task backlog can consume over 300k tokens in a single session. Aggressively close or merge tasks to stay under 20 open items.
data-ai
Autonomously work through the backlog — dispatches /chain for chain heads, /tusk for standalone tasks, repeating until empty
tools
File a GitHub issue against the tusk repo itself — tusk bugs, CLI limitations, skill improvements, or missing features. Use anytime the user identifies a gap in tusk (not in their own project's code).
tools
Contribute a client-discovered fix or improvement back to the configured iOS library repo from an ios_app tusk project.
data-ai
File a GitHub issue against the configured iOS lib repo with originating tusk task auto-attached