agentleFS
combinautcombinaut/ai-agent-orchestration/skills/review-prs/SKILL.md

review-prs

Skill2 starsChanged 20 days agoMITView on GitHub

List open PRs that request your review — author, freshness, CI/conflict blockers — or watch them live and auto-dispatch a Herdr Codex pane to review or re-review each Ready PR

10 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

7 rules. 0 are common, 3 are distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 9 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read-only for the orchestrator: this skill never merges, closes, or assigns reviewers itself.

    line 18
  2. Very specific:

    Read through orch-settings (docs/settings.md), which prints the resolved values.

    line 22
  3. Distinctive:

    After the tables, add only what the buckets do not already say: months-old parked PRs, or which Ready PRs you just dispatched.

    line 62
  4. Very specific:

    Run list with the same scope (tables + snapshot).

    line 66
  5. Distinctive:

    Start the watcher in the background, scope explicit, its output appended to a log in your scratchpad:

    line 68
  6. Very specific:

    Default interval 120s (--interval overrides).

    line 74
  7. Distinctive:

    Run one dispatch per queue item in the background:

    line 109

“Common” is measured: kept by at least 6 in 10 of the 9 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Review PRs

Scripts: ~/.claude/skills/review-prs/scripts/ (prs.sh runs prs.py on the orchestration's Python 3.11+; dispatch.sh; watch-events.sh). State: ~/.cache/review-prs/.

  • list (default): open PRs that still request your review (review-requested:@me), bucketed by whether you can review now.
  • watch: the list once, then a background watcher that reports each change. It stays silent while nothing changes.
  • auto-dispatch (default on watch, and whenever the user asks to review/dispatch): for each 🔔 Ready for your review PR, open a Herdr sibling pane and start Codex on $ORCH_CODEX_WORKER_MODEL ($ORCH_CODEX_SMART_MODEL when only that one is set) to review or re-review it.

Read-only for the orchestrator: this skill never merges, closes, or assigns reviewers itself. Codex may post the GitHub review (that is the point of dispatch). Pass --no-dispatch to list/watch without launching agents.

Settings

Read through orch-settings (docs/settings.md), which prints the resolved values; never read ~/.claude/orchestration.toml directly, since an empty providers.enabled there still means Codex is on:

  • models.codex_worker (ORCH_CODEX_WORKER_MODEL): the review model; when it is empty or a <placeholder>, models.codex_smart serves. Applies only when codex is in ORCH_PROVIDERS; then, both empty or a <placeholder>: dispatch nothing and tell the user to fill one in.
  • providers.enabled (ORCH_PROVIDERS): without codex, dispatch-queue plans an empty queue with a note and dispatch.sh refuses; list and watch as with --no-dispatch, and say once in one line that Codex reviews are off.
  • watchers.pr_scope (ORCH_WATCHERS_PR_SCOPE): the scope when no scope flag is given outside a repo.

Repo settings of the PR's clone shape the prompt: guard.big_repo forbids broad Git reads, legacy.scan adds the legacy check.

Arguments

  • watch — start watch mode. Without it, list once.
  • --repo owner/name — one repo. --repo name works together with --org.
  • --org ORG — every repo in the org.
  • --all — every PR requesting you, anywhere.
  • --actionable — list only Ready-for-review PRs.
  • --no-dispatch — never open Herdr/Codex panes.

With no scope flag, the script uses the GitHub repo of the current directory, else watchers.pr_scope, else --all.

List

~/.claude/skills/review-prs/scripts/prs.sh list [scope] [--actionable]

It prints markdown tables. The user cannot see tool output rendered: copy the script's output into your reply verbatim, as markdown. Every table stays a table, and every PR stays its full bare https://github.com/... URL. Never answer "see above", never summarize the tables into prose or bullets, and never shorten a URL to #1234.

The buckets, first match wins:

BucketTest
📝 DraftsisDraft
🔴 Conflictingmergeable == CONFLICTING
❔ Merge state unknownmergeable == UNKNOWN after one retry; never dispatched
🔴 CI failingrollup FAILURE / ERROR
⏳ Waiting on CIrollup PENDING / EXPECTED
🔔 Ready for your reviewnone of the above

Three short columns: PR, Title (≤60 chars), Author · status. Your own authored PRs and bot README-sync titles are hidden.

After the tables, add only what the buckets do not already say: months-old parked PRs, or which Ready PRs you just dispatched.

Watch

  1. Run list with the same scope (tables + snapshot).
  2. Unless --no-dispatch, run Auto-dispatch below for the current Ready queue.
  3. Start the watcher in the background, scope explicit, its output appended to a log in your scratchpad:

    ~/.claude/skills/review-prs/scripts/prs.sh watch [scope] >>"<scratchpad>/pr-watch.log" 2>&1

    Default interval 120s (--interval overrides). Follow it with one Monitor on ~/.claude/skills/review-prs/scripts/watch-events.sh "<scratchpad>/pr-watch.log": it prints only event lines, from line one on first attach and after the last line it read on a restart, so no event is skipped.

  4. Tell the user: you only speak on changes; watch lasts until the session ends; "stop the PR watch" ends it. On new: / ready: events for actionable PRs, run Auto-dispatch again (skip SHAs already dispatched).

Reporting a watch event

PrefixMeaning
new:PR started requesting your review
changed:draft/CI/conflict/new commits
ready:became reviewable (or new commits while still ready)
cleared:open, but no longer requesting you
merged: / closed:left the list with real GitHub state
PR fetch failing 3x in a row: / recovered:auth/network

Relay in plain words with full bare URLs. End with now: counts. PushNotification for new: only: Review requested: PR <n> (<short title>) by <author>.

Auto-dispatch (Herdr + Codex)

Requires HERDR_ENV=1. If not inside Herdr, say so and stop dispatch (list/watch still fine).

Queue

~/.claude/skills/review-prs/scripts/prs.sh dispatch-queue [scope]

JSON fields per item: url, number, title, author, repo, sha, kind (review | re-review | re-request), agent (rev<number>-<sha7>-<repo hash>, plus -<4 hex> for a re-request; unique per repo and head), cwd (local clone or null), model.

cwd comes from the clones of the open work, the current directory, or ~/Projects/<owner>/<name>; a clone matches when its origin is the repo, or else its upstream (a fork of it), and a clone whose origin is the repo wins. Skip entries with cwd: null and tell the user no local clone was found.

Skip entries already marked for the same sha, pending, blocked, or done (script does this). Each dispatch-queue result includes every blocked current head with its recorded reason; a new head or an explicit release-dispatched clears that condition. It also lists in stuck every review pending for 30 minutes or more (url, sha, agent, pane, minutes); nothing expires, so release or finish it by hand. Concurrency: up to 3 Codex reviews at once. Queue the rest; when any in-flight review finishes, start the next queued item until 3 are running again (or the queue is empty).

Launch one review

Run one dispatch per queue item in the background:

~/.claude/skills/review-prs/scripts/dispatch.sh "<url>" <number> "<title>" "<author>" <sha> <kind> <agent> "<cwd>" <owner/repo> [right|down]

Set ORCH_REVIEW_EXTRA_STEPS when dispatching to add review-specific instructions; dispatch.sh includes them in the authorized review prompt. Any follow-up sent to a review pane must repeat that it must post without asking for confirmation.

It first claims the SHA (pending, under a lock); a head another dispatch already claimed or finished prints TAKEN <sha> and exits 3 before any pane, agent or worktree. It then records the ids of your submitted reviews on the PR; when that read fails it prints SNAPSHOT FAILED, releases the claim and sends nothing. Then it checks out a detached worktree at the SHA under ~/.cache/review-prs/worktrees/<agent> (fetching pull/<n>/head when the clone lacks it; if GitHub's pull ref lags, it validates and fetches the PR fork's owner/repository/ref directly). If neither source provides the SHA it prints HEAD FAILED and releases the claim. It splits a sibling pane there in the current tab without taking focus (down when the pane is already narrow; PANE=<id> reuses an empty pane instead), starts Codex on $ORCH_CODEX_WORKER_MODEL in that worktree (--cd, also for a PANE) without loading the PR's AGENTS.md (-c project_doc_max_bytes=0; review rules come from the base branch), sends the review prompt and waits for the turn to end. The prompt tells Codex to post through python3 <orch>/lib/github_write.py --timeout 240 api -X POST repos/<owner>/<repo>/pulls/<number>/reviews --input -, with the JSON payload (commit_id, event, body, inline comments) on stdin from a quoted heredoc and no temporary files (not gh pr review). The wrapper serializes writes and retries only a confirmed secondary-limit/abuse response; other errors are reported without replaying a write. Codex replies APPROVE|COMMENT|REQUEST_CHANGES — <url> and ends its turn: no polling, no waiting for CI or replies.

Output lines: WORKTREE <path> and PANE <id> AGENT <name> PR <url> at start; PROMPT_EXIT <n> and the agent's last lines at the end. HEAD FAILED <sha> ... means neither the pull ref nor validated fork ref contained the requested SHA; its claim is released. WORKTREE FAILED ... means checkout setup failed; its claim is released. Codex 0.164.0's 1 hook needs review before it can run and N hooks need review before they can run screens are never accepted: HOOKS UNTRUSTED <hook list> records the SHA as blocked with reason hooks need review, closes the pane it opened, and removes its worktree. It never sends keys to approve or trust hooks. The screen is read again after an update banner is dismissed. An incomplete prompt stays pending: a bounded transcript cannot reliably prove that a turn never started, except that UNDELIVERED agent_blocked followed by RELEASED <sha> closes a pane this dispatch opened and releases its claim for retry. Then either LASTREVIEW <state> <time> <url> (your submitted review of the dispatched SHA whose id was not among your reviews before the prompt; the SHA is marked done), or INCOMPLETE no review of <sha> (the SHA stays pending when a prompt did not post a review). A release closes the pane it opened first, so the agent name is free for the retry; a pane passed in as PANE is never closed or has its worktree removed. Then CLOSED <pane> and REMOVED <worktree> (a pane it opened, review posted, prompt finished) or LEFT OPEN <pane>; DONE. VERIFY FAILED means the reviews could not be read: the SHA stays pending and the pane open; check the PR by hand. After closing a LEFT OPEN pane yourself, remove its worktree: git -C <cwd> worktree remove --force <worktree>. gh calls stop after 45 seconds.

Tell the user which pane/agent is reviewing which PR (full URL). When the review finishes you must announce the outcome — silence after dispatch is not enough.

Report and close

Report in one short line with the full bare PR URL:

Take it from LASTREVIEW only (a trailing SWEPT means the review body carries the sweep marker): the agent's one-liner is a claim, the posted review is the fact. With INCOMPLETE, say Review not posted with the PR URL and a one-sentence note from the agent's lines, whatever verdict the agent printed — do not invent an approval.

Close review panes only with ~/.claude/coordinator/watchers/close-pane.sh <pane_id>: it marks the pane closed on purpose, so the workers watcher reports it as closed, not dead. dispatch.sh does this itself for a pane it opened once the review is posted and the prompt finished. For LEFT OPEN (no review yet, timeout, blocked, or a pane passed in as PANE), report first and close only when it is done or the user says to abandon it. Never close panes you did not create for this dispatch.

Re-review

dispatch-queue emits kind: re-review when the same URL was marked before with a different head SHA (new commits while still requesting you, or after CI became green again). Same launch path; prompt Mode is re-review.

A manual review of a moved head is re-queued once when an older completed dispatched SHA remains recorded; the re-review claim prevents another duplicate.

dispatch-queue emits kind: re-request when the head already has a done review and the PR asks for your review again personally (the author clicked re-request; a team-only request does not count, because a member's review does not clear it). dispatch.sh claims the head again with claim-dispatched --retake, and the agent name gets a suffix so it never meets the pane of the earlier review.

Sweep in the review

The prompt runs the repo's review.finalize_commands (default /finalize-sweep in report-only mode, with the base ref, the PR URL and 25 slices as inputs; [] leaves the sweep out) on your first review of a PR and on a head you would APPROVE, and skips it when one of your own earlier reviews holds a <!-- finalize-sweep {"head":"<sha>"} --> marker for that head. The findings table goes in the review body with that marker as its last line before the trailer; fix findings block APPROVE and nit findings never do. last-review marks a review SWEPT when its body carries the marker of the head, and dispatch.sh prints SWEEP MISSING for a first review or an APPROVE without it.

Rules

  • Orchestrator never merges, closes, or assigns reviewers. Codex posts reviews only.
  • Do not dispatch Draft / CI-failing / CI-running / Conflicting buckets — only Ready.
  • At most 3 concurrent Codex reviews unless the user raises the limit. When one finishes, report → close pane → fill from the queue.
  • A PR missing from search is not proof it is gone — watcher checks up to 10 absent PRs per poll through GraphQL and keeps direct or team requests. A failed departure read retains that entry without adding a miss, reports READFAIL, and allows other PR updates to continue.
  • merge state unknown is not a pass — list retries once.

Common pitfalls

  • GitHub MCP often misses private org repos — use gh (the script does).
  • review-requested:@me clears after you (or Codex) submit a review. A PR you reviewed whose head moved stays in the queue without a new request (reviewed-by:@me), so watch mode re-reviews it after further pushes.
  • GraphQL search must paginate; mergeStateStatus needs the merge-info-preview Accept header.
  • Herdr agent start needs an empty shell pane; it does not create layout — dispatch.sh splits first.
  • Agent names: [a-z][a-z0-9_-]{0,31}, unique among live agents (dispatch-queue makes them so).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.