Install
openclaw skills install @arunjeetsingh/review-prReview a PR, reconcile prior feedback, and watch for the author's fix
openclaw skills install @arunjeetsingh/review-prReview one pull request repeatedly until it has no blocking issues within the agreed
review scope. Use GitHub comments as the durable review ledger and a background watch (see
../WAITING.md) for the polling loop.
Invoking this skill authorizes it to, without pausing for a per-step confirmation: post
one top-level GitHub PR comment per completed review cycle, and create or reactivate a
background watch that keeps running GitHub reads (and, on a qualifying author response,
another review cycle plus another comment) after this invocation ends — potentially
across sessions, depending on which host mechanism ../WAITING.md selects for your
runtime. It never pushes code, edits or deletes comments, resolves threads, approves,
merges, labels, or closes the PR, and never modifies the PR branch. If you need to know
exactly how to list, pause, or permanently stop a watch this skill armed, see the "Arm
the Watch" section below and ../WAITING.md's host-mapping table before invoking it in
an environment where an unattended background job would be unexpected.
Require one of:
owner/repo#number; orIf a number cannot be resolved unambiguously from the current repository, ask for the repository. Do not guess.
Support two modes:
start (default): perform an immediate review, post the result, and start monitoring if
issues remain;monitor: poll for a qualifying author response and re-review only when triggered.gh CLI for all GitHub reads and writes, including gh pr comment --body-file for the cycle's top-level comment. Use a connected GitHub integration only where it provides data the CLI cannot, and use the signed-in browser only as the final fallback after both authenticated API paths fail.gh api graphql or the bundled GitHub review-comment workflow for reviewThreads, isResolved, isOutdated, anchors, and replies. Flat comment reads are not a complete history.../WAITING.md's host mapping: on OpenClaw a cron job with a trigger.script gate, on Codex a heartbeat (inspect active and paused automations by the immutable marker; reuse a same-task match; treat a foreign or ambiguous match as a conflict), on Claude Code a Monitor task ID retained for this session. A durable GitHub marker proves review state, never that this task owns a watch.If GitHub reads or writes fail, do not infer state and do not post a partial review. A 404 can mean missing access rather than a missing PR. Leave an existing watch armed and report the failed run unless reliable authenticated metadata proves a terminal state.
Before inspecting for new issues:
addressed, partial, unaddressed, regressed, or superseded-with-reason.Do not copy old comments blindly. Re-establish each issue from current evidence.
Make the first review cycle the broad discovery pass. Inspect the complete PR across correctness, security, data loss, races, compatibility, tests, operability, and user-facing behavior; use independent parallel lenses when useful so material blockers are found together rather than serially. The first posted review establishes the baseline threat model, architecture, acceptance criteria, and blocking-invariant ledger.
After that baseline, keep the review scope frozen unless the user explicitly expands it or the PR materially changes its stated objective or architecture. On a follow-up cycle, post a new blocking finding only when it is one of:
For category 3, require specific evidence and explain why the path is blocking; do not use it as a license to reopen general discovery indefinitely. Do not turn design preferences, speculative concerns, theoretical edge cases, or merely underspecified operational details into new blockers. Treat useful operational detail as non-blocking P2/follow-up work and do not keep the watch armed solely for it.
Do not require a new architecture, trust boundary, or threat model during a follow-up cycle by default. If fixing a genuine blocker requires such an expansion, stop and ask the user to choose rather than silently moving the goalposts. In each follow-up result, classify every prior blocker and identify which allowed category justifies any newly reported blocker. A cycle is clean when no blocking finding remains under this frozen scope, even if optional P2 follow-ups could improve implementation polish.
Use priority labels such as [P1] when they help the author triage. Include exact paths, lines, behavior, and the required outcome. Keep optional P2/follow-up notes out of an issues verdict; mention them only in the chat handoff when materially useful.
Append one hidden marker to every comment posted by this skill. Compute workflow_id first. Compute cycle_key only from stable cycle inputs, and derive batch_id as the first 16 lowercase hexadecimal characters of cycle_key. Then render the visible body, including codex-addressed:BATCH_ID, and compute body_digest from those exact UTF-8 visible-body bytes. The body digest is validation metadata and is deliberately excluded from cycle_key.
<!-- review-pr-state
schema=1
repo=OWNER/REPO
pr=NUMBER
workflow_id=SHA256(OWNER/REPO#NUMBER|REVIEWER)
cycle_key=SHA256(WORKFLOW_ID|REVIEWED_HEAD|TRIGGER_KIND|TRIGGER_NODE_ID)
batch_id=FIRST_16_HEX(CYCLE_KEY)
cycle=N
reviewed_head=FULL_OID
trigger_kind=initial|manual|issue_comment|review|review_reply
trigger_node_id=INITIAL_OR_GLOBAL_GRAPHQL_NODE_ID
verdict=issues|clean
reviewer=LOGIN
body_digest=SHA256(EXACT_VISIBLE_BODY_UTF8)
-->
Accept a marker only when its containing top-level comment was authored by the authenticated reviewer and its schema, repository, PR, reviewer, workflow hash, cycle hash, batch ID, and visible-body hash all recompute correctly. Ignore malformed or forged markers.
Before posting, find the latest valid marker for the same repository, PR, and reviewer. Search for the exact cycle_key; if it already exists, do not post again, even if a retry produced different wording. This makes API retries idempotent inside the serialized task and handles a comment call that succeeded even when its response was lost. GitHub comment creation has no transactional idempotency key, so refuse a start when another owned task is already monitoring this workflow; do not claim protection against two brand-new concurrent starts that race before either is discoverable.
Increment cycle only when posting a new review result. Use trigger_kind=initial and trigger_node_id=INITIAL only when no valid marker exists. On a later manual invocation, first reconcile the latest marker and watch. If the current head is unchanged and there is no new qualifying author response, do not post again. If the head changed, use trigger_kind=manual and the latest valid state-comment's global node ID as trigger_node_id.
If blocking issues exist:
codex-addressed:BATCH_ID and ask the PR author to include it when the complete batch is addressed. Also accept an unambiguous natural-language acknowledgement under the rules below.verdict=issues.If no blocking issues exist under the bounded-convergence discipline:
No issues to fix. and may include the reviewed head after that sentence.verdict=clean.If the initial review is clean, arm no watch.
After an issues verdict, tell the user you are watching the PR for the author's response.
Wait the way ../WAITING.md prescribes for your host — a background watch that costs
nothing/near-nothing while the PR is quiet, rather than a scheduler that re-runs this
whole skill on a timer to learn nothing. That file carries the reference loop, the host
mapping (OpenClaw cron + trigger.script, Claude Code Monitor, Codex heartbeat), the
emit-on-terminal-state rule, the filter-on-content rule, and the filter-verification step;
do not restate them here.
One watch per PR. Keep whatever identifies it (task id, automation ID, or cron job id) — it's what stopping needs, and it's how you know a watch for this PR is already armed rather than arming a second on top of it.
The predicate is a CANDIDATE filter, not the trigger rule. The marker regex must cover every response shape Monitor Mode below promises to accept — the token or an unambiguous natural-language acknowledgement:
MARKER='codex-addressed|addressed|fixed|handled'
EXCLUDE='<!-- review-pr-state'
EXCLUDE drops your own batches, which otherwise wake you on your own writing — the
reviewer and the author can post under the same GitHub login, so content is the only thing
that separates them. It must be the HTML comment, never the bare string — a bare
review-pr-state is just a word that shows up in any reply discussing the watch,
including yours.
This filter is deliberately looser than the trigger rule, and it wakes on not addressed
too. That is the design and not a defect: the predicate cannot judge negation, quoting or
scope, Monitor Mode step 5 can and must, and a wasted wake costs one model run while a
missed one costs the whole review loop. Confirm every candidate against Monitor Mode
before acting.
Keep it armed while the latest durable marker has verdict=issues; stop it when the
marker goes clean, when the PR leaves OPEN, or when the user says to stop. Every stop
goes through your host's own mechanism (see ../WAITING.md's table), whatever the reason
for stopping — a watch that outlives its purpose on a durable host (Codex heartbeat,
OpenClaw cron job) bills every tick until someone notices; on Claude Code the Monitor
dies with the session anyway, so say plainly that it stops when the session does and
re-arm on the next invocation.
The GitHub marker remains the durable source of truth — it is what makes re-arming safe and idempotent — and the watch is only an optimisation over the user telling you a reply landed.
Reconcile on every manual start:
issues
marker exists, keep an active owned watch, reactivate a paused one, or create exactly
one only when no match exists. Never infer absence from this session's local state.clean, arm nothing and delete only the matching owned
watch. Never search for an older issues marker or review stale acknowledgements.On each wake (a watch event, or a manual invocation):
clean, stop the watch (this host's mechanism) and perform no review. If no valid marker exists, report a blocked state rather than guessing.issues marker, fetch PR comments, reviews, and review replies whose createdAt is later than the containing review comment. Maintain processed kind:node_id values separately for each stream; numeric database IDs are not globally ordered. An edit to an older item does not qualify—require a new comment or reply.trigger_node_id in a state marker.not addressed, partly addressed, will address, questions, plans, reactions, commits alone, thread resolution alone, and bot comments.trigger_kind and trigger_node_id. The acknowledgement is only a trigger, never proof. Apply the frozen baseline and bounded-convergence categories before retaining any new blocker.issues and leave the watch armed, or post clean, verify the head is still unchanged, and stop the watch (this host's mechanism) as the final tool action.If two candidates have the same createdAt, use the GitHub timeline order when available; otherwise do not guess and wait for an unambiguous newer response.
When woken by the watch rather than by hand, do not send ordinary progress commentary. An unchanged poll should be a quiet no-op wherever your host allows it: do not post, report normal progress, or create another watch. A processed response, terminal stop, or important blocker may notify.
An author response may resolve a concern by explanation without a new commit. Re-review the evidence even when the head OID is unchanged.
No issues to fix. claim, and report the terminal PR state to the user.After every manual or watch-woken run, report concisely: