name: groom-backlog description: Use when the user says "groom the backlog" / "clean up the backlog" / "what's stale" / "prune the queue" — pulls all open tickets from the connected issue tracker and returns three review lists (keep-and-prioritize / merge-as-duplicates / close-as-stale), each with one-line rationales. HARD NO — never closes, merges, or reprioritizes tickets in the tracker; the user reviews and acts.
Groom Backlog
Weekly backlog pass. Three lists. You decide what actually happens in the tracker.
When to use
- User: "groom the backlog" / "clean up the backlog" / "what's stale" / "prune the queue" / "weekly grooming".
- As a recurring weekly rhythm for a long-lived backlog.
Steps
-
Read engineering context —
../head-of-engineering/engineering-context.md. If missing or empty, say: "I need the engineering context doc first. Run Head of Engineering'sdefine-engineering-context(5 minutes), then come back." Stop. -
Read
config/issue-tracker.json. If missing, stop and ask: "I don't know where your tickets live. Runonboard-me(30 seconds for just this topic), or tell me your tracker now." Write and continue. -
Read
config/cadence.mdso the week number used in the output filename matches the user's rhythm. Read anystaleThresholdDaysoverride inconfig/issue-tracker.json— default is 90 days with no activity if not set. -
Fetch open tickets via Composio. Run
composio search <issue-tracker>to find the list-issues tool slug for the connected tracker, then call it. If the tracker isn't connected, stop and tell the user which category to link. For each ticket capture: id, title, URL, labels / tags, assignee, createdAt, updatedAt, lastActivityAt (comments + state changes), priority field, and the first ~200 chars of the body. -
Build list 1 — keep-and-prioritize. Score each ticket by alignment with the current-priorities section of the engineering context. Keep the top N (default 15; halve if the user's tracker has <30 open tickets). For each, a one-line rationale tying it to a named priority or a named user-surface / quality-bar item.
-
Build list 2 — merge-as-duplicates. Group tickets by normalized-title similarity + body keyword overlap (cheap heuristic — not a model call). For each group pick a canonical ticket (the one with the most activity / best body) and note the others as likely dupes. One-line rationale per group ("same symptom — 500 on POST /auth/login — filed 3 times since March"). A group is only worth listing if it has 2+ members.
-
Build list 3 — close-as-stale. Tickets with
lastActivityAtolder than the stale threshold (default 90 days). One-line rationale per ticket ("no activity since 2025-11-18; labeled P3; no recent duplicates"). Explicitly exclude anything with labels that hint at long-term tracking (e.g.epic,parent,roadmap,paused) — name those exclusions in a short "Not-stale despite age" footnote. -
Write
backlog-grooming/{YYYY-Www}.mdatomically (.tmp→ rename). Structure:# Backlog grooming — {ISO-week} **Stale threshold:** {N} days. **Open tickets scanned:** {count}. ## Keep and prioritize (top {N}) - [TICKET-ID] Title — rationale. {URL} ## Merge as duplicates (you review, you merge) **Group 1** — rationale. Canonical: [TICKET-ID]. Dupes: [...] ## Close as stale (you review, you close) - [TICKET-ID] Title — last activity {date}, rationale. {URL} ## Not-stale despite age (kept) - [TICKET-ID] {reason} -
Append to
outputs.json— type"backlog-grooming", status"draft", 2-3-sentence summary naming the open-ticket count and the sizes of the three lists. Read-merge-write atomically. -
Summarize to user — one paragraph: "Grooming pass at {path}. {X} to keep, {Y} dupe groups, {Z} stale. I have not closed, merged, or reprioritized anything — the tracker is yours. Skim the three lists, act on what you agree with."
Hard nos
- Never actually close, merge, or reprioritize tickets in the tracker. No tracker writes, ever. The output is a list you review.
- Never auto-prune — even if a ticket clearly matches stale criteria, it lands in the list for review, not in a "close" call.
- Never invent tickets that aren't in the tracker.
Outputs
backlog-grooming/{YYYY-Www}.md- Appends to
outputs.jsonwith{ id, type: "backlog-grooming", title, summary, path, status: "draft", createdAt, updatedAt }.