Skip to content
Back to skills

Triage Issues

ASecurity

Manually triage and groom a-novel/a-novel-kit issue boards: refine scope, priority, size, dates, and status. Use when asked to triage, groom, prioritize, or prepare planning.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentgobashnodeexpressapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add a-novel-kit/stack --skill triage-issues --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Triage Issues?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Triage Issues
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/a-novel-kit-triage-issues/badge)](https://www.skillsdirectory.com/skills/a-novel-kit-triage-issues)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: triage-issues
description: >
  Manually triage and groom a-novel/a-novel-kit issue boards: refine scope, priority, size, dates,
  and status. Use when asked to triage, groom, prioritize, or prepare planning.
---

# Triage & groom the issue set

Planning creates issues; **triage keeps them honest**. Over time priorities drift, scopes change,
drafts pile up, active work loses its due date, and the `Triage` status fills with un-assessed
reports. This is the recurring pass that fixes all of that — run **manually**, as a planning meeting
with the operator, not on a timer. A weekly cadence is recommended, but the human pulls the trigger.

`plan-feature` sets a ticket's fields at **creation**; this pass keeps them true **over time**.

---

## Posture

- **Scope to the work in hand.** "Clean the board" means the milestone — or the single task — this
  session is already about, not every open item. Survey what that work touches, fix what drifted
  there, and leave the rest alone: an unrelated ticket belongs to someone else's pass, and reporting
  it is noise dressed as diligence. Sweep the whole board only when the operator asks for that
  explicitly.
- **This is a planning conversation, not a batch job.** Propose field values; the operator confirms —
  especially **due dates**, which are commitments. Use the `resolve-pr-feedback` issue-comment loop to
  ask and record decisions where useful.
- **Lead with priority.** Work the set in Priority order (P0 → P4). A pass outputs a clear "what's
  next": the P0/P1 items that aren't already moving.
- **Keep the board honest.** The invariants a pass enforces: every actionable ticket has a **Type**, a
  **Priority**, and a **Size**; **every item that belongs to a milestone actually carries it** — boarding
  an item (`--project`) never sets its Milestone, so scan for a **Stage-tagged item with an empty
  Milestone** (the tell that `--milestone` was forgotten at creation) and add it; no **active** issue
  lacks a **due date**; no items lingering in `Triage`; no rotting drafts.

---

## The pass

### 1. Survey both boards

```bash
gh project item-list 7 --owner a-novel --format json --limit 200
gh project item-list 1 --owner a-novel-kit --format json --limit 200
```

Both orgs, because one milestone's work is usually split across them. Then **filter to the work in
hand** (see Posture). A milestone is per-repo, so its copies all share a title: selecting on that
gathers every repo's share of it in one pass.

```bash
gh project item-list 7 --owner a-novel --format json --limit 200 \
  --jq '.items[] | select(.milestone.title == "<the goal>")'
```

`gh`'s own `--jq` flag runs the expression, so this needs no external `jq` on the box.

Drop the filter only for a full sweep the operator has asked for.

For each item in scope read: Type, Priority, Size, Status, Target date, Milestone, linked PRs,
blocked-by, and sub-issue progress. The **Triage queue** is every board item sitting in the `Triage`
**status**, where an un-assessed incoming issue lands; filter the item-list above by
`Status == Triage`.

`item-list` is a scan, not evidence. It has returned a single item for a populated board even at
`--limit 1200`, which reads as "everything else was archived" when nothing was. Before concluding an
item is missing or archived, confirm against the issue itself:

```bash
gh api graphql -f query='query { repository(owner:"<org>", name:"<repo>") {
  issue(number: <n>) { id projectItems(first:10, includeArchived:true) {
    nodes { id isArchived project { number title } } } } } }'
```

Read the fields off that item node (`ProjectV2ItemFieldSingleSelectValue`).

### 2. Drain the triage queue (un-assessed → assessed)

For each item in the `Triage` status, with the operator:

- Confirm or assign its **Type** (Epic / Feature / Task / Bug).
- Assign **Priority** and **Size** (weight).
- Add it to the org board if it isn't already (`gh project item-add`).
- Assess it and move its **Status** out of `Triage` — `Backlog` for a not-yet-ready draft, `Ready`
  when it can be picked up (`gh project item-edit`).
- An empty `Triage` status is the goal of a **full sweep** — no item should linger un-assessed (the
  cli/cli "First Responder" model). In a scoped pass, drain only what belongs to the work in hand; an
  unrelated arrival is worth one line as a signal, not a detour.
- **Escalation tickets** (label `escalation`) are a distinct intake — the governance automation files
  them in `Triage` when something needs a human (a stale backport, a stale required check, a
  failed emergency path; see `coordinate-landing`). Don't size them as planning work: act on the
  underlying condition, then let the `escalate` action resolve the ticket (Status → `Applied`) as it
  self-heals, or close it once handled. A pile of open `escalation` tickets is an ops signal.

### 3. Prioritise

Order the actionable set by **Priority** and surface the **P0/P1 items not yet In progress** — the
planning focus. Re-balance priorities with the operator where reality has drifted (a P2 now blocking
a release becomes P1; a P1 nobody will touch becomes P3).

### 4. Weights

Every actionable ticket gets a **Size** (XS–XL). Assign where missing; **re-estimate** where the
scope changed since creation. A ticket whose size keeps growing should be split into sub-issues
(hand back to `plan-feature`).

### 5. Due dates — with the operator

- **Active issues** — those with an **open linked PR** — **must** have a **Target date**. Agree it
  with the operator. _An active issue with no due date is the single thing this pass exists to catch._
- **Milestones** get a **due date** too, set/adjusted to the release plan:

  ```bash
  gh api repos/<owner>/<repo>/milestones/<number> -X PATCH -f due_on=2026-07-15T00:00:00Z
  ```

- Treat both as **soft commitments** that drive the _next_ pass — a slipped date is information, not a
  failure. Every in-flight thing needs a date to slip _from_.

### 6. Refine drafts nearing production

The Backlog drafts `plan-feature` stages ahead (future stages, `blocked-by` their predecessors) need
grooming as they approach activation:

- For a draft about to go active: **firm up the body** (is the approach still right?), set its
  **Size/Priority**, confirm its **blocked-by** is now satisfied, and move **Backlog → Ready**.
- **Delete drafts the plan has overtaken** (`gh issue delete <n> --yes`) — a not-yet-started draft is
  cheap to discard, and a stale one is worse than none.

### 7. Status is single-writer

The board's bot derives Status from what happened to a Pull Request, so `In progress`, `In review`,
and `Awaiting release` are not yours to set: a manual edit will not stick. Your part is the
`Triage → Ready` move from the drain above, plus a **meta task**'s final `Applied`, which has no Pull
Request to read from. Everything else follows the work.

**Check for siblings before closing a child.** Sub-issue progress of 1 of 1 is indistinguishable from
"all children done", so closing an Epic or Initiative's only sub-issue derives the parent as
complete: Status moves to Done, the auto-close workflow closes it, and it disappears from the board.
Either hold the child open until siblings exist, or expect the close and reopen the parent straight
after — `gh issue reopen <parent>`, then set its Status again by hand, since reopening does not
restore board fields the automation overwrote. A parent with several children is safe; this bites
only at the start of a plan, when the first child is the only child.

### 8. Keep the Stage field accurate (absolute scheme)

The `Stage` board field is **absolute** — `Stage 1 … Stage N` (six on the board today), plus
`Unscheduled` for work not yet placed in a stage. A staged milestone's epics and their child tasks
each carry their stage's number, set once at creation (per the `plan-feature` field habit) and
**never shifted**: an item at `Stage 3` stays `Stage 3` for good. "What's next" is a derivation, not
a label — the lowest-numbered stage not yet done. A finished stage keeps its number; its epic follows
the normal Done → archive lifecycle rather than being relabelled.

So this pass has nothing to shift. Check only that new items carry the right stage number — a human
call about which stage the work belongs to — and that an epic and its tasks agree on it. No
automation reads the field yet: you set it by hand at creation and read "what's next" off the numbers
yourself.

### 9. Report

Close the pass with a tight summary for the operator, and **end it with the session recap table**
(memory `session-recap-table`): every issue that still needs the operator — decisions, due dates to
commit, promotions pending — as a row whose id is an **inline link** to the issue, so they can jump
straight there. Cover it in:

- The prioritised **P0/P1 "what's next"** list.
- What was **triaged** (queue drained), **re-prioritised**, and **re-sized**.
- **Due dates** set (issues + milestones) and any the operator still needs to commit.
- Drafts **promoted** (Ready) or **deleted**.
- Anything still **needing the operator's decision**.

---

## gh quick reference

| Action                        | Command                                                                                             |
| ----------------------------- | --------------------------------------------------------------------------------------------------- |
| List board items              | `gh project item-list <7\|1> --owner <org> --format json --limit 200`                               |
| Find the triage queue         | filter `gh project item-list` output to items with `Status == Triage`                               |
| Set Priority / Size / Status  | `gh project item-edit --id <item> --project-id <proj> --field-id <f> --single-select-option-id <o>` |
| Set a due date (Target date)  | `gh project item-edit --id <item> --project-id <proj> --field-id <date-field> --date YYYY-MM-DD`    |
| Set a milestone due date      | `gh api repos/<o>/<r>/milestones/<n> -X PATCH -f due_on=<RFC3339>`                                  |
| Leave Triage (assess an item) | move Status `Triage → Backlog`/`Ready` via `gh project item-edit`                                   |
| Promote a draft               | move Status `Backlog → Ready` via `gh project item-edit`                                            |
| Delete an overtaken draft     | `gh issue delete <n> --repo <o>/<r> --yes`                                                          |

Field / option / item IDs come from `gh project field-list <num> --owner <org>` and
`gh project item-list`. Scopes: `repo` + `project`, on top of write on the board, which
[check-access](../check-access/SKILL.md) checks. On an authorization failure, follow `plan-feature` →
_Token scopes_: ask for a missing scope, report a missing role.

---

## How this composes

```
plan-feature (creates issues, sets fields at creation)
      │
      ▼
triage-issues (recurring manual pass: prioritise · weigh · due-date · refine drafts · drain triage)
      │
      ├─ hands a near-ready draft back to plan-feature when it needs real (re)design
      ├─ uses resolve-pr-feedback's comment loop to ask/record operator decisions on an issue
      └─ feeds the P0/P1 "what's next" into implement-feature / manage-versions
```

---

## Principles

- **Scope before sweep** — the work the session is about; the whole board only on request.
- **Lead with priority** — a pass is judged by whether "what's next" is unambiguous afterwards.
- **Honest invariants** — Type + Priority + Size on every actionable ticket; active ⇒ a due date;
  nothing lingering in `Triage`.
- **Dates are for triage, not theatre** — they make the next decision, and a slip is information.
- **Drafts are living** — refine the ones going active, delete the ones the plan has overtaken.
- **Propose, the operator commits** — especially dates; triage is a conversation, not an edict.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.