Skip to content
Agentmart
Submit a tool

groom-issues

Skill bundle for the phil:groom-issues, phil:groom-fix, phil:groom-set and phil:groom-ask commands — reads a whole issue board in one list call per forge —…

Skill by pmvanev

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/pmvanev-groom-issues

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Skill bundle for the phil:groom-issues, phil:groom-fix, phil:groom-set and phil:groom-ask commands — reads a whole issue board in one list call per forge — plus one GraphQL call on GitHub for the parent/child edges that call cannot return — and reports what is wrong with it against a stated standard, applies the mechanical fixes inside a scope the user picks, resolves the defects between issues (merge, split, close, group, consolidate a feature decomposed under retired rules or a story spread across feature cards) by asking before each one, and fills in a card that says too little from the user's answers and its own suggestions, labelling where every field's words came from. Derives the defect table fresh every run and stores no grooming marker, so a declined candidate returns. For where the board STANDS rather than what is wrong with it — what is blocked, what is in flight, the next few queued — use phil:board-snapshot instead.

Use cases: backend

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/groom-issues

What's inside

Skill name
groom-issues
Description
Skill bundle for the phil:groom-issues, phil:groom-fix, phil:groom-set and phil:groom-ask commands — reads a whole issue board in one list call per forge — plus one GraphQL call on GitHub for the parent/child edges that call cannot return — and reports what is wrong with it against a stated standard, applies the mechanical fixes inside a scope the user picks, resolves the defects between issues (merge, split, close, group, consolidate a feature decomposed under retired rules or a story spread across feature cards) by asking before each one, and fills in a card that says too little from the user's answers and its own suggestions, labelling where every field's words came from. Derives the defect table fresh every run and stores no grooming marker, so a declined candidate returns. For where the board STANDS rather than what is wrong with it — what is blocked, what is in flight, the next few queued — use phil:board-snapshot instead.
License
MIT
Instructions
462 lines in SKILL.md · view on GitHub

Agent Skills spec issues

  • files: referenced but missing: references/gitlab-cli.md, references/hierarchy.md

Files (96)

  • SKILL.md
  • ask.md · references/
  • fix.md · references/
  • scan.md · references/
  • set.md · references/
  • expected.md · self-test/01-scan-and-report/
  • manifest.json · self-test/01-scan-and-report/
  • expected.md · self-test/02-partial-read-no-claim/
  • manifest.json · self-test/02-partial-read-no-claim/
  • expected.md · self-test/03-clean-board/
  • manifest.json · self-test/03-clean-board/
  • expected.md · self-test/04-generated-line-not-a-defect/
  • manifest.json · self-test/04-generated-line-not-a-defect/
  • expected.md · self-test/05-session-scratch-is-a-defect/
  • manifest.json · self-test/05-session-scratch-is-a-defect/
  • expected.md · self-test/06-no-marker-anywhere/
  • manifest.json · self-test/06-no-marker-anywhere/
  • expected.md · self-test/07-surface-not-act/
  • manifest.json · self-test/07-surface-not-act/
  • expected.md · self-test/08-read-only/
  • manifest.json · self-test/08-read-only/
  • expected.md · self-test/09-unevaluated-is-not-clean/
  • manifest.json · self-test/09-unevaluated-is-not-clean/
  • expected.md · self-test/10-one-sided-chain/
  • manifest.json · self-test/10-one-sided-chain/
  • expected.md · self-test/11-scope-before-write/
  • manifest.json · self-test/11-scope-before-write/
  • expected.md · self-test/12-apply-reports-its-reason/
  • manifest.json · self-test/12-apply-reports-its-reason/
  • expected.md · self-test/13-semantic-untouched-same-issue/
  • manifest.json · self-test/13-semantic-untouched-same-issue/
  • expected.md · self-test/14-stale-since-scan/
  • manifest.json · self-test/14-stale-since-scan/
  • expected.md · self-test/15-generated-region-refused/
  • manifest.json · self-test/15-generated-region-refused/
  • expected.md · self-test/16-population-of-one/
  • manifest.json · self-test/16-population-of-one/
  • expected.md · self-test/17-partial-overlap-three-outcomes/
  • manifest.json · self-test/17-partial-overlap-three-outcomes/
  • expected.md · self-test/18-merge-survivor-is-a-choice/
  • manifest.json · self-test/18-merge-survivor-is-a-choice/
  • expected.md · self-test/19-split-second-pass/
  • manifest.json · self-test/19-split-second-pass/
  • expected.md · self-test/20-obe-unverified/
  • manifest.json · self-test/20-obe-unverified/
  • expected.md · self-test/21-declined-leaves-no-trace/
  • manifest.json · self-test/21-declined-leaves-no-trace/
  • expected.md · self-test/22-rederive-between-candidates/
  • manifest.json · self-test/22-rederive-between-candidates/
  • expected.md · self-test/23-ungrouped-effort-container/
  • manifest.json · self-test/23-ungrouped-effort-container/
  • expected.md · self-test/24-wave-family-needs-no-declaration/
  • manifest.json · self-test/24-wave-family-needs-no-declaration/
  • expected.md · self-test/25-elicit-and-write/
  • manifest.json · self-test/25-elicit-and-write/
  • expected.md · self-test/26-elicit-declined/
  • manifest.json · self-test/26-elicit-declined/
  • expected.md · self-test/27-elicit-body-moved/
  • manifest.json · self-test/27-elicit-body-moved/
  • expected.md · self-test/28-partial-answer-stays-partial/
  • …and 36 more

SKILL.md (first lines)

# Groom issues — say what is wrong with a board

A board accumulates cards that someone filed half-finished. Reading them one at a time finds the
sloppy ones and misses the expensive ones, because the costly defects live *between* issues.

**Four commands, and the splits between them are the guarantee.**

- `/phil:groom-issues` reads and reports. It holds no `Write` and no `Edit`, so it cannot touch a file.
  Its forge calls must be reads, and since 2026-09-04 that half is a promise, not a scoping: reading a
  parent/child edge needs `gh api graphql`, which also accepts a mutation document. The scan's invariants,
  in `references/scan.md`, carry that promise, and nothing else does. Wound: without the grant, the decomposed-feature check
  reported clean on every board it was written for.
- `/phil:groom-fix` applies the mechanical column inside a scope the user picks, and changes no card's
  existence.
- `/phil:groom-set` resolves the defects between issues — merge, split, close, group, consolidate — and
  asks before every one.
- `/phil:groom-ask` fills in a card that says too little, asking, suggesting, and writing what the user
  sanctions.

Run each exactly as its section or file says; improvise none of them.

**The splits buy three things.**

- **A structural re-read.** One command carrying the report in context computes writes against
  remembered text. Separate commands must re-read.
- **Separate blast radii.** `/phil:groom-fix`'s edits each undo in one edit; `/phil:groom-set` changes
  **which cards exist**, and neither a merge nor a split reverses cleanly. One consent over both trains
  the habit formed on the many reversible changes onto the few irreversible ones.
- **Separate provenance.** `/phil:groom-ask` writes what no artifact holds — why a card is wanted. It
  needs consent **plus provenance**: did the human sanction this claim, and does the card record whose
  words carried it. No scoping enforces either.

**REQUIRED BACKGROUND: `phil:issue-board`.** Every forge mechanic — `-R` targeting, label semantics,
absolute-URL rules, dependency links, generated blocks — lives there. Do not guess any of it here.

## The four commands

Each command runs from one place. **Read the command's file whole before its first step**; this file
governs all four.

| Command | Runs | Read |
|---|---|---|
| `/phil:groom-issues` | the scan and its report | `references/scan.md` |
| `/phil:groom-fix` | the mechanical column | `references/fix.md` |
| `/phil:groom-set` | the set-level candidates | `references/set.md` |
| `/phil:groom-ask` | the semantic column | `references/ask.md` |

**Every ask in this skill follows `${CLAUDE_PLUGIN_ROOT}/skills/shared/decision-request.md`. Load it
before the first `AskUserQuestion` call.**

## The standard — what a well-formed issue contains

Without this, "appropriate description" is not checkable and grooming is taste. This is the house
default. **A project may override it in its own `CLAUDE.md`**, beside the per-project setup block
`phil:issue-board` already prescribes; where it does, that override wins and this section is ignored.

A well-formed issue has:

1. **A purpose readable without context** — what and why, in the body. A title is not a purpose, and
   the next reader is a stranger or a forgetful you.
2. **A way to tell when it is done** — acceptance criteria, or an outcome concrete enough to check.
3. **Links that resolve.** Absolute URLs for files, because GitHub emits relative paths verbatim and
   they 404. Bare `#N` for issues, because a bare reference renders live title and state where a
   markdown link freezes both. **This rule is about the form, and the form is fully checkable here** —
   a relative path is a finding whether or not its target exists, because the form 404s either way.
   Whether a correctly-formed link *reaches* something is a different question, and it belongs to the
   cross-reference row of the defect table below, which is where it goes dark.
4. **Correct labels**, with single-valued families carrying exactly one value. Nothing in a label's
   name says whether it excludes a sibling; GitHub has no scoped labels at all. `documentation` +
   `enhancement` on one issue is a defect or two orthogonal facts depending on a convention no forge
   records — so for a **project-local** family this is checkable only where the project declares it,
   and absent a declaration you report the rule **unevaluated**.

   **`wave: *` is single-valued by default, with no declaration.** In a repo holding `.nwave/` or
   `docs/feature/`, `phil:nwave-issue-board` makes it so: *"the wave label is single-valued and must be
   swapped, not added"*. A feature walked DISCUSS→DELIVER otherwise carries four wave labels, and every
   command reports success while the record of where it stands becomes unreadable. Report the
   accumulation as a mechanical defect. A project overrides this only by declaring `wave: *`
   multi-valued in as many words.

   Match a family on the prefix before `::` or `: ` — `wave::deliver` where scoped labels exist and
   `wave: deliver` where they do not are the same family, and a board may carry both spellings.

   **A declaration is a bullet under the project's `## Issue board` section in `CLAUDE.md`** naming a
   family and calling it single-valued or multi-valued, per the setup block in `phil:issue-board`.
   Neither a label's own description nor the labels in use counts: the first is not authoritative, and
   inferring the rule from the board's habits lets the board audit itself.
5. **A `## Chain` section when blocked or related** — the edge *and* the reason it exists, **on both
   ends**. `phil:issue-board` puts the prose line on both issues even where the forge writes the
   reverse edge itself, because the forge records the edge and never the reason. A chain naming an
   issue that does not name back is therefore half-written, and it is the half a reader lands on that
   decides whether they learn why. Cheap to check: the reciprocal is derivable from the same payload.

And it does **not** contain:

- **Session scratch or working state *typed outside a generated region*.** A board is world-readable, and
  hand-written scratch belongs in the git-ignored local surface (ADR-013). Session state **inside** the
  `nwave:status` markers is intended: `/phil:handoff` projects the why, the next action and the
  diversion stack there. Reporting that generated projection as a body defect flags the correct shape.
- **Hand-written content inside a generated region** — anything between `nwave:status` markers is
  regenerated, so a hand edit is destroyed on the next refresh and disagrees with its source until
  then.
- **A second copy of something the forge already keeps** — a roster where sub-issues exist, an order
  where position holds it. The copy is the one that goes stale.

  **A dated observation is not a copy.** The defect is a body asserting the forge's *present* state —
  "this board currently shows two cards In Progress" — which is wrong the moment the board moves and
  says nothing about when it was true. An observation stamped with its date, and pointing at the forge
  for the live answer, is history: it stays true, and a reader knows what to distrust. Prefer the
  observation where the state is the argument and deleting it would remove the argument.

### Judging prose is taste; composing it is not

**Rules 1, 2 and 5 check that a purpose, a done-condition and a reason are PRESENT. None of the five
items asks how anything READS.** The discriminator is who composed the words:

- **Judging prose a human wrote is taste. It stays out.** A scan that flagged someone's style would be
  the taste-policing this standard's opening sentence refuses, and no rule here licenses it. Presence is
  all those rules check — never whether what is present is well written.

From pmvanev/phil-claude-plugin, MIT.

More from pmvanev/phil-claude-plugin

Signals

Stars
0
Forks
0
Open issues
10
Last commit (this folder)
Oct 14, 2026 (14 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from pmvanev

Cite this page

groom-issues skill. Agent Mart. https://agentmart.dev/skills/pmvanev-groom-issues (last updated 2026-10-24)