SLOPSHOPPER

review-queue

Shows how many open GitHub pull requests are waiting on your review in the status line.

newstatusprocesstimer
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · review-queue
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts ⚠ review-queue: You're a slacker, McFly: reviews: ?
README

review-queue

Puts the number of open pull requests waiting on your review in the Claude Code status line:

You're a slacker, McFly: 9 reviews

It counts open PRs where you are a requested reviewer, skipping archived repositories, the same set as GitHub's review-requested:@me search. The count is fetched when the session starts and every five minutes after. If gh fails (not logged in, offline), the line reads You're a slacker, McFly: reviews: ?.

Requirements

  • gh, logged in (gh auth login)

How it works

This is a mod: a plugin of function hooks (hooks/register.ts) rather than commands or agents. On session.start it runs gh api search/issues for is:pr is:open review-requested:@me archived:false, reads total_count, and sets the line with $.ui.status. A $.clock.every timer repeats that every five minutes.

To change the wording, edit PREFIX in hooks/register.ts; to change how often it refreshes, edit REFRESH_MS.

Developing

claude plugin validate --strict plugins/review-queue
claude plugin test plugins/review-queue
claude --plugin-dir plugins/review-queue    # load it from disk; edits hot-reload

Once Claude Code has loaded the mod from disk, .claude-plugin/types/ holds the API typings and tsc -p plugins/review-queue type-checks it.

Source 1 files
hooks/register.ts 32 lines
1import type { Register, EngineInterface } from 'claude-code'
2
3const REFRESH_MS = 5 * 60 * 1000
4export const PREFIX = "You're a slacker, McFly:"
5const QUERY = 'is:pr is:open review-requested:@me archived:false'
6
7export async function refresh($: EngineInterface): Promise<void> {
8  try {
9    const { exitCode, stdout } = await $.process.run(
10      ['gh', 'api', '-X', 'GET', 'search/issues', '-f', `q=${QUERY}`, '-f', 'per_page=1', '--jq', '.total_count'],
11      { timeoutMs: 15_000 },
12    )
13    const count = Number.parseInt(stdout.trim(), 10)
14    if (exitCode !== 0 || Number.isNaN(count)) {
15      $.ui.status(`${PREFIX} reviews: ?`)
16      return
17    }
18    $.ui.status(`${PREFIX} ${count} review${count === 1 ? '' : 's'}`)
19  } catch {
20    $.ui.status(`${PREFIX} reviews: ?`)
21  }
22}
23
24export const register: Register = on => {
25  on('session.start', async ($, e, next) => {
26    const started = await next(e)
27    void refresh($)
28    $.clock.every(REFRESH_MS, () => void refresh($))
29    return started
30  })
31}
32