Skip to content
Development
Skill

/model-triage

Adopt the per-issue model-selection convention in a repo — tier every open issue, apply the model: labels, board field, and callouts behind an approval gate. Also runs in maintenance mode to sweep up unlabeled issues and label/field drift.

BOOST
From plugin
joshukraine-dotfiles
42924 skills
Install
$ npx -y skills add joshukraine/dotfiles --skill model-triage --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/model-triage

Context preview

The summary Claude sees to decide when to auto-load this skill.

Adopt the per-issue model-selection convention in a repo — tier every open issue, apply the model: labels, board field, and callouts behind an approval gate. Also runs in maintenance mode to sweep up unlabeled issues and label/field drift.

SKILL.md

model-triage.SKILL.md
name: model-triage
description: Adopt the per-issue model-selection convention in a repo — tier every open issue, apply the model: labels, board field, and callouts behind an approval gate. Also runs in maintenance mode to sweep up unlabeled issues and label/field drift.
disable-model-invocation: true
argument-hint: "[--maintenance]"

Model Triage

Roll the per-issue model-selection convention into a repository: tier each open issue, then apply the `model:` labels, the board's `Model` field, and any body callouts — all behind a single approval gate. The convention, its heuristic, and the manual runbook this encodes live in `~/.claude/docs/model-selection-strategy.md`; the label vocabulary lives in `~/.claude/docs/label-taxonomy.md`.

This is a **rollout tool, not a routine one.** Model labels are assigned at issue creation alongside the type label. Run this skill once when adopting the convention in a repo that already has open issues, and after that only in maintenance mode when drift has accumulated.

Where this runs

From the **target repository's checkout** — you need the issues _and_ the code, because tiering an issue means judging what a fix would actually touch. If you must run from elsewhere, every `gh issue` call needs `--repo <owner>/<name>`; without it the command silently targets whatever repo you are standing in.

Arguments

  • **(no args)** — full rollout: tier every open issue that should carry a label.
  • **`--maintenance`** — sweep mode: tier only issues _missing_ a label, reconcile label ↔ board-field drift, and refresh stale label _descriptions_. Leaves existing label assignments alone unless an issue's scope has visibly changed.

The tiering heuristic

Assign a tier by asking what a _wrong answer_ costs and how far the reasoning reaches. Full treatment in the strategy doc; the working summary:

  • **Fable (flagship)** — a wrong answer would _silently_ corrupt canonical/persistent data with no error surface. This is the insurance case, and only that case. Expect it rare, and expect each one to have a nameable reason. (Multi-module reasoning with non-obvious ripple used to qualify here too; Opus 5 absorbed it and the clause was cut on 2026-07-27.)
  • **Opus (workhorse)** — well-specified features with a test scaffold and a contained blast radius; migrations / data-model; thin specs; security-adjacent work. The default when you genuinely can't tell.
  • **Sonnet (light)** — docs, a single regression test, i18n / copy, mechanical pattern-following where the spec leaves little to interpret and failure is visible.

Lean one tier down for docs/tests, one tier up for anything touching data integrity.

**Calibration:** ComixDistro's settled pass was 4 Fable / 32 Opus / 25 Sonnet across 61 issues — roughly **6% flagship** — but that pass was tiered under the older two-clause flagship bar. Under the tightened bar expect **~2–3%**. Either way, a pass landing far above is not discriminating, it is just burning limit headroom. Check the two calibration references in the strategy doc — and the note on which rules they were measured under — before presenting.

Issues that get no tier

Some issues have nothing to build directly, and a tier on them is noise:

  • **epics and tracking issues** — the children carry the tiers
  • **content hubs** — durable reference/index issues
  • **`qa` reports** — the tech issue derived via `/qa-triage` carries the tier

Call these out explicitly as deliberate exclusions rather than silently skipping them; an unexplained gap looks identical to an oversight.

Your task

Step 0 — Preflight

Establish that everything the apply step needs exists, and stop early if it doesn't:

1. **Token scope** — `gh auth status` must list `project` in the token scopes. If it's missing, stop: the user must run `gh auth refresh -s project` interactively. You cannot grant it for them. 2. **Locate the board** — `gh project list --owner <OWNER>`; capture the project number and node ID (`PVT_…`). If the repo has no board, the label pass can still proceed — say so and skip the field work rather than stopping. 3. **Labels exist** — `gh label list`. Create any missing ones from the taxonomy, exactly as specified there:

   gh label create "model: fable"  --color B60205 --description "Recommended model: Fable 5 (reserve for silent-data-corruption stakes)"
   gh label create "model: opus"   --color FBCA04 --description "Recommended model: Opus 5 (well-scoped features, refactors)"
   gh label create "model: sonnet" --color 0E8A16 --description "Recommended model: Sonnet (docs, single tests, mechanical edits)"

**Also check the descriptions of labels that already exist.** A description names the model current _at the time the label was created_, so a repo adopted before a model release carries a stale one indefinitely — `gh label create` won't touch it and no other step will either. Compare against the strings above and repair any mismatch:

   gh label list --json name,description --jq '.[] | select(.name | startswith("model: ")) | "\(.name)\t\(.description)"'
   gh label edit "model: opus" --description "Recommended model: Opus 5 (well-scoped features, refactors)"

Report each repair as drift fixed, not as a label created.

4. **`Model` field exists** — `gh project field-list <N> --owner <OWNER> --format json`. If absent, create it once:

   gh project field-create <N> --owner <OWNER> \
     --name "Model" --data-type SINGLE_SELECT --single-select-options "Fable,Opus,Sonnet"

5. **Board membership** — `gh project item-list <N> --owner <OWNER> --limit 200 --format json`. Diff against the open-issue list; **an issue not on the board cannot receive a field value.** Note the strays now so the apply step can `gh project item-add` them first. Trust `item-list` over any claim an issue body makes about its own board membership.

Report the preflight result compactly: what existed, what you created, what needs ad

Read more
Ships withjoshukraine-dotfiles

:round_pushpin: My dotfiles for macOS using Neovim, Zsh, and Ghostty + Tmux

Get the whole plugin

Other skills on joshukraine-dotfiles.