noahdgrant

ns-triage

Move issues and external PRs through the triage state machine, categorise, verify, write Agent Briefs, and route each to its next phase. Use when triaging a new issue, reviewing what needs attention on the tracker, or starting a unit of work from an issue.

noahdgrant 1 Updated 2w ago

Resources

2
GitHub

Install

npx skillscat add noahdgrant/nightshift/ns-triage

Install via the SkillsCat registry.

SKILL.md

Triage

Move issues on the project issue tracker through a small state machine, and route each one to the phase that picks it up next. This is the outer loop's entry point.

Read docs/agents/issue-tracker.md (how to reach the tracker, who counts as the team) and docs/agents/triage-labels.md (the label string for each role). If either is missing, load the ns-setup skill.

If the tracker config treats external pull requests as a request surface, triage covers them too: a PR is an issue with attached code, using the same roles and states, with the deltas marked "for a PR" below. Resolve a bare #42 to an issue or PR per the tracker config.

Every comment or issue posted to the issue tracker during triage must start with this disclaimer:

> *This was generated by AI during triage.*

Reference docs

Roles

Two category roles: bug (something is broken) and enhancement (new feature or improvement).

Seven state roles, each routing to a next phase:

State Meaning Next
needs-triage new, not yet evaluated triage
needs-info waiting on the reporter reporter, then triage
needs-repro a bug with no reproducible failure yet ns-troubleshoot
needs-define intent unclear, or the change is large ns-define
ready-for-agent Agent Brief written, small enough to build directly ns-build
ready-for-human brief written, but needs a human (hardware access, a judgement call, credentials) a person
wontfix will not be actioned none

For a PR, the states read against the attached code: ready-for-agent means a brief is attached and an agent should take the next step on the diff; ready-for-human means it's ready for a human to merge.

Every triaged issue carries exactly one category and one state. If state labels conflict, flag it and ask the maintainer before doing anything else.

State transitions: an unlabeled issue normally goes to needs-triage first, and from there to any other state. needs-info returns to needs-triage once the reporter replies. The maintainer can override at any time. Flag transitions that look unusual and ask before proceeding.

Gate policy

The gate policy comes from the prompt that started the run, and decides who applies the outcome. With no policy given, use stop.

  • gates: stop: recommend, then wait for the maintainer's direction before applying anything.
  • gates: auto: apply your own recommendation and continue. Grilling needs a human, so route an issue that needs it to needs-define or needs-info instead. A comment addressed to someone outside the team follows the tracker config's External comments setting: allow posts it, wait (the default) drafts it in your report and stops.

Invocation

The maintainer describes what they want in natural language. Interpret the request and act. Examples:

  • "Show me anything that needs my attention"
  • "Let's look at #42" (issue or PR)
  • "Move #42 to ready-for-agent"
  • "What's ready for agents to pick up?"

Show what needs attention

Query the issue tracker and present three buckets, oldest first:

  1. Unlabeled: never triaged.
  2. needs-triage: evaluation in progress.
  3. needs-info with reporter activity since the last Triage Notes: needs re-evaluation.

When PRs are in scope, include external PRs and tag each line [PR] or [issue]. Discovery surfaces only external PRs, so a collaborator's in-flight PR is not triage work. An explicitly named PR is always triaged regardless of author.

Show counts and a one-line summary per item. Let the maintainer pick.

Triage a specific issue or PR

  1. Gather context. Read the full issue or PR (body, comments, labels, author, dates; for a PR, the diff too). Parse any prior Triage Notes so you don't re-ask resolved questions. Explore the codebase using the domain glossary and ADRs (see docs/agents/domain.md). Run three checks, and report where you looked for each:

    • Duplicates: search open and closed issues for the same request by domain concept, not just the reporter's wording. A match is a duplicate: link it, and close this one as wontfix (duplicate) or merge the new detail into the original.
    • Redundancy: search the codebase for an existing implementation of the requested behavior. If found, it's an already-implemented wontfix (step 5).
    • Prior rejection: read .out-of-scope/*.md and surface any that resembles this request.
  2. Recommend. State your category and state recommendation with reasoning, the next phase it routes to, and a brief codebase summary relevant to the request. Under stop, wait for direction. Under auto, carry on.

  3. Verify the claim. Before any grilling, check that the claim holds up. For a bug, reproduce it from the reporter's steps using the commands in docs/agents/stack.md. For a PR, check out the diff and run the relevant tests. Report the result: confirmed (with code path), failed, or insufficient detail. A bug you can't reproduce routes to needs-repro when the report is plausible and detailed, or needs-info when it lacks the detail to try. A confirmed verification makes a much stronger brief.

  4. Grill (if needed). If a few rounds of questions would settle the request, load the ns-grilling and ns-domain-modeling skills and grill it into shape, sharpening domain terms and updating GLOSSARY.md/ADRs inline as decisions land. If it needs a spec or a redesign, route it to needs-define instead.

  5. Apply the outcome. Set the labels, then:

    • ready-for-agent: post an Agent Brief comment (agent-brief.md), then start the unit (below).
    • ready-for-human: same structure as an Agent Brief, plus why it can't be delegated (judgement calls, hardware or external access, design decisions, manual testing).
    • needs-repro: post Triage Notes with the reporter's steps, what you tried, and what happened. Next: ns-troubleshoot.
    • needs-define: post Triage Notes with what's settled and the open questions. Next: ns-define.
    • needs-info: post Triage Notes (template below).
    • wontfix: close the issue, with the comment depending on why:
      • Already implemented: point to where it lives. Leave .out-of-scope/ alone: that KB is for rejected requests, not built ones.
      • Duplicate: link the original.
      • Rejected (bug): give a polite explanation, then close.
      • Rejected (enhancement): write to .out-of-scope/, link to it from a comment, then close (out-of-scope.md).
    • needs-triage: apply the label. Optional comment if there's partial progress.
  6. Hand off. Under stop, report the outcome and the next phase, and stop. Under auto, load the next phase's skill (ns-build, ns-troubleshoot or ns-define) for ready-for-agent, needs-repro and needs-define. If that skill isn't installed, report the routing and stop. Every other state stops.

Start the unit (ready-for-agent)

The unit ID is <issue-number>-<slug>, with a short kebab-case slug from the title (142-uart-timeout).

  1. Run ns worktree new <unit-id> and read path and artifacts from its JSON. Without ns: git worktree add ../<repo-name>.worktrees/<unit-id> -b ns/<unit-id>, create .ns/<unit-id>/ inside it, and append .ns/ to $(git rev-parse --git-common-dir)/info/exclude if it isn't listed.
  2. Write the same Agent Brief to <worktree>/.ns/<unit-id>/brief.md, with a link to the issue under it:
---
unit: 142-uart-timeout
phase: triage
status: pass
base: main          # the branch the worktree came from
updated: 2026-10-08T21:14:00Z
---
Issue: <issue URL>

## Agent Brief
...

The unit is started when the issue carries ready-for-agent, the brief comment is posted, and brief.md exists in the worktree with status: pass.

Quick state override

If the maintainer says "move #42 to ready-for-agent", trust them and apply the label directly. Confirm what you're about to do (label changes, comment, close), then act. Skip grilling. If moving to ready-for-agent without a grilling session, ask whether they want an Agent Brief written. The unit starts only once a brief exists.

Needs-info template

## Triage Notes

**What we've established so far:**

- point 1
- point 2

**What we still need from you (@reporter):**

- question 1
- question 2

Capture everything resolved during grilling under "established so far" so the work isn't lost. Each question is specific and actionable ("which firmware version was on the board?"), never a generic request for more info.

Resuming a previous session

If prior Triage Notes exist on the issue or PR, read them, check whether the reporter has answered any outstanding questions, and present an updated picture before continuing. Skip questions already resolved.

Categories