Discovery — scan GitHub issues (and anything else the project names) for work, rank it, and append rows to state/triage.md at status `new`. Never modifies or closes existing rows.
Install
npx skillscat add luxtelos/loopkit/morning-triage Install via the SkillsCat registry.
Skill: Morning Triage
Job
Scan GitHub issues and any alert source the project names. Find work. Write tostate/triage.md.
Algorithm
Fetch open GitHub issues labeled
bug.Fetch open GitHub issues labeled
enhancement.Override priority from a
Priority Nlabel when one is present, using this
mapping. The label vocabulary and the column vocabulary are different, and
until this table existed nothing said how one became the other:Label prioritycolumnPriority 1criticalPriority 2highPriority 3mediumPriority 4lowIf an issue carries more than one, take the most severe and note the clash in
Warnings — two priority labels is a human disagreement, not something to
average away.With no
Priority Nlabel, fall back on the type label:highforbug,mediumforenhancement. An issue with neither ismedium, so nothing is
silently dropped for want of a label.Deduplicate by issue number before appending.
Append to
state/triage.mdwithstatus=newand an emptyspec, through
the helper — never by hand-editing the table:python3 "${CLAUDE_PLUGIN_ROOT}/scripts/triage_state.py" upsert --state state/triage.md \ --finding "<title>" --source "GitHub #<n>" --priority <p> --status newBridge the inbox. Findings written as prose in
inbox/needs-human.mdare
invisible to a loop that discovers from code; a real loop once reported
itself idle in front of sixty-four open findings for exactly this reason.python3 "${CLAUDE_PLUGIN_ROOT}/scripts/inbox_to_triage.py" # dry run python3 "${CLAUDE_PLUGIN_ROOT}/scripts/inbox_to_triage.py" --apply # add the rowsIt is create-only: an existing row's status belongs to the loop, and the
bridge never resets it.
Output Format
Markdown table rows, one per finding. Columns:finding | source | priority | spec | status
priority is one of critical, high, medium, low — the four values step
3 produces, and nothing else.
| Report timeout on 50k transactions | GitHub #42 | high | | new |
| Sandbox credential refresh fails | GitHub #156 | medium | | new |Warnings
Anything the run surfaces that is not a row goes here, under its own heading
beneath the table, as one bullet each. The table has no column for it, and a
warning with nowhere to go is a warning that gets dropped:
#### Warnings
- PR #2451 has no `Fixes #` line — the ticket it closes cannot be derived.
- Issue #42 carries both `Priority 1` and `Priority 3`; took `critical`.Write the heading even when there is nothing under it, with - none. An absent
section reads the same whether the check ran clean or never ran at all.
Environment
ghauthenticated (orGH_TOKENset) for the GitHub API.
Do NOT
- Modify existing rows (only append new findings).
- Close findings (leave that to the loop).
- Comment on issues or PRs unless the project has an idempotent script for it —
a hand-written status comment is written twice the next morning.
Gotchas
- Never hand-edit the table. A finding containing
|is escaped on write and
unescaped on read bytriage_state.py; a hand edit breaks the row silently
and the loop re-files it forever. - Two
Priority Nlabels on one issue is a human disagreement; take the most
severe and say so in Warnings, never average. - The inbox bridge only files
##headings whose text is not stamped
RESOLVED/CLOSED/SUPERSEDED (uppercase) or struck through. A closure stamp in
the body, not the heading, does not count. - Prettier rewrites table cells (strips spaces around inline code), which
changes thesourcekey.initaddsstate/triage.mdto.prettierignore;
keep it there.