Skip to content
Productivity
Command

/triage-prs

Sync open GitHub PRs into the github-pr tracker, rank the untriaged ones for merge priority, and spawn /review-contribution sessions for the ones worth a deep look

From plugin
nimbalyst
2.1k54 skills3 agents54 commands3 MCP
> /plugin marketplace add nimbalyst/nimbalyst
> /plugin install nimbalyst-wiki@nimbalyst

Command definition

triage-prs.md
name: triage-prs
description: Sync open GitHub PRs into the github-pr tracker, rank the untriaged ones for merge priority, and spawn /review-contribution sessions for the ones worth a deep look

Triage Open GitHub PRs

Keep the `github-pr` tracker in sync with GitHub, then help me decide two things for every PR that hasn't been looked at yet:

1. **Priority** — how important is this to merge, relative to everything else in the queue? (`low` / `medium` / `high` / `critical`) 2. **Is it worth a deep review right now**, or is it blocked (CI failing, conflicts, needs contributor changes) / clearly out of scope / too stale to bother with yet?

For the ones worth a deep review, let me pick a subset and spawn isolated Nimbalyst sessions that run `/review-contribution <PR#>` against each — same dispatch pattern as `/review-multiple-contributions`, throttled to N at a time.

This command does **not** do the deep review itself. It's triage: fast, metadata-only (`gh pr view` / `gh pr checks`, no diffs), meant to answer "what order should I work through this queue in," not "is this PR safe to merge." That's `/review-contribution`'s job.

Usage

`/triage-prs [using <model>] [max <N> at a time]`

Both are optional and only affect the spawn step in Step 6:

  • `using <model>` — model for spawned `/review-contribution` sessions. Same

resolution table as `/review-multiple-contributions` (`opus`, `sonnet`, `haiku`, `gpt-5`/`codex`, or a passthrough `provider:model` string). If omitted, spawned sessions inherit this session's model (`inheritModel: true`).

  • `max <N> at a time` — concurrency for spawning, default **3**, clamp to

`[1, 10]`.

Steps

1. Fetch open PRs from GitHub

gh pr list \
  --state open \
  --limit 200 \
  --json number,title,url,author,headRefName,baseRefName,isDraft,createdAt,updatedAt

(`authorAssociation` is not a valid `--json` field on `gh pr list`/`gh pr view`; get it per-PR via `gh api repos/{owner}/{repo}/pulls/<pr> --jq .author_association` when needed in Step 3.)

Filter out PRs where `isDraft` is `true`.

2. Sync the tracker

Pull only the **non-terminal** items — the working set this command acts on. `complete`/`rejected` items are already closed out and both sync steps below explicitly leave them alone, so dumping every historical PR (the 500 cap is mostly terminal) into context is pure token waste:

tracker_list({
  type: "github-pr",
  where: [
    { field: "status", op: "!=", value: "complete" },
    { field: "status", op: "!=", value: "rejected" }
  ],
  limit: 500
})

Dedupe on `prNumber`, not URL (URLs can shift if a fork is renamed).

Edge case: a PR that was previously merged/closed (terminal) and then **reopened** on GitHub won't be in this filtered set, so it'll be re-created as a fresh `backlog` item rather than reconciled in place — that's acceptable (a reopened closed PR genuinely warrants fresh triage). Don't widen the filter to catch it; the full-scan cost isn't worth that rare case.

  • **Already tracked** → leave `status`, `priority`, and `notes` alone for now

(they may already have maintainer-set values) — it gets re-evaluated in Step 4 only if `status` is still `backlog`.

  • **Not tracked** → create it:
tracker_create({
  type: "github-pr",
  title: "<PR title>",
  fields: {
    prUrl: { url: "<pr url>", label: "#<number>" },
    prNumber: <number>,
    author: "<author.login>",
    headBranch: "<headRefName>",
    baseBranch: "<baseRefName>",
    status: "backlog"
  }
})

**Close the loop on merged/closed PRs.** For each tracked item whose `status` is not yet `complete` or `rejected` and whose `prNumber` is **not** in the open-PR list from Step 1, check what happened on GitHub:

gh pr view <prNumber> --json state,mergedAt,closedAt,title

(If an old item is missing `prNumber`, find it with `gh pr list --state all --search "<distinctive title words>" --json number,state,mergedAt,title`.)

Then update the tracker so the board reflects reality:

  • `state: MERGED` → `tracker_update` with `status: "complete"` and a note like

`"Merged on GitHub <mergedAt date>."` (prepend it; keep any useful prior review note in parentheses). Backfill `prUrl`/`prNumber` if they were missing.

  • `state: CLOSED` (not merged) → `status: "rejected"` with

`"Closed on GitHub <closedAt date> without merge."`

  • Still `OPEN` (e.g. it was just past the `--limit`, or re-opened) → leave it

alone.

Surface every item updated this way in the report (Step 5).

This command only **creates** tracker items during sync — it never deletes. Review-verdict status transitions (`inspecting` → `needs-review`/`safe`) are owned by `/review-contribution` and the maintainer. The **only** `status` writes this command makes are the merged/closed reconciliations above, which mirror GitHub facts rather than making a judgment call.

3. Gather triage signals for untriaged PRs

"Untriaged" = tracker items with `status: backlog` (new ones from Step 2, plus any left over from a previous run that never got reviewed).

For each untriaged PR, in parallel:

gh pr view <pr> --json number,title,author,authorAssociation,body,additions,deletions,changedFiles,files,labels,createdAt,updatedAt,mergeable,mergeStateStatus,reviewDecision,isCrossRepository
gh pr checks <pr>

Do **not** run `gh pr diff` or read file contents — this is a metadata-only pass. Derive, per PR:

  • **Age** — days since `createdAt`, and days since `updatedAt` (staleness).
  • **Size** — XS (<20 lines) / S (<100) / M (<400) / L (<1000) / XL (1000+),

from `additions + deletions`.

  • **Sensitive-area touch** — does `files[].path` match auth, sync/collab,

IPC/main-process, persistence/DB, or other areas called out as high-blast-radius in `CLAUDE.md`? Flag if so — informs priority and whether it needs `/review-contribution`'s deeper analysis rather than a quick maintainer glance.

  • **CI status** — passing / failing / pending / no checks, from `gh pr
Read more
@nimbalyst
Ships withnimbalyst

Nimbalyst - The open-source visual workspace for Claude Code, Codex, and OpenCode. Run multiple coding agents in parallel, edit their work visually in markdown, mockups, and diagrams, and track tasks. Free, MIT-licensed desktop app for macOS, Windows, Linux, with mobile companion for iOS and Android.

2.1k16 skills3 agents3 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
2.1k
Star history of nimbalyst/nimbalyst on GitHub, a chart by star-history.com

Other commands on nimbalyst.

analyze-sessions

analyze-sessions

Command

Audit recent AI coding sessions to find repeated mistakes, speed losses, and missed Nimbalyst tool usage — then propose harness…

@nimbalyst@nimbalystInstall Command
audit-updates

audit-updates

Command

Triage pnpm audit findings and produce a prioritized, supply-chain-cautious package-update plan, then apply approved batches

@nimbalyst@nimbalystInstall Command
autofix-issues

autofix-issues

Command

Survey recently triaged GitHub issues, propose the ones safe to fix without a product decision, and fan the selected ones out to…

@nimbalyst@nimbalystInstall Command

More commands from other plugins.

analyze-cohorts

analyze-cohorts

Command

Perform cohort analysis on user data — retention curves, feature adoption, and engagement trends

@phuryn@phurynInstall Command
again

again

Command

PUA Again — 用于再试试、换个方法、别放弃、为什么还不行、同一路径失败多次;要求停止微调同一思路,改用本质不同方案。

pua2mo20k
@tanweai@tanweaiInstall Command