Install
$ agentstack add skill-agent-rig-rig-rig-review ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
rig-review — find and fix, in one skill
Local code review with two verbs:
find(default) — walk the project'sREVIEWER.mdcatalog and the
applicable per-scope invariants against a diff with a fresh-context reviewer agent (two passes), and return a triaged P0–P3 finding list. Read-only — it reports, it doesn't edit.
fix— take review feedback and loop acoderagent over it until the
review comes back clean (or a round budget is hit). Two feedback sources: a PR review bot on an open PR, or local find results.
The point is to pre-empt the PR review bot: every finding caught and fixed locally is one you don't pay PR round-trip latency on. Implement/epic-style flows call rig-review find then rig-review fix --source local so the loop lives in one place.
Configuration
Reads .rig/config.json:
review.patternsFile— the P0–P3 catalog the reviewer walks (default
.claude/REVIEWER.md). If absent, fall back to the kit's generic categories (correctness, security/trust-boundary, error-handling, concurrency, API/contract, tests, style) and say so.
review.bot— PR review bot to poll/re-trigger:codex,claude, ornone
(default none). none forces the local-only loop for fix.
review.botRetrigger— comment that re-triggers the bot (e.g. `@codex
review). Required when bot is not none`.
review.maxRounds— max fix↔recheck rounds before handing to a human
(default 5); --rounds N overrides.
vcs.baseRef— diff base when no `is given (defaultorigin/main`).project.repo—owner/namefor everygh apicall (bot source). Never
hardcode; derive from the git remote if unset.
agents.reviewer/agents.coder— the project's names for those roles
(default rig-).
Scope invariants (per-subsystem REVIEWER.md). Beyond the root catalog, a subsystem may carry its own REVIEWER.md colocated with its code — concrete correctness invariants it "learned the hard way," each ideally citing the PR where it was found. scripts/scope-reviewer.ts resolves which apply to a diff (ancestor-walk + any governs: globs a scope declares). find collects them and has the reviewer assert each as a P1. No-op if the project ships none.
Verbs & arguments
$ARGUMENTS begins with an optional verb, then args:
find [](default when no verb) — diff against `` or
vcs.baseRef. For a stacked/epic child, pass the integration branch.
fix [] [--source bot|local] [--rounds N] [--base ]- `
implies--source botunlessreview.botisnoneor--source
local` is set.
--sourcedefault:botif a PR is given andreview.bot != none, else
local.
--roundsdefaultreview.maxRounds;--base(local only) default
vcs.baseRef.
If invoked from another skill, the caller may thread {base}, {ticket-id}, {worktree-path} — use them.
find — the read-only gate
- Resolve the base and confirm there's a diff:
``bash git fetch origin git diff --stat {base}...HEAD ` If empty, report clean — no changes vs {base}` and stop.
Then collect the scope invariants for the changed files: ``bash bun scripts/scope-reviewer.ts {base} # or your TS runner; --files also works ` Capture as {scope-invariants}`. Informational, never fails; if it prints "No scope REVIEWER.md apply", drop the scope-invariant paragraph below.
- Spawn the
revieweragent (viaagents.reviewer) against the diff,
working in {worktree-path} if a caller passed one:
> "Review the diff git diff {base}...HEAD{ticket-suffix}. Read > {patternsFile} first and walk every pattern against the diff. (If it > doesn't exist, walk the generic categories: correctness, > security/trust-boundary, error-handling, concurrency, API/contract, tests, > style — and say so.) Worktree path: {worktree-path}. Be specific — file and > line refs. Tag each finding with its pattern number and severity > (P0/P1/P2/P3). If clean against every pattern, say so explicitly. > > This diff touches scopes with recorded invariants — assert the diff against > every one; a violation is a P1 tagged scope-invariant. > Invariants:\n{scope-invariants}"
({ticket-suffix} = for {ticket-id} when passed, else empty. Omit the scope-invariant paragraph when step 1 found none.)
- If pass 1 has any P0/P1, stop here and report (step 5) — no value hunting
for more before known blockers are fixed. The caller re-invokes find after fix, and the adversarial pass runs on that next iteration.
- Adversarial second pass (only when pass 1 is clean of P0/P1). Spawn a
second, independent reviewer call — fresh context, framed to default to skepticism:
> "A prior reviewer found this diff clean of blocking issues: git diff > {base}...HEAD{ticket-suffix}. Assume that verdict is wrong and find what it > missed. Read {patternsFile} and walk every pattern independently — don't > anchor on 'a reviewer already passed this.' Worktree path: {worktree-path}. > File/line refs, tagged with pattern number and severity. Also assert the > diff against the recorded scope invariants below independently; a violation > is a P1 tagged scope-invariant. Invariants:\n{scope-invariants} If you > also find it clean, say so; don't invent findings to justify a second > opinion."
(Omit the scope-invariant lines when step 1 found none.) Merge any P0/P1 the second pass surfaces into the list.
- Classify and report (this verb finds, it does not edit):
clean — 0 findings vs {base} (2 passes)findings — N P0/P1, M P2/P3— each with file:line, pattern number,
severity, and [pass 1]/[pass 2].
P0/P1 block (don't push). P2/P3 ship-with-a-note. To fix them, hand off to fix --source local.
fix — drive feedback to convergence
Source: local (findings from find)
- Get findings. Use the caller's
findoutput if passed; else run the
find verb (rig-review {base}) first.
- Classify: no P0/P1 → return
clean(surface P2/P3); any P0/P1 → fix round. - Fix round (while `round "Address these review findings on {ticket-id}. Worktree: {worktree-path}.
> Findings:\n{find_output}\n\nFor each, either apply the fix or explain in > one line why the finding is wrong. Don't silently skip."
- Re-run the
findverb (fresh context). If still P0/P1, incrementround.
- Return the outcome.
Outcomes (local):
clean — 0 P0/P1 vs {base}(P2/P3, if any, listed)unresolved — N P0/P1 after {N} rounds, leaving for your review
Source: bot (review bot on a PR)
Drives whatever bot review.bot names — mechanics are identical; only the author login and re-trigger phrase differ. Set REPO="$(project.repo)" and RETRIGGER="$(review.botRetrigger)" up front.
> Headless in CI. This same fix loop can run in GitHub Actions on each > posted review (out of any local session) via ci/workflows/auto-review-fix.yml > — one round per invocation, re-fired by the bot's re-review. Setup: > ci/README.md#review-bot-bundle + docs/auto-fix-app.md.
Identifying the bot. Match the author with a case-insensitive regex on the login, not an exact string — most bots post under more than one identity (a ...-connector for reviews, a ...[bot] for inline threads); exact match misses half the surface and stalls polling.
bot: codex→ regexchatgpt-codex-connector.bot: claude→ regexclaude.bot: bugbot→ regexcursor(Cursor Bugbot posts ascursor[bot]; re-trigger
comment is bugbot run).
Clean signal differs by bot. codex/claude announce a clean run with an APPROVED review or a +1 reaction. Bugbot does not — on a clean PR it posts no review and no reaction; it completes a GitHub check-run (Cursor Bugbot, app cursor) with conclusion: success. So for bot: bugbot the poll must read that check-run — keying on review/reaction alone makes every clean PR time out and the merge gates never go green.
Loop, round starting at 1:
- Wait for the bot. Poll ~5 min (15 × 20s). Watch review state AND inline
comments AND reactions in one snapshot: ``bash PR= PUSH_TIME=$(gh pr view $PR --repo "$REPO" --json commits -q '.commits[-1].committedDate') BOT='' REVIEW=$(gh pr view $PR --repo "$REPO" --json reviews -q " [.reviews[] | select((.author.login | test(\"$BOT\"; \"i\")) and .submittedAt > \"$PUSH_TIME\")] | last | .state // \"none\"") REACTION=$(gh api "repos/$REPO/issues/$PR/reactions" -q " [.[] | select((.user.login | test(\"$BOT\"; \"i\")) and .content == \"+1\" and .created_at > \"$PUSH_TIME\")] | length") INLINE=$(gh api "repos/$REPO/pulls/$PR/comments" -q " [.[] | select((.user.login | test(\"$BOT\"; \"i\")) and .created_at > \"$PUSH_TIME\")] | length") # bugbot only: its verdict is a check-run, not a review/reaction. Filter # server-side by name (so it can't fall off page 1 of an unfiltered list), # take the NEWEST run by started_at (a push auto-starts one and bugbot run # starts another on the same SHA — an older success must not win over a newer # in-progress run), and guard the no-run-yet case (// "none") so the jq # concat doesn't error on early polls before Bugbot has created its run. SHA=$(gh pr view $PR --repo "$REPO" --json headRefOid -q .headRefOid) CHECK=$(gh api "repos/$REPO/commits/$SHA/check-runs?check_name=Cursor%20Bugbot" -q " [.check_runs[] | select(.name | test(\"bugbot\"; \"i\"))] | sort_by(.started_at) | last | ((.status // \"none\") + \":\" + (.conclusion // \"\"))") [ -z "$CHECK" ] && CHECK="none:" # gh/network error → treat as not-yet-run ``
- Classify (codex/claude use the review/reaction signals; bugbot uses
CHECK):
bot: bugbot(classify offCHECK, the newest run for the head SHA):completed:success→ clean, exit.completed:with any other conclusion (neutral/action_required/failure):INLINE > 0→ actionable, go to 3.INLINE == 0→ race window (inline threads lag the check conclusion,
like the codex COMMENTED case): keep polling. If inlines never populate within budget, treat neutral as clean (body-only, no actionable threads) and failure/action_required as actionable to stay safe.
- anything not
completed:(none:/queued:/in_progress:) → keep polling. REACTION > 0orREVIEW == "APPROVED"→ clean, exit.REVIEW == "COMMENTED"ANDINLINE > 0→ actionable, go to 3.REVIEW == "COMMENTED"ANDINLINE == 0→ race window: review state can
flip before inline threads are API-visible. Keep polling. If inlines never populate within budget AND the review body is boilerplate-only, treat as clean (a header-only review is a soft +1).
- Timeout (5 min, nothing) → timeout, exit.
Never classify on review-state alone — COMMENTED with empty inlines is a transient race, not "no findings."
- Fix round (only if `round /replies" -f body=""
```
- Stage, commit, push (
fix({ticket-id}): address review). - Resolve the threads you addressed. If merge gates on unresolved blocking
threads, resolve each the coder actually fixed; for a blocker coder pushed back on, reply with rationale, resolve as explicit dismissal, and surface to the user — never leave an applicable blocker unresolved. Use the project's thread-resolution tooling if it ships one. A resolve without a push doesn't re-run a gate check — re-run the required check or let the next push re-trigger it.
- Re-trigger:
gh pr comment $PR --repo "$REPO" --body "$RETRIGGER". - Increment
round; updatePUSH_TIMEto the new commit; loop to 1.
- After N rounds (or
clean/timeout): the merge-queue gate is the
authority — converge to it. If the project ships a P1-gate script, run it with REVIEW_BOT_LOGIN set to the bot's login regex (the same one used above — e.g. REVIEW_BOT_LOGIN=cursor for bugbot) so it matches the right author; left unset it defaults to a placeholder that matches nothing, so the gate falsely passes and can wave through an unresolved blocker. (exit 0 → clean; non-zero → actionable with blocking titles + URLs.) Else use the final snapshot + tracked unresolved blockers.
Outcomes (bot) — stacked/epic flows read this to decide auto-merge:
clean — PR reviewed by , no unresolved blockersactionable — PR still has N unresolved blocker(s) after {N} rounds. Findings:timeout — PR open, did not respond within 5 min, leaving for your review
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: agent-rig
- Source: agent-rig/rig
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.