agentleFS
rlajousrlajous/claude-code-commands/skills/review-watch/SKILL.md

review-watch

Skill30 starsChanged 3 months agoMITView on GitHub

Review pull requests that requested your review, in a loop until clean. Runs cheap deterministic checks (linters + a known-issues ruleset) first, then the full review fan-out, posts REQUEST_CHANGES when it finds problems, and APPROVE plus a human-readable change brief when the PR is clean. Use when the user asks to "review the PRs waiting on me", "auto-review", "watch for review requests", "drain the review queue", or passes a PR URL to review-and-decide.

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 2 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

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

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

    If the host cannot expose the loaded path, use PLUGIN_ROOT, then CLAUDE_PLUGIN_ROOT, only to locate skills/review-watch/SKILL.md.

    line 17
  2. Very specific:

    Read the reviewed-SHA ledger .git-workflow/.review-watch-reviewed (legacy fallback .claude/.review-watch-reviewed).

    line 39
  3. Very specific:

    If repo#number@headRefOid is already in the ledger, skip this PR (nothing new since the last review).

    line 45
  4. Distinctive:

    Run the fast, mechanical checks first so obvious problems cost nothing.

    line 59
  5. Very specific:

    Stop without reviewing unless reviewWatch.enabled is exactly true.

    line 65
  6. Distinctive:

    If the repo is not available locally (a PR on someone else's repo you have not cloned), skip the linters and note it — Tier 2 still covers …

    line 77
  7. Very specific:

    If --comment-only was passed, force REVIEW_EVENT=COMMENT after resolution.

    line 109
  8. Very specific:

    When the PR is clean (HAS_BLOCKING=false, whether the posted event is APPROVE or COMMENT):

    line 131

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “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

Cross-runtime: follow runtime compatibility for invocation, delegation, configuration precedence, state paths, and permissions.

You are the worker side of the review-watch tool. The skill-local scripts/review-watch.sh daemon listens for PRs where your review was requested and pings you; this skill does the actual review and decides whether to request changes or approve. Goal: loop a PR until it is clean, cheaply. Follow each step in order.

Step 1: Parse Arguments and Pick Targets

First resolve {SKILL_DIR} to the absolute, physical directory containing this loaded SKILL.md. If the host cannot expose the loaded path, use PLUGIN_ROOT, then CLAUDE_PLUGIN_ROOT, only to locate skills/review-watch/SKILL.md. Verify requested resources exist. Never substitute an empty variable or silently fall back to /scripts.

  • --doctor → run bash "{SKILL_DIR}/scripts/review-watch-tools.sh" --doctor, report its output, and exit. This checks paths, dependencies, configuration, and gh authentication without querying PRs, publishing reviews, or changing GitHub state.
  • --daemon-command → run bash "{SKILL_DIR}/scripts/review-watch-tools.sh" --daemon-command, print the absolute command unchanged so the user can paste it into another terminal, and exit.
  • A PR URL or number → review just that PR.
  • --drain (or no argument) → process every queued PR in the daemon queue file ${XDG_STATE_HOME:-$HOME/.local/state}/git-workflow/review-watch-queue.jsonl (dedupe by repo#number@headRefOid; newest entry per PR wins). Remove entries as you finish them. New entries include the nullable PR-author login as author; accept older entries where that field is absent and fetch the author with the PR metadata below.
  • --comment-only → never post REQUEST_CHANGES/APPROVE, only a COMMENT review (safe mode).

For each target resolve {owner}/{repo} and PR number (parse from the URL, or use the current repo for a bare number).

Step 2: Skip Already-Reviewed Head SHAs

Read the reviewed-SHA ledger .git-workflow/.review-watch-reviewed (legacy fallback .claude/.review-watch-reviewed). Each line is repo#number@headRefOid. Fetch the PR head SHA:

gh pr view {PR} --repo {owner}/{repo} --json number,title,url,author,isDraft,baseRefOid,headRefOid,files,additions,deletions

If repo#number@headRefOid is already in the ledger, skip this PR (nothing new since the last review). If the PR isDraft, skip and note it.

Self-review guard: GitHub forbids REQUEST_CHANGES/APPROVE on your own PR. If the PR author is you (gh api user --jq .login), operate in --comment-only mode for this PR.

Step 3: Get the Diff

gh pr diff {PR} --repo {owner}/{repo}

Note the changed file list and languages. If the diff exceeds review.maxDiffLines (default 3000), work from the file list and read files individually.

Step 4: Tier 1 — Deterministic Checks (cheap, no model reasoning)

Run the fast, mechanical checks first so obvious problems cost nothing.

Resolve configuration once from .git-workflow/config.yaml, then the legacy .claude/config.yaml fallback. If neither exists, use these defaults: reviewWatch.enabled=false, reviewWatch.linters=auto, reviewWatch.knownIssues=references/known-issues.md, and review.postEvent=auto. Stop without reviewing unless reviewWatch.enabled is exactly true; an explicit --comment-only changes posting behavior but does not bypass this opt-in gate.

a) Project linters (only if the repo is checked out locally with deps). Use the resolved reviewWatch.linters. When it is auto, auto-detect and run against the changed files; when it is an explicit command, run that exact project-owned command:

  • JS/TS: npx eslint <changed> , npx tsc --noEmit
  • CSS/SCSS: npx stylelint <changed css>
  • Python: ruff check <changed> / flake8
  • Others: the project's configured lint command (.git-workflow/config.yaml → testing.lint).

If the repo is not available locally (a PR on someone else's repo you have not cloned), skip the linters and note it — Tier 2 still covers logic from the diff.

b) Known-issues ruleset. Resolve reviewWatch.knownIssues as follows: an absolute path is used as-is; for a relative path, prefer a matching project-root file, otherwise resolve it under {SKILL_DIR}. If the setting is absent, use the bundled {SKILL_DIR}/references/known-issues.md. Read its grep-style patterns and scan only changed diff lines. These are the "errors we already know": stray console.log, debugger, CSS !important abuse, inline styles, shipped TODO/FIXME, hard-coded colors, TS any, etc. If the configured file is missing, stop with the resolved path instead of silently dropping the deterministic checks.

Collect all Tier-1 findings with file, line, and the rule that fired. Anything at severity error/BLOCKING/HIGH is a blocker.

If Tier 1 found blockers → go straight to Step 6 and post REQUEST_CHANGES with those findings. Skip Tier 2 (do not spend the expensive review when there are already known errors to fix). This is the cost gate.

Step 5: Tier 2 — Full Review Fan-out (only when Tier 1 is clean)

Run the standard review: delegate, through the active host's subagent mechanism, to the specialized reviewers used by the review skill (pr-reviewer always; silent-failure-hunter, type-design-analyzer, pr-test-analyzer, comment-analyzer by changed-file type), in parallel. Hand each the PR number/repo, baseRefOid as BASE_SHA, headRefOid as HEAD_SHA, the changed-file list, and the diff.

Aggregate and de-duplicate their findings. Keep only findings with confidence ≥ 80 and drop the false-positive classes (pre-existing, linter-catchable, intentionally-silenced, formatter-style, speculative) — the same bar as the review skill. Assign each survivor a severity (BLOCKING / HIGH / MEDIUM / LOW).

Step 6: Decide and Post

Combine Tier-1 blockers and Tier-2 findings. Resolve review.postEvent from the same config (auto by default). Set {HAS_BLOCKING} to true when any BLOCKING/HIGH finding survived and set {SELF_AUTHORED_FLAG} to --self-authored only for the self-review case. Determine the event with the package's tested resolver:

REVIEW_EVENT="$(bash "{SKILL_DIR}/../review/scripts/review-event.sh" \
  --has-blocking {HAS_BLOCKING} {SELF_AUTHORED_FLAG})"

If --comment-only was passed, force REVIEW_EVENT=COMMENT after resolution. Never infer a more permissive event when the resolver reports invalid configuration.

  • REVIEW_EVENT=REQUEST_CHANGES. Build the review body: a one-line verdict, then each finding as severity — file permalink — what is wrong — suggested fix, using SHA permalinks (https://github.com/{owner}/{repo}/blob/{headRefOid}/{path}#L{line}, literal). Post:

    gh api "repos/{owner}/{repo}/pulls/{PR}/reviews" --method POST \
      -f body="$(cat <<'REVIEW_EOF'
    {REVIEW_BODY}
    REVIEW_EOF
    )" -f event="$REVIEW_EVENT"
  • No BLOCKING/HIGH (clean) → APPROVE or COMMENT as resolved. Post the same way with -f event="$REVIEW_EVENT", a short "looks good" body plus any remaining LOW/MEDIUM notes. A clean result triggers the human-readable change brief (Step 7) and ping even when safe mode or self-authorship forces the GitHub event to COMMENT.

Respect review.postToGitHub (ask | always | never, default ask): when ask, show the drafted review and confirm through the host's user-input mechanism before posting. Truncate bodies over ~65,000 characters.

Step 7: On Clean — Generate the Change Brief and Ping

When the PR is clean (HAS_BLOCKING=false, whether the posted event is APPROVE or COMMENT):

  • Generate the human-facing HTML decision brief by following /change-brief {PR} in Claude Code or $change-brief {PR} in Codex. Output goes to .git-workflow/change-brief/pr-{PR}/index.html.
  • Ping the human that it is ready:

    bash "{SKILL_DIR}/scripts/notify.sh" \
      "{owner}/{repo} · PR #{PR}" \
      "{AUTHOR_LABEL} — Ready for merge: {title}"

    Resolve {AUTHOR_LABEL} as @{author.login}, or unknown author when GitHub returns no author. This matches the daemon's initial review-request notification, which uses the same title and {AUTHOR_LABEL} — {title} as its message.

Step 8: Record and Loop

Append repo#number@headRefOid to .git-workflow/.review-watch-reviewed so this exact head SHA is not reviewed again. Remove the PR from the daemon queue file if you were draining it.

The loop is head-SHA driven: when the author pushes a fix, the daemon detects the new head SHA and re-queues the PR; running this skill again reviews only the new SHA. Repeat REQUEST_CHANGES → author fixes → re-review until a round posts APPROVE. Never re-review an unchanged SHA (the ledger prevents it).

Step 9: Report

Print a compact summary per PR: verdict (REQUEST_CHANGES / APPROVED / COMMENTED), Tier-1 vs Tier-2 finding counts, whether a change brief was written, and the PR URL.

Configuration Reference

SettingDefaultDescription
reviewWatch.intervalSeconds60Daemon poll interval
notifications.soundGlassShared notification sound name (reviewWatch.sound remains a fallback)
reviewWatch.lintersautoauto-detect, or an explicit lint command
reviewWatch.knownIssuesreferences/known-issues.mdDeterministic ruleset path
review.postToGitHubaskask | always | never
review.postEventautoauto (derive REQUEST_CHANGES/APPROVE) | comment

The daemon implementation and generic notifier are owned by the sibling notifications skill; the skill-local scripts here are compatibility wrappers. Enabling notifications.prActivity adds authored-PR review events to the same GraphQL poll without duplicating the daemon.

Error Handling

ScenarioAction
gh unauthenticatedStop with a hint to run gh auth login
Repo not available locallySkip Tier-1 linters, run Tier-2 from the diff, note it
PR authored by youFall back to COMMENT (cannot self-approve/request-changes)
Head SHA already reviewedSkip; nothing new
Node unavailable (change brief)Post the approval, skip the HTML, note it

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.