geminiloop · v1.0 · 2026-08-24 · sha256 4c59a6053f812a13
geminiloop v1.0A
Immutable. This exact content never changes and is served at /api/v1/blob/4c59a6053f812a13.
---
name: geminiloop
description: >
Iteratively satisfy Gemini Code Assist's review on a GitHub PR, but treat every Gemini comment
SKEPTICALLY (Gemini Code Assist is materially more error-prone than Greptile): verify each finding
against the real code first, fix ONLY the genuinely-correct ones, and rebut + resolve false
positives WITHOUT changing correct code. Repeat until no unresolved Gemini comments remain. Use
when the user wants to clear a PR's Gemini Code Assist review.
compatibility: GitHub only (Gemini Code Assist is a GitHub app). Requires git + gh (GitHub CLI) authenticated, and the Gemini Code Assist app installed on the repo.
metadata:
version: "1.0"
allowed-tools: Bash(gh:*) Bash(git:*)
---
# Geminiloop
Drive a GitHub PR until Gemini Code Assist has no unresolved comments — **but do not cargo-cult
its suggestions.** Gemini is often confidently wrong. Every comment is a *claim to verify*, not an
instruction to obey. A wrong suggestion applied is worse than the comment itself.
## How Gemini differs from other review bots
- **No check-run, no score.** Gemini does not publish a `X/5` confidence or a `greptile` check. It
posts a **PR review** (state `COMMENTED`) authored by `gemini-code-assist[bot]` with a
`## Code Review` summary body plus inline review comments. Detection is by polling the *reviews*
endpoint, not a check-run. "Satisfied" = zero unresolved comments (each either fixed or rebutted),
since there is no numeric target.
- **Auto-reviews on push/open.** It reviews automatically when a PR opens or gets new commits;
`/gemini review` forces a fresh pass.
- **Severity, not confidence.** Inline comments carry a priority badge (a `![critical]` /
`![high]` / `![medium]` / `![low]` shields image) at the top of the body. Weight `critical`/`high`
seriously; treat `medium`/`low` as usually-skippable nits unless clearly correct.
- **Higher false-positive rate.** This is the whole point of the skill: bias toward *rebut* over
*change*.
## Not for
- GitLab / Perforce (Gemini Code Assist is GitHub-only). For other review bots this catalog ships
`codexloop`, `coderabbitloop`, and `qodoloop`; for CI failures rather than review comments, use
`ci-fix-loop`.
## 1. Identify the PR
```bash
gh pr view --json number,headRefName,headRefOid -q '{number,branch:.headRefName,head:.headRefOid}'
```
Switch to the PR branch if not already on it. Capture `OWNER`/`REPO` (`gh repo view --json owner,name`).
## 2. The loop (max 5 iterations)
Keep an explicit iteration counter and stop at 5 — the cap is a real bound to enforce, not a
figure of speech. Each pass through A–G is one iteration; on hitting the cap, go straight to the
report and list what is still unresolved rather than starting a sixth.
### A. Ensure a fresh Gemini review on the current head
Gemini auto-reviews new commits, but force a deterministic pass and record the head SHA:
```bash
HEAD_SHA=$(gh pr view <PR> --json headRefOid -q .headRefOid)
# Only trigger if no gemini review already exists for this exact SHA:
HAVE=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
--jq "[.[] | select(.user.login==\"gemini-code-assist[bot]\" and .commit_id==\"$HEAD_SHA\")] | length")
if [ "$HAVE" = "0" ]; then gh pr comment <PR> --body "/gemini review"; fi
```
Poll for the review of THIS head to land. No check-run exists, so poll the reviews endpoint — and
poll it on a **deadline**, never `while true`: a review that never arrives must end the skill with
an honest timeout, not hang it.
```bash
# 10-minute deadline, one retry, then give up.
wait_for_review() { # $1 = attempt label
local deadline=$(( SECONDS + 600 ))
while [ "$SECONDS" -lt "$deadline" ]; do
R=$(gh api repos/{owner}/{repo}/pulls/<PR>/reviews --paginate \
--jq "[.[] | select(.user.login==\"gemini-code-assist[bot]\" and .commit_id==\"$HEAD_SHA\")] | last")
if [ -n "$R" ] && [ "$R" != "null" ]; then return 0; fi
echo "waiting for Gemini review of $HEAD_SHA ($1)..."; sleep 15
done
return 1
}
if ! wait_for_review "first wait"; then
echo "no Gemini review after 10m — retrying once" # say the retry out loud
gh pr comment <PR> --body "/gemini review"
if ! wait_for_review "after retry"; then
echo "Gemini did not review $HEAD_SHA after a retry; stopping and reporting."
exit 1 # honest timeout, never a success claim
fi
fi
```
Report the retry in the final summary; two silent timeouts are the failure mode this guard exists
to prevent.
### B. Fetch the findings
- **Summary** (the `## Code Review` body): the review `.body` from the object above — read the
overall take and the severity spread.
- **Unresolved inline comments** on the current head:
```bash
gh api repos/{owner}/{repo}/pulls/<PR>/comments --paginate \
--jq '.[] | select(.user.login=="gemini-code-assist[bot]") | {id, path, line, body}'
```
Also pull the review threads + their resolved state via GraphQL (see step F) so you only act on
unresolved ones.
### C. Critically evaluate EACH comment (the core of this skill)
For every comment, **verify the claim against the actual code and repo conventions before touching
anything.** Read the file, the surrounding code, the types, and any call sites. Then classify:
1. **CORRECT + actionable** — the finding is real and the fix improves the code. → fix it (step D).
2. **FALSE POSITIVE / technically wrong** — the claim doesn't hold. → do **NOT** change code; write a
specific, evidence-based reply (cite the exact code/line/behavior that disproves it), then resolve.
3. **Valid but out-of-scope / stylistic nit** that conflicts with repo convention or the PR's intent
→ briefly decline with a reason, then resolve. Do not expand the PR's scope to satisfy a nit.
**Hard rules:**
- **Never modify correct code just to silence Gemini.** Prefer a reasoned rebuttal.
- When uncertain whether a claim holds, **investigate** (read more code, run the type-checker / tests)
rather than assume Gemini is right. Default to skepticism.
- If a suggested change would break other call sites, alter public behavior, or contradict a verified
repo convention, it is a category-2 rebuttal, not a fix.
- Never fabricate identifiers to satisfy a comment (e.g. a Linear/ticket prefix). If Gemini asks for a
ticket reference and none exists, say so; do not invent one.
**Gemini's common failure modes to watch for (default these to category 2):**
- Hallucinated APIs, options, or framework behavior stated as fact.
- "Add a null/undefined check" where the type already guarantees presence.
- Suggestions that compile-break or break other callers.
- Security/perf warnings with no actual exploit path or measurable cost.
- Restating library/framework semantics incorrectly.
- Style demands that contradict the repo's existing, consistent pattern.
### D. Apply fixes — category 1 only
Make the minimal correct change. Re-run the local gate if the repo has one (typecheck/tests) before
moving on.
### E. Commit and push FIRST, before resolving anything
Order matters. A resolved thread is a claim that the fix is on the branch, so the push has to
succeed before the claim is made — otherwise a failed commit or push leaves the PR unfixed with the
finding marked resolved, and nobody looks at it again.
If step D changed code:
```bash
# Stage ONLY the files your fixes touched — never `git add -A`, which sweeps up
# unrelated work and untracked secrets sitting in the worktree.
git status --short # look before you stage
git add <path> [<path>...] # the files named in the findings you fixed
git commit -m "address gemini review feedback (geminiloop iteration N)"
git push
```
Author the commit per the repo's norms (e.g. the user's identity; no AI attribution if that is the
convention). Confirm the push actually landed before continuing:
```bash
git rev-parse HEAD
gh pr view <PR> --json headRefOid -q .headRefOid # must match
```
If they differ, stop: the fix is not on the PR, so nothing may be resolved yet.
### F. Reply to and resolve every addressed thread
Only now, with the fixes pushed, reply and resolve. Fetch unresolved threads, **following
pagination** — a PR with more than 100 threads will otherwise look clean while unresolved findings
sit on page two:
```bash
# Loop until hasNextPage is false, passing endCursor back in as $cursor.
CURSOR=null
while : ; do
PAGE=$(gh api graphql -F cursor="$CURSOR" -f query='
query($cursor: String) {
repository(owner: "OWNER", name: "REPO") {
pullRequest(number: PR_NUMBER) {
reviewThreads(first: 100, after: $cursor) {
pageInfo { hasNextPage endCursor }
nodes { id isResolved comments(first: 1) { nodes { databaseId author { login } path body } } }
}
}
}
}')
echo "$PAGE" # collect nodes from every page before deciding the PR is clean
PI='.data.repository.pullRequest.reviewThreads.pageInfo'
[ "$(echo "$PAGE" | jq -r "$PI.hasNextPage")" = "true" ] || break
CURSOR=$(echo "$PAGE" | jq -r "$PI.endCursor")
done
```
Reply on a thread's comment via `gh api repos/{owner}/{repo}/pulls/<PR>/comments -f body="..." -F in_reply_to=<comment_id>`,
then resolve:
```bash
gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'
```
Resolve a thread only for comments authored by `gemini-code-assist[bot]` that you have fixed or
rebutted — never blanket-resolve, and never resolve a human reviewer's thread.
Threads you are **rebutting** need no push, so they may be replied to and resolved regardless of
whether step D changed code.
### G. Re-review
Pushing re-triggers Gemini automatically; go back to **A** with the new head SHA. If step D changed
nothing (all comments were rebutted), skip the push, ensure all threads are resolved, and exit.
## 3. Exit conditions
Stop when **any** is true:
- Zero unresolved `gemini-code-assist[bot]` comments remain, and every comment this round was fixed
or rebutted+resolved. (There is no score to hit — this is "done".)
- Max iterations (5) reached — report what remains.
## 4. Report
```text
Geminiloop complete.
PR: #<n>
Iterations: N
Comments fixed: N (genuinely-correct findings)
Comments rebutted: N (false positives / nits, resolved with rationale)
Remaining: 0
```
If it stopped at max iterations, list the remaining threads with your current assessment
(fix-pending vs disputed) so a human can arbitrate.