Finish PR
Bring the pull request attached to the current branch to a genuinely ready state.
Requires Git 2.38+, GitHub CLI (gh) authenticated for the repository, and PowerShell 7 (pwsh) for bundled helpers.
Definition of done
Finish only when all of these are true for the current PR HEAD:
- GitHub and a local merge probe show no merge conflicts.
- No CI check is failing. Pending checks may still be running, but never describe the PR as fully ready while a required check is pending.
- Every unresolved review thread is in one of these states:
- its latest unaddressed feedback has been actioned and the agent has replied with the result; or
- the latest relevant comment is the agent's response and no reviewer has replied afterwards, so the thread is awaiting review and needs no duplicate work.
- No reply created by this run remains in a pending GitHub review.
- No review thread's resolution state was changed by this run.
- The exact current HEAD has a successful completed
Gitar check with an Approved dashboard verdict — when Gitar is running for this repository (same detection rule as PR Agent below: a Gitar check or dashboard comment anywhere on the pull request). When Gitar is not running, this rule does not apply.
- If PR Agent is running for this repository, the exact current HEAD also carries a
PR Agent status with state success. See the PR Agent section below: pending means its review is still running, failure means its inline findings are action-required feedback, and the complete absence of any PR Agent status anywhere on the pull request means PR Agent is not running and this rule does not apply.
This completion rule uses Gitar Core only. Never require Gitar auto-approval, a GitHub approving review, merge blocking, auto-apply, or any other Pro signal. Treat Approved with Suggestions, Changes Requested, Blocked, and Needs Review as non-terminal feedback states even if the Gitar check itself succeeds.
An unresolved thread is not automatically unfinished. Reviewers own resolution state; the conversation order determines whether the agent currently owes action.
PR Agent
PR Agent is a self-hosted reviewer that may or may not be running. Detect it by its commit status: the context is exactly PR Agent (configurable via its CHECK_NAME), posted on every PR head it reviews.
- Detection: PR Agent is considered running for this PR when a
PR Agent status exists on the current HEAD or on any earlier commit of the pull request. If no PR Agent status exists anywhere on the PR, it is not running — never wait for it, never post anything to trigger it, and skip every PR Agent rule below.
- Status semantics:
pending = a review is running or about to run (PR Agent picks up new PRs and pushes within about a minute of detection and typically finishes in one to three minutes); failure = its inline findings are open and action-required; success = PR Agent has approved this exact HEAD. The status description also states how long the review took.
- Feedback identification: PR Agent posts inline review comments and replies through the repository owner's own login. Identify them by the hidden
<!-- pr-agent:v1 --> marker (and the "PR Agent" shields badge) in the body — never by author login. Its messages are reviewer feedback, not agent responses, even though the login matches yours. The bundled watcher already includes them in new feedback.
- Thread handling: apply exactly the same logic as every other reviewer — agree and fix (one focused commit, then reply on the thread with the commit SHA and verification), or push back with concrete evidence. Never resolve PR Agent threads: it owns their resolution and resolves a thread automatically once it verifies a fix against the pushed HEAD or accepts a justified decline.
- Memory of declined findings: when PR Agent accepts a push-back and resolves a thread, it remembers the declined finding and will not re-report it on later reviews of the same PR. If it pushes back again, only continue the debate when you have new evidence; otherwise leave the thread awaiting its response.
- Superseded reviews: PR Agent reviews the entire pull request on every push. If you push while a review is running, that review is cancelled and a fresh one starts on the new HEAD — do not wait for the cancelled run's verdict.
Operating rules
- Use the conversation history as first-class task context. The skill is often invoked after implementation, so recover the user's intent, earlier decisions, tradeoffs, verification, known limitations, and reasons for the current design before judging PR feedback.
- Read every applicable
AGENTS.md plus repository-native requirements and design documents implicated by the PR. Discover these from the repository and PR; never assume a particular task directory, branch naming scheme, language, build system, or hosting provider.
- Treat unresolved review threads as the authoritative inline-feedback list. Also inspect PR-level reviews and issue comments for standalone actionable feedback.
- Preserve unrelated worktree changes. Commit only changes made during this run.
- Resolve conflicts before failed checks, and failed checks before review feedback. Later evidence may require revisiting an earlier phase.
- Prefer the smallest correct change. Add focused tests for behavioural or regression-prone fixes.
- Use exactly one focused, unsquashed commit per action-required PR feedback unit whose disposition produces a change: one review thread or one standalone PR-level feedback item. Never combine multiple units into one commit, even when they are related. A justified disagreement requires a reply but no commit.
- Never rebase, force-push, merge the pull request on GitHub, close, approve, or mark the PR ready for review unless the user explicitly requested that separate action. The conflict-resolution workflow may merge the latest base commit into the PR branch.
- Never resolve or unresolve a review thread. Do not call
resolveReviewThread, unresolveReviewThread, or an equivalent.
- Reply directly to review threads, one at a time. Never create replies concurrently.
- Continue autonomously through new feedback from Gitar, PR Agent, and every other source after pushes, within the convergence bounds below.
- Never ask Gitar to apply or commit a fix. Do not use
gitar fix, one-click apply, or gitar auto-apply:on. This agent owns every code change.
- Never post trigger comments or fallbacks for PR Agent. It discovers PRs and pushes automatically when running; its only terminal signals are its commit status and its inline threads.
1. Establish state and intent
Locate the repository root and read applicable instructions.
Inspect:
git status --short
git rev-parse --abbrev-ref HEAD
git rev-parse HEAD
gh --version
gh auth status
gh pr view --json number,title,url,body,author,headRefName,headRefOid,headRepository,headRepositoryOwner,isCrossRepository,baseRefName,baseRefOid,mergeable,mergeStateStatus,reviews,comments
Record the starting SHA and every existing changed path, separating staged, unstaged, and untracked changes. Never include pre-existing changes in this run's commits.
A feedback or CI fix must not touch a path that had any pre-existing staged, unstaged, or untracked change. Stop and ask the user before editing that path; partial staging plus git commit --only does not preserve same-file hunk isolation.
If the current branch has no PR, inspect gh pr status. Switch or check out a PR only when the mapping is unambiguous and local changes are safe; otherwise ask the user.
Reconstruct the intended change from, in priority order:
- explicit user instructions and this conversation;
- applicable repository instructions;
- PR title, body, commits, and diff;
- linked issue/spec/design documents;
- surrounding code, tests, and conventions.
Inspect the complete PR diff before evaluating conflicts, CI, or feedback.
Identify the Gitar integration from exact case-insensitive Gitar check runs whose GitHub App slug is Gitar-marked, plus the Gitar-authored dashboard Code Review comment. Treat the exact-HEAD check as the processing/completion boundary and the dashboard's Code Review verdict as the review result. Never infer completion from reactions or require a GitHub approval review.
Resolve the authenticated GitHub viewer login. Treat comments from that login, or another agent login established unambiguously by the conversation/PR history, as agent responses.
Resolve the base and head repositories independently from PR metadata:
- derive the base repository from the PR URL;
- use
headRepository.nameWithOwner for the head repository;
- prefer existing configured remotes that match those exact repositories;
- otherwise use GitHub-provided clone URLs and configure Git to use the authenticated
gh credential helper;
- retain the exact
headRefName.
$pr = gh pr view --json number,url,headRefName,headRefOid,headRepository,headRepositoryOwner |
ConvertFrom-Json
$prNumber = [int]$pr.number
$prUri = [uri]$pr.url
$pathSegments = $prUri.AbsolutePath.Trim("/").Split("/")
$githubHostname = $prUri.Authority
$baseRepositoryName = "$($pathSegments[0])/$($pathSegments[1])"
$baseRepository = "$githubHostname/$baseRepositoryName"
$baseMetadata = gh api --hostname $githubHostname "repos/$baseRepositoryName" |
ConvertFrom-Json
$headMetadata = gh api --hostname $githubHostname "repos/$($pr.headRepository.nameWithOwner)" |
ConvertFrom-Json
gh auth setup-git --hostname $githubHostname
$baseFetchUrl = [string]$baseMetadata.clone_url
$headPushUrl = [string]$headMetadata.clone_url
GitHub's clone_url preserves the server authority, including non-default ports, while gh auth setup-git makes HTTPS Git operations use the authenticated CLI identity. A verified matching SSH/configured remote may be used instead. Stop if authentication, repository identity, or the head repository is unavailable or ambiguous. Never assume origin points to either side of a fork-based PR.
Align the checkout with the exact PR head before making any changes:
git fetch $headPushUrl $pr.headRefName
$remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()
$lastObservedPrHeadSha = $remoteHeadSha
$localHeadSha = (git rev-parse HEAD).Trim()
git merge-base --is-ancestor $remoteHeadSha $localHeadSha
$localContainsRemoteHead = $LASTEXITCODE -eq 0
if ($localContainsRemoteHead -and $localHeadSha -ne $remoteHeadSha) {
$initialLocalAheadCommits = git log --oneline "$remoteHeadSha..$localHeadSha"
# Validate and record every commit against the recovered user intent and full PR diff.
# Stop for confirmation if any commit is unrelated, unfinished, or ambiguous.
}
if (-not $localContainsRemoteHead) {
git merge-base --is-ancestor $localHeadSha $remoteHeadSha
$canFastForward = $LASTEXITCODE -eq 0 -and -not (git status --porcelain)
if (-not $canFastForward) {
throw "Local HEAD is stale or diverged from the PR head; stop before mutation."
}
git merge --ff-only $remoteHeadSha
}
Continue only when local HEAD matches the fetched PR head, is safely fast-forwarded to it, or every initially local-ahead commit was explicitly validated as intended PR work from conversation and repository evidence. Record those commits as pre-existing push scope; stop for confirmation on any uncertainty. Never silently publish local-ahead commits.
11. Create one unique state directory outside the repository and retain it for the full run:
$runStateDirectory = Join-Path ([IO.Path]::GetTempPath()) (
"finish-pr-{0}-{1}" -f $prNumber, [guid]::NewGuid().ToString("N")
)
New-Item -ItemType Directory -Path $runStateDirectory | Out-Null
Store every baseline, snapshot, and watcher-state file for this run inside this directory so concurrent runs cannot overwrite one another.
2. Resolve merge conflicts
Run this before CI or feedback:
Refresh PR/base metadata and perform a non-mutating local probe:
$pr = gh pr view $prNumber --repo $baseRepository --json number,url,baseRefName,baseRefOid,headRefName,headRefOid,headRepository,headRepositoryOwner,mergeable,mergeStateStatus |
ConvertFrom-Json
git fetch $baseFetchUrl $pr.baseRefName
$baseCommit = (git rev-parse FETCH_HEAD).Trim()
git merge-tree --write-tree --messages HEAD $baseCommit
Investigate locally when GitHub reports CONFLICTING, DIRTY, or UNKNOWN, or when the probe reports conflicts.
If conflicts exist, check the initial worktree baseline before merging. A normal merge requires a clean index: if any pre-existing staged change remains, stop before mutation and tell the user to commit or stash it, or request explicit permission to isolate and restore the index. Do not use --autostash on user work without that permission.
If the index is clean and unrelated local changes are safe, merge the latest base into the PR branch:
git merge --no-ff $baseCommit
Resolve each conflict using the recovered task intent, repository requirements, adjacent code, and tests. Do not mechanically prefer either side.
Run focused verification, stage only the resolution, and commit it. Record the conflict summary, commit SHA, and checks run.
If the merge is clean, keep any Git-created merge commit but do not create an extra empty commit.
3. Fix failed CI
Inspect all checks:
gh pr checks $prNumber --repo $baseRepository --json bucket,completedAt,description,event,link,name,startedAt,state,workflow
gh pr checks $prNumber --repo $baseRepository --required --json bucket,completedAt,description,event,link,name,startedAt,state,workflow
Use the second query to distinguish required checks from optional checks. Treat “no required checks reported” as an empty required set, not a failure.
For each failure, retrieve the actual logs before editing:
gh run list --repo $baseRepository --branch $pr.headRefName --commit $pr.headRefOid --json databaseId,name,workflowName,status,conclusion,url,headSha,event,createdAt -L 50
gh run view <run-id> --repo $baseRepository --json name,status,conclusion,jobs,url
gh run view <run-id> --repo $baseRepository --log-failed
For non-Actions checks, inspect the provider link or available check details.
Fix the root cause, not merely the symptom. Work from the clearest upstream failure outward because one failure may cascade into others.
Run the closest local equivalent, inspect the initial worktree baseline, and stage only that fix. Commit with an exact pathspec so pre-existing staged changes remain outside the CI commit:
git commit --only -m "fix(ci): address <failed check>" -- <exact-ci-fix-paths>
If a CI fix path had pre-existing staged, unstaged, or untracked changes, stop before editing it. Record the check, cause, SHA, and verification.
If a failure is external, flaky, permission-related, or not repository-fixable, capture evidence. Retry only when safe and supported; do not change code to appease an unrelated failure.
4. Fetch and classify feedback
Resolve the loaded skill's directory, then use its bundled helpers by absolute path; do not assume the skill lives inside the target repository.
Capture every thread's read-only resolution baseline outside the repository:
$threadBaseline = Join-Path $runStateDirectory "thread-resolution.json"
$threadSnapshot = Join-Path $runStateDirectory "unresolved-threads.json"
pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname -All |
Set-Content -Encoding utf8 $threadBaseline
pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname |
Set-Content -Encoding utf8 $threadSnapshot
For each unresolved thread, read all paginated comments in chronological order and classify it. First identify comment authorship: PR Agent posts through the repository owner's own login, so classify every comment carrying the hidden <!-- pr-agent:v1 --> marker (or the "PR Agent" badge) as a PR Agent reviewer message — never as an agent response. Then classify the thread:
- Awaiting reviewer: the latest relevant comment is an agent response in a submitted review (
pullRequestReview.state != PENDING with non-null submittedAt) and nobody has replied later. Do nothing. Do not post a reminder, repeat the fix, or duplicate the response. PR Agent messages count as reviewer messages for this rule: when PR Agent replies (verification result, push-back, or resolution note), the thread is awaiting your action or is already resolved by it.
- Action required: there is reviewer feedback after the agent's latest submitted response, the agent has never responded, or its latest response exists only in a pending review. PR Agent inline findings are always action-required when the thread is unresolved: agree and fix with a focused commit, or push back with evidence and let PR Agent re-evaluate.
- Superseded/non-actionable: the later conversation explicitly withdraws, answers, or supersedes the point. Reply only if the thread still needs an agent acknowledgement; avoid duplicating an existing agent response. A PR Agent resolution note ("verified ... resolving this thread") on a thread it has just resolved needs no reply.
Within action-required threads, identify each distinct feedback item. Judge it against the user's intent, conversation history, repository rules, linked requirements, PR scope, current code, conventions, and tests. The thread is the commit boundary: group all work required by one thread into that thread's single commit, but never include another thread's work.
Classify actionable PR-level review bodies and issue comments with the same rules. Each standalone feedback item is its own commit boundary; never combine it with a review thread or another standalone item. Track it by feedback ID and permalink because it has no review-thread ID.
- Agree when it identifies a real bug, missed requirement, broken invariant, missing test, misleading behaviour, or scoped maintainability problem.
- Disagree when it conflicts with requirements, established intent, repository invariants, or would produce a worse/out-of-scope design.
- When uncertain, make a small scoped correctness fix if evidence supports it. Otherwise explain the uncertainty and why no change was made.
Do not skip outdated unresolved threads; determine whether their feedback still applies to current code.
5. Fix and reply
For each action-required review thread or standalone feedback item:
Make the smallest complete fix for every actionable item in that thread, with focused tests.
Run the narrowest meaningful verification.
Inspect and stage only files for that item:
git status --short
git diff
git add <paths>
git diff --cached
Keep unrelated staged changes in other paths staged. Stop before editing any fix path that had a pre-existing staged, unstaged, or untracked change; never rely on partial staging followed by git commit --only for same-file isolation.
If the disposition produces a change, create exactly one commit for the feedback unit before moving to the next unit:
git commit --only -m "fix(pr): address <thread summary>" -- <exact-thread-fix-paths>
Do not amend, squash, or combine feedback commits. If an earlier unit's change completely satisfies a later agreed unit and no distinct file change remains, create an explicit traceability commit with --allow-empty for that later unit rather than merging their commit history. Do not create a commit for a justified disagreement.
For review-thread feedback, reply directly to the thread after evaluating it and creating any relevant commit, subject to the Gitar deferral below:
$body = @"
Agreed. I fixed this in commit <sha> by <specific change>.
Verification: <command and result>.
"@
pwsh <skill-directory>/scripts/reply-to-review-thread.ps1 -ThreadId "<thread-id>" -Hostname $githubHostname -Body $body
For standalone feedback, post a PR-level reply that links the exact feedback permalink:
$body = @"
Regarding [this feedback](<feedback-permalink>): agreed. I fixed this in commit <sha> by <specific change>.
Verification: <command and result>.
"@
gh pr comment $prNumber --repo $baseRepository --body $body
Use the same PR-level path for a standalone justified disagreement, retaining the feedback permalink and the disagreement wording below.
For a justified disagreement:
I don't think this change is correct for this PR.
Reason: <specific reason grounded in requirements, conversation, or code>.
No code change made.
If any Gitar-authored feedback disposition created a commit that has not been pushed yet, defer its thread or PR-level reply until immediately after the batch push. Gitar cannot verify a local-only SHA; replying before it can see the commit may cause a misleading follow-up. Prefix a PR-level Gitar reply with Gitar, so the dashboard feedback is processed; never ask it to apply the fix. A Gitar disagreement has no commit dependency and may be replied to immediately. Keep all replies serial.
Record the one-to-one feedback-unit ID → commit SHA mapping for changed dispositions, plus every disposition, verification, and returned comment ID. Use the thread ID for review threads and the feedback ID for standalone items. Record no commit — disagreement for justified disagreements.
The reply helper uses GitHub's single-comment reply endpoint so it never submits or modifies a shared pending review. It then verifies state != PENDING plus a non-null submittedAt. A helper failure is blocking; a returned comment URL alone is not proof of submission.
After all replies:
- Re-fetch all threads with
-All, plus PR-level reviews and issue comments.
- Verify every reply created in this run belongs to a submitted review.
- Verify the authenticated user has no pending review on the PR, including reviews created before this run.
- For every thread ID present in the baseline, compare its
isResolved value with the current value. Baseline resolution states must be unchanged; report external changes and never mutate them back. New thread IDs are expected during review convergence: classify them as additional feedback rather than treating their existence as a resolution mutation.
- If new action-required review threads or standalone feedback items appeared during the batch, action each in its own commit and repeat the audit. Push only once the currently visible feedback set has been fully actioned or is awaiting reviewer response. Gitar threads with a deferred local-commit reply count as actioned for this pre-push audit, but the reply remains mandatory immediately after push.
6. Push and converge with Gitar
Confirm the worktree contains no uncommitted changes created by this run. Do not push individual thread commits as they are created; batch-push all unsquashed thread commits only after the feedback audit is clear for the time being.
Review commits after the starting SHA and every validated commit that was already local-ahead at invocation, then fetch the exact PR head before pushing:
git log --oneline <starting-sha>..HEAD
git fetch $headPushUrl $pr.headRefName
$remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()
$localHeadSha = (git rev-parse HEAD).Trim()
$currentPrHeadSha = (gh pr view $prNumber --repo $baseRepository --json headRefOid --jq .headRefOid).Trim()
$pushRequired = $localHeadSha -ne $remoteHeadSha
git status --short --branch
Stop if $remoteHeadSha and $currentPrHeadSha differ, or if either differs from $lastObservedPrHeadSha. Never overwrite $lastObservedPrHeadSha with an unexpected remote value. Use $pushRequired, not the starting-SHA commit range, to decide whether the PR head needs a push; the range is reporting context only.
If $pushRequired, increment $reviewRound and capture a review baseline immediately before pushing:
$reviewRound++
$reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
-CaptureBaseline `
-StatePath $reviewState `
-PrNumber $prNumber `
-Repository $baseRepository `
-Hostname $githubHostname `
-PrAgentContext "PR Agent"
Push without force and record the exact HEAD:
$reviewRequestedAt = [DateTimeOffset]::UtcNow
git push $headPushUrl "HEAD:refs/heads/$($pr.headRefName)"
$expectedHeadSha = git rev-parse HEAD
$lastObservedPrHeadSha = $expectedHeadSha
Immediately after the push, post each deferred Gitar thread or PR-level reply serially with its now-visible commit SHA and verification result. Verify thread replies are submitted, then refresh feedback once before waiting for Gitar. Post deferred PR Agent thread replies the same way — PR Agent can only verify fixes against pushed commits.
After pushing, allow approximately 60 seconds for the exact-HEAD Gitar check to appear, and for the PR Agent status to flip to pending when PR Agent is running (it picks up pushes automatically; its review typically completes within one to three minutes):
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
-Wait `
-StatePath $reviewState `
-ExpectedHeadSha $expectedHeadSha `
-ReviewRequestedAt $reviewRequestedAt `
-ReviewStartGraceSeconds 60 `
-TimeoutMinutes 25 `
-PollSeconds 10
If this returns review_not_started, and only then, request review once for that pushed HEAD:
gh pr comment $prNumber --repo $baseRepository --body "gitar review"
Do not post the fallback comment when an exact-HEAD Gitar check appeared during the grace period, even if it is still queued or processing.
If the grace-period watcher returned review_not_started, resume the bundled watcher against the same baseline:
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
-Wait `
-StatePath $reviewState `
-ExpectedHeadSha $expectedHeadSha `
-ReviewRequestedAt $reviewRequestedAt `
-TimeoutMinutes 25 `
-PollSeconds 20
Run it as a long-lived tool call. While it runs, use only the environment's wait mechanism and remain silent unless the user interrupts. The watcher keeps repeated polling out of model context.
Handle its terminal result. The watcher converges on both reviewers: when PR Agent is running (prAgentRelevant true in the result), a PR Agent status on the exact HEAD is part of every terminal state, and PR Agent's inline findings are delivered through newFeedback like every other reviewer's:
feedback: fetch all feedback for context, but action only IDs in newFeedback. This may include inline threads (from PR Agent, Gitar, or any other reviewer), PR-level feedback from any reviewer, Gitar's dashboard when its verdict is Approved with Suggestions, Changes Requested, Blocked, or Needs Review, and a synthetic pragent_status item when PR Agent reported failure without captured comments. If a new comment extends an old unresolved thread, read the full thread and handle only feedback after the last agent response. PR Agent findings follow the same agree-and-fix / push-back rules, and it will re-verify pushed fixes and resolve its threads automatically.
approved: the exact-HEAD Gitar check completed successfully with a fresh Approved dashboard verdict (when Gitar is running) AND the exact-HEAD PR Agent status is success (when PR Agent is running). Re-fetch checks, dashboards, PR-level feedback, and threads once; finish only if the full definition of done still holds.
gitar_failed: inspect the Gitar check and dashboard details. Treat provider/integration failure as a blocker unless repository evidence gives a scoped fix; never describe the PR as reviewed successfully.
review_not_started: post the single fallback gitar review comment, then resume step 6. This outcome is never returned while PR Agent is still processing a review.
timeout: report that a reviewer did not reach a terminal state; do not claim readiness.
head_changed: fetch and inspect the new state. Stop when another actor's push makes continued mutation unsafe.
pr_closed: stop and report the PR state.
For new feedback, repeat fix → verify → commit → serial reply → audit → baseline → push → automatic-review grace period → wait.
If no push is needed, never post gitar review: the fallback is only permitted after this run pushes a new HEAD. Capture the current state and wait read-only. A completed successful Gitar check on the exact current HEAD plus an Approved dashboard verdict — and a success PR Agent status on the same HEAD when PR Agent is running — is sufficient; no Pro approval signal is required. Otherwise wait for an already-running automatic review and stop on timeout without posting a trigger.
$expectedHeadSha = (git rev-parse HEAD).Trim()
$reviewRound++
$reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
-CaptureBaseline `
-StatePath $reviewState `
-PrNumber $prNumber `
-Repository $baseRepository `
-Hostname $githubHostname
pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `
-Wait `
-StatePath $reviewState `
-ExpectedHeadSha $expectedHeadSha `
-ReviewRequestedAt ([DateTimeOffset]::MinValue) `
-TimeoutMinutes 25 `
-PollSeconds 20
The watcher verifies that Gitar's check belongs to the exact expected SHA. After a push, it also requires the dashboard comment to have changed after the baseline and in the same processing window before accepting its verdict, because Gitar edits one persistent dashboard comment in place. Never use the fallback comment without a preceding push from this run. When PR Agent is running, the watcher additionally waits for the exact-HEAD PR Agent status to reach success or failure before reporting approved or feedback, and never reports review_not_started while PR Agent is processing.
Bound convergence to five pushed review rounds or two hours overall. Stop earlier for a clean combined result, timeout, closure, unexpected head movement, or a genuine blocker.
Final audit and response
Re-fetch rather than relying on cached state:
- PR head, mergeability, and base;
- latest base commit and a fresh local
git merge-tree --write-tree --messages HEAD <base-commit> conflict probe;
- all checks;
- required checks queried separately with
gh pr checks --required;
- the exact-HEAD Gitar check and Gitar dashboard Code Review verdict;
- the exact-HEAD
PR Agent status state (when PR Agent is running for this repository);
- PR-level reviews/comments;
- all review threads and reply submission states;
- local/remote branch state and worktree.
Report concisely:
- PR number and URL;
- conflict and CI outcome, with commits;
- thread counts: actioned, awaiting reviewer, and disagreed;
- fixes, focused verification, and commit SHAs;
- push result and Gitar review rounds;
- terminal Gitar Core status for current HEAD: successful completed check plus
Approved dashboard verdict;
- terminal
PR Agent status for current HEAD: success (or not running when no PR Agent status exists on the pull request);
- pending review replies:
0;
- review-thread resolution mutations:
0, with baseline audit result;
- any blocker or required check still pending.
1---2name: finish-pr3description: Finish the GitHub pull request attached to the current branch; resolve merge conflicts, diagnose and fix failed CI checks, action review feedback from every source without duplicating replies that are awaiting a reviewer response, push focused commits, and continue through Gitar review until its current-HEAD Core signals show a completed clean review. Use whenever the user asks to finish, complete, ready, resolve, fix, or address feedback/CI/conflicts on the current PR.4---56# Finish PR78Bring the pull request attached to the current branch to a genuinely ready state.910Requires Git 2.38+, GitHub CLI (`gh`) authenticated for the repository, and PowerShell 7 (`pwsh`) for bundled helpers.1112## Definition of done1314Finish only when all of these are true for the current PR HEAD:1516- GitHub and a local merge probe show no merge conflicts.17- No CI check is failing. Pending checks may still be running, but never describe the PR as fully ready while a required check is pending.18- Every unresolved review thread is in one of these states:19 - its latest unaddressed feedback has been actioned and the agent has replied with the result; or20 - the latest relevant comment is the agent's response and no reviewer has replied afterwards, so the thread is awaiting review and needs no duplicate work.21- No reply created by this run remains in a pending GitHub review.22- No review thread's resolution state was changed by this run.23- The exact current HEAD has a successful completed `Gitar` check with an `Approved` dashboard verdict — when Gitar is running for this repository (same detection rule as PR Agent below: a `Gitar` check or dashboard comment anywhere on the pull request). When Gitar is not running, this rule does not apply.24- If PR Agent is running for this repository, the exact current HEAD also carries a `PR Agent` status with state `success`. See the PR Agent section below: `pending` means its review is still running, `failure` means its inline findings are action-required feedback, and the complete absence of any `PR Agent` status anywhere on the pull request means PR Agent is not running and this rule does not apply.2526This completion rule uses Gitar Core only. Never require Gitar auto-approval, a GitHub approving review, merge blocking, auto-apply, or any other Pro signal. Treat `Approved with Suggestions`, `Changes Requested`, `Blocked`, and `Needs Review` as non-terminal feedback states even if the `Gitar` check itself succeeds.2728An unresolved thread is not automatically unfinished. Reviewers own resolution state; the conversation order determines whether the agent currently owes action.2930## PR Agent3132PR Agent is a self-hosted reviewer that may or may not be running. Detect it by its commit status: the context is exactly `PR Agent` (configurable via its `CHECK_NAME`), posted on every PR head it reviews.3334- **Detection**: PR Agent is considered running for this PR when a `PR Agent` status exists on the current HEAD or on any earlier commit of the pull request. If no `PR Agent` status exists anywhere on the PR, it is not running — never wait for it, never post anything to trigger it, and skip every PR Agent rule below.35- **Status semantics**: `pending` = a review is running or about to run (PR Agent picks up new PRs and pushes within about a minute of detection and typically finishes in one to three minutes); `failure` = its inline findings are open and action-required; `success` = PR Agent has approved this exact HEAD. The status description also states how long the review took.36- **Feedback identification**: PR Agent posts inline review comments and replies through the repository owner's own login. Identify them by the hidden `<!-- pr-agent:v1 -->` marker (and the "PR Agent" shields badge) in the body — never by author login. Its messages are reviewer feedback, not agent responses, even though the login matches yours. The bundled watcher already includes them in new feedback.37- **Thread handling**: apply exactly the same logic as every other reviewer — agree and fix (one focused commit, then reply on the thread with the commit SHA and verification), or push back with concrete evidence. Never resolve PR Agent threads: it owns their resolution and resolves a thread automatically once it verifies a fix against the pushed HEAD or accepts a justified decline.38- **Memory of declined findings**: when PR Agent accepts a push-back and resolves a thread, it remembers the declined finding and will not re-report it on later reviews of the same PR. If it pushes back again, only continue the debate when you have new evidence; otherwise leave the thread awaiting its response.39- **Superseded reviews**: PR Agent reviews the entire pull request on every push. If you push while a review is running, that review is cancelled and a fresh one starts on the new HEAD — do not wait for the cancelled run's verdict.4041## Operating rules4243- Use the conversation history as first-class task context. The skill is often invoked after implementation, so recover the user's intent, earlier decisions, tradeoffs, verification, known limitations, and reasons for the current design before judging PR feedback.44- Read every applicable `AGENTS.md` plus repository-native requirements and design documents implicated by the PR. Discover these from the repository and PR; never assume a particular task directory, branch naming scheme, language, build system, or hosting provider.45- Treat unresolved review threads as the authoritative inline-feedback list. Also inspect PR-level reviews and issue comments for standalone actionable feedback.46- Preserve unrelated worktree changes. Commit only changes made during this run.47- Resolve conflicts before failed checks, and failed checks before review feedback. Later evidence may require revisiting an earlier phase.48- Prefer the smallest correct change. Add focused tests for behavioural or regression-prone fixes.49- Use exactly one focused, unsquashed commit per action-required PR feedback unit whose disposition produces a change: one review thread or one standalone PR-level feedback item. Never combine multiple units into one commit, even when they are related. A justified disagreement requires a reply but no commit.50- Never rebase, force-push, merge the pull request on GitHub, close, approve, or mark the PR ready for review unless the user explicitly requested that separate action. The conflict-resolution workflow may merge the latest base commit into the PR branch.51- Never resolve or unresolve a review thread. Do not call `resolveReviewThread`, `unresolveReviewThread`, or an equivalent.52- Reply directly to review threads, one at a time. Never create replies concurrently.53- Continue autonomously through new feedback from Gitar, PR Agent, and every other source after pushes, within the convergence bounds below.54- Never ask Gitar to apply or commit a fix. Do not use `gitar fix`, one-click apply, or `gitar auto-apply:on`. This agent owns every code change.55- Never post trigger comments or fallbacks for PR Agent. It discovers PRs and pushes automatically when running; its only terminal signals are its commit status and its inline threads.5657## 1. Establish state and intent58591. Locate the repository root and read applicable instructions.602. Inspect:6162 ```powershell63 git status --short64 git rev-parse --abbrev-ref HEAD65 git rev-parse HEAD66 gh --version67 gh auth status68 gh pr view --json number,title,url,body,author,headRefName,headRefOid,headRepository,headRepositoryOwner,isCrossRepository,baseRefName,baseRefOid,mergeable,mergeStateStatus,reviews,comments69 ```70713. Record the starting SHA and every existing changed path, separating staged, unstaged, and untracked changes. Never include pre-existing changes in this run's commits.72 A feedback or CI fix must not touch a path that had any pre-existing staged, unstaged, or untracked change. Stop and ask the user before editing that path; partial staging plus `git commit --only` does not preserve same-file hunk isolation.734. If the current branch has no PR, inspect `gh pr status`. Switch or check out a PR only when the mapping is unambiguous and local changes are safe; otherwise ask the user.745. Reconstruct the intended change from, in priority order:75 - explicit user instructions and this conversation;76 - applicable repository instructions;77 - PR title, body, commits, and diff;78 - linked issue/spec/design documents;79 - surrounding code, tests, and conventions.806. Inspect the complete PR diff before evaluating conflicts, CI, or feedback.817. Identify the Gitar integration from exact case-insensitive `Gitar` check runs whose GitHub App slug is Gitar-marked, plus the Gitar-authored dashboard Code Review comment. Treat the exact-HEAD check as the processing/completion boundary and the dashboard's Code Review verdict as the review result. Never infer completion from reactions or require a GitHub approval review.828. Resolve the authenticated GitHub viewer login. Treat comments from that login, or another agent login established unambiguously by the conversation/PR history, as agent responses.839. Resolve the base and head repositories independently from PR metadata:84 - derive the base repository from the PR URL;85 - use `headRepository.nameWithOwner` for the head repository;86 - prefer existing configured remotes that match those exact repositories;87 - otherwise use GitHub-provided clone URLs and configure Git to use the authenticated `gh` credential helper;88 - retain the exact `headRefName`.8990 ```powershell91 $pr = gh pr view --json number,url,headRefName,headRefOid,headRepository,headRepositoryOwner |92 ConvertFrom-Json93 $prNumber = [int]$pr.number94 $prUri = [uri]$pr.url95 $pathSegments = $prUri.AbsolutePath.Trim("/").Split("/")96 $githubHostname = $prUri.Authority97 $baseRepositoryName = "$($pathSegments[0])/$($pathSegments[1])"98 $baseRepository = "$githubHostname/$baseRepositoryName"99 $baseMetadata = gh api --hostname $githubHostname "repos/$baseRepositoryName" |100 ConvertFrom-Json101 $headMetadata = gh api --hostname $githubHostname "repos/$($pr.headRepository.nameWithOwner)" |102 ConvertFrom-Json103 gh auth setup-git --hostname $githubHostname104 $baseFetchUrl = [string]$baseMetadata.clone_url105 $headPushUrl = [string]$headMetadata.clone_url106 ```107108 GitHub's `clone_url` preserves the server authority, including non-default ports, while `gh auth setup-git` makes HTTPS Git operations use the authenticated CLI identity. A verified matching SSH/configured remote may be used instead. Stop if authentication, repository identity, or the head repository is unavailable or ambiguous. Never assume `origin` points to either side of a fork-based PR.10910. Align the checkout with the exact PR head before making any changes:110111 ```powershell112 git fetch $headPushUrl $pr.headRefName113 $remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()114 $lastObservedPrHeadSha = $remoteHeadSha115 $localHeadSha = (git rev-parse HEAD).Trim()116 git merge-base --is-ancestor $remoteHeadSha $localHeadSha117 $localContainsRemoteHead = $LASTEXITCODE -eq 0118119 if ($localContainsRemoteHead -and $localHeadSha -ne $remoteHeadSha) {120 $initialLocalAheadCommits = git log --oneline "$remoteHeadSha..$localHeadSha"121 # Validate and record every commit against the recovered user intent and full PR diff.122 # Stop for confirmation if any commit is unrelated, unfinished, or ambiguous.123 }124125 if (-not $localContainsRemoteHead) {126 git merge-base --is-ancestor $localHeadSha $remoteHeadSha127 $canFastForward = $LASTEXITCODE -eq 0 -and -not (git status --porcelain)128 if (-not $canFastForward) {129 throw "Local HEAD is stale or diverged from the PR head; stop before mutation."130 }131132 git merge --ff-only $remoteHeadSha133 }134 ```135136 Continue only when local `HEAD` matches the fetched PR head, is safely fast-forwarded to it, or every initially local-ahead commit was explicitly validated as intended PR work from conversation and repository evidence. Record those commits as pre-existing push scope; stop for confirmation on any uncertainty. Never silently publish local-ahead commits.13711. Create one unique state directory outside the repository and retain it for the full run:138139 ```powershell140 $runStateDirectory = Join-Path ([IO.Path]::GetTempPath()) (141 "finish-pr-{0}-{1}" -f $prNumber, [guid]::NewGuid().ToString("N")142 )143 New-Item -ItemType Directory -Path $runStateDirectory | Out-Null144 ```145146 Store every baseline, snapshot, and watcher-state file for this run inside this directory so concurrent runs cannot overwrite one another.147148## 2. Resolve merge conflicts149150Run this before CI or feedback:1511521. Refresh PR/base metadata and perform a non-mutating local probe:153154 ```powershell155 $pr = gh pr view $prNumber --repo $baseRepository --json number,url,baseRefName,baseRefOid,headRefName,headRefOid,headRepository,headRepositoryOwner,mergeable,mergeStateStatus |156 ConvertFrom-Json157 git fetch $baseFetchUrl $pr.baseRefName158 $baseCommit = (git rev-parse FETCH_HEAD).Trim()159 git merge-tree --write-tree --messages HEAD $baseCommit160 ```1611622. Investigate locally when GitHub reports `CONFLICTING`, `DIRTY`, or `UNKNOWN`, or when the probe reports conflicts.1633. If conflicts exist, check the initial worktree baseline before merging. A normal merge requires a clean index: if any pre-existing staged change remains, stop before mutation and tell the user to commit or stash it, or request explicit permission to isolate and restore the index. Do not use `--autostash` on user work without that permission.164165 If the index is clean and unrelated local changes are safe, merge the latest base into the PR branch:166167 ```powershell168 git merge --no-ff $baseCommit169 ```1701714. Resolve each conflict using the recovered task intent, repository requirements, adjacent code, and tests. Do not mechanically prefer either side.1725. Run focused verification, stage only the resolution, and commit it. Record the conflict summary, commit SHA, and checks run.1736. If the merge is clean, keep any Git-created merge commit but do not create an extra empty commit.174175## 3. Fix failed CI1761771. Inspect all checks:178179 ```powershell180 gh pr checks $prNumber --repo $baseRepository --json bucket,completedAt,description,event,link,name,startedAt,state,workflow181 gh pr checks $prNumber --repo $baseRepository --required --json bucket,completedAt,description,event,link,name,startedAt,state,workflow182 ```183184 Use the second query to distinguish required checks from optional checks. Treat “no required checks reported” as an empty required set, not a failure.1851862. For each failure, retrieve the actual logs before editing:187188 ```powershell189 gh run list --repo $baseRepository --branch $pr.headRefName --commit $pr.headRefOid --json databaseId,name,workflowName,status,conclusion,url,headSha,event,createdAt -L 50190 gh run view <run-id> --repo $baseRepository --json name,status,conclusion,jobs,url191 gh run view <run-id> --repo $baseRepository --log-failed192 ```1931943. For non-Actions checks, inspect the provider link or available check details.1954. Fix the root cause, not merely the symptom. Work from the clearest upstream failure outward because one failure may cascade into others.1965. Run the closest local equivalent, inspect the initial worktree baseline, and stage only that fix. Commit with an exact pathspec so pre-existing staged changes remain outside the CI commit:197198 ```powershell199 git commit --only -m "fix(ci): address <failed check>" -- <exact-ci-fix-paths>200 ```201202 If a CI fix path had pre-existing staged, unstaged, or untracked changes, stop before editing it. Record the check, cause, SHA, and verification.2036. If a failure is external, flaky, permission-related, or not repository-fixable, capture evidence. Retry only when safe and supported; do not change code to appease an unrelated failure.204205## 4. Fetch and classify feedback206207Resolve the loaded skill's directory, then use its bundled helpers by absolute path; do not assume the skill lives inside the target repository.208209Capture every thread's read-only resolution baseline outside the repository:210211```powershell212$threadBaseline = Join-Path $runStateDirectory "thread-resolution.json"213$threadSnapshot = Join-Path $runStateDirectory "unresolved-threads.json"214pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname -All |215 Set-Content -Encoding utf8 $threadBaseline216217pwsh <skill-directory>/scripts/get-unresolved-pr-threads.ps1 -PrNumber $prNumber -Repository $baseRepository -Hostname $githubHostname |218 Set-Content -Encoding utf8 $threadSnapshot219```220221For each unresolved thread, read all paginated comments in chronological order and classify it. First identify comment authorship: PR Agent posts through the repository owner's own login, so classify every comment carrying the hidden `<!-- pr-agent:v1 -->` marker (or the "PR Agent" badge) as a PR Agent reviewer message — never as an agent response. Then classify the thread:222223- **Awaiting reviewer:** the latest relevant comment is an agent response in a submitted review (`pullRequestReview.state != PENDING` with non-null `submittedAt`) and nobody has replied later. Do nothing. Do not post a reminder, repeat the fix, or duplicate the response. PR Agent messages count as reviewer messages for this rule: when PR Agent replies (verification result, push-back, or resolution note), the thread is awaiting your action or is already resolved by it.224- **Action required:** there is reviewer feedback after the agent's latest submitted response, the agent has never responded, or its latest response exists only in a pending review. PR Agent inline findings are always action-required when the thread is unresolved: agree and fix with a focused commit, or push back with evidence and let PR Agent re-evaluate.225- **Superseded/non-actionable:** the later conversation explicitly withdraws, answers, or supersedes the point. Reply only if the thread still needs an agent acknowledgement; avoid duplicating an existing agent response. A PR Agent resolution note ("verified ... resolving this thread") on a thread it has just resolved needs no reply.226227Within action-required threads, identify each distinct feedback item. Judge it against the user's intent, conversation history, repository rules, linked requirements, PR scope, current code, conventions, and tests. The thread is the commit boundary: group all work required by one thread into that thread's single commit, but never include another thread's work.228229Classify actionable PR-level review bodies and issue comments with the same rules. Each standalone feedback item is its own commit boundary; never combine it with a review thread or another standalone item. Track it by feedback ID and permalink because it has no review-thread ID.230231- Agree when it identifies a real bug, missed requirement, broken invariant, missing test, misleading behaviour, or scoped maintainability problem.232- Disagree when it conflicts with requirements, established intent, repository invariants, or would produce a worse/out-of-scope design.233- When uncertain, make a small scoped correctness fix if evidence supports it. Otherwise explain the uncertainty and why no change was made.234235Do not skip outdated unresolved threads; determine whether their feedback still applies to current code.236237## 5. Fix and reply238239For each action-required review thread or standalone feedback item:2402411. Make the smallest complete fix for every actionable item in that thread, with focused tests.2422. Run the narrowest meaningful verification.2433. Inspect and stage only files for that item:244245 ```powershell246 git status --short247 git diff248 git add <paths>249 git diff --cached250 ```251252 Keep unrelated staged changes in other paths staged. Stop before editing any fix path that had a pre-existing staged, unstaged, or untracked change; never rely on partial staging followed by `git commit --only` for same-file isolation.2532544. If the disposition produces a change, create exactly one commit for the feedback unit before moving to the next unit:255256 ```powershell257 git commit --only -m "fix(pr): address <thread summary>" -- <exact-thread-fix-paths>258 ```259260 Do not amend, squash, or combine feedback commits. If an earlier unit's change completely satisfies a later agreed unit and no distinct file change remains, create an explicit traceability commit with `--allow-empty` for that later unit rather than merging their commit history. Do not create a commit for a justified disagreement.2612625. For review-thread feedback, reply directly to the thread after evaluating it and creating any relevant commit, subject to the Gitar deferral below:263264 ```powershell265 $body = @"266 Agreed. I fixed this in commit <sha> by <specific change>.267268 Verification: <command and result>.269 "@270 pwsh <skill-directory>/scripts/reply-to-review-thread.ps1 -ThreadId "<thread-id>" -Hostname $githubHostname -Body $body271 ```272273 For standalone feedback, post a PR-level reply that links the exact feedback permalink:274275 ```powershell276 $body = @"277 Regarding [this feedback](<feedback-permalink>): agreed. I fixed this in commit <sha> by <specific change>.278279 Verification: <command and result>.280 "@281 gh pr comment $prNumber --repo $baseRepository --body $body282 ```283284 Use the same PR-level path for a standalone justified disagreement, retaining the feedback permalink and the disagreement wording below.285286 For a justified disagreement:287288 ```text289 I don't think this change is correct for this PR.290291 Reason: <specific reason grounded in requirements, conversation, or code>.292293 No code change made.294 ```295296 If any Gitar-authored feedback disposition created a commit that has not been pushed yet, defer its thread or PR-level reply until immediately after the batch push. Gitar cannot verify a local-only SHA; replying before it can see the commit may cause a misleading follow-up. Prefix a PR-level Gitar reply with `Gitar,` so the dashboard feedback is processed; never ask it to apply the fix. A Gitar disagreement has no commit dependency and may be replied to immediately. Keep all replies serial.2972986. Record the one-to-one feedback-unit ID → commit SHA mapping for changed dispositions, plus every disposition, verification, and returned comment ID. Use the thread ID for review threads and the feedback ID for standalone items. Record `no commit — disagreement` for justified disagreements.299300The reply helper uses GitHub's single-comment reply endpoint so it never submits or modifies a shared pending review. It then verifies `state != PENDING` plus a non-null `submittedAt`. A helper failure is blocking; a returned comment URL alone is not proof of submission.301302After all replies:3033041. Re-fetch all threads with `-All`, plus PR-level reviews and issue comments.3052. Verify every reply created in this run belongs to a submitted review.3063. Verify the authenticated user has no pending review on the PR, including reviews created before this run.3074. For every thread ID present in the baseline, compare its `isResolved` value with the current value. Baseline resolution states must be unchanged; report external changes and never mutate them back. New thread IDs are expected during review convergence: classify them as additional feedback rather than treating their existence as a resolution mutation.3085. If new action-required review threads or standalone feedback items appeared during the batch, action each in its own commit and repeat the audit. Push only once the currently visible feedback set has been fully actioned or is awaiting reviewer response. Gitar threads with a deferred local-commit reply count as actioned for this pre-push audit, but the reply remains mandatory immediately after push.309310## 6. Push and converge with Gitar3113121. Confirm the worktree contains no uncommitted changes created by this run. Do not push individual thread commits as they are created; batch-push all unsquashed thread commits only after the feedback audit is clear for the time being.3132. Review commits after the starting SHA and every validated commit that was already local-ahead at invocation, then fetch the exact PR head before pushing:314315 ```powershell316 git log --oneline <starting-sha>..HEAD317 git fetch $headPushUrl $pr.headRefName318 $remoteHeadSha = (git rev-parse FETCH_HEAD).Trim()319 $localHeadSha = (git rev-parse HEAD).Trim()320 $currentPrHeadSha = (gh pr view $prNumber --repo $baseRepository --json headRefOid --jq .headRefOid).Trim()321 $pushRequired = $localHeadSha -ne $remoteHeadSha322 git status --short --branch323 ```324325 Stop if `$remoteHeadSha` and `$currentPrHeadSha` differ, or if either differs from `$lastObservedPrHeadSha`. Never overwrite `$lastObservedPrHeadSha` with an unexpected remote value. Use `$pushRequired`, not the starting-SHA commit range, to decide whether the PR head needs a push; the range is reporting context only.3263273. If `$pushRequired`, increment `$reviewRound` and capture a review baseline immediately before pushing:328329 ```powershell330 $reviewRound++331 $reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)332 pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `333 -CaptureBaseline `334 -StatePath $reviewState `335 -PrNumber $prNumber `336 -Repository $baseRepository `337 -Hostname $githubHostname `338 -PrAgentContext "PR Agent"339 ```3403414. Push without force and record the exact HEAD:342343 ```powershell344 $reviewRequestedAt = [DateTimeOffset]::UtcNow345 git push $headPushUrl "HEAD:refs/heads/$($pr.headRefName)"346 $expectedHeadSha = git rev-parse HEAD347 $lastObservedPrHeadSha = $expectedHeadSha348 ```349350 Immediately after the push, post each deferred Gitar thread or PR-level reply serially with its now-visible commit SHA and verification result. Verify thread replies are submitted, then refresh feedback once before waiting for Gitar. Post deferred PR Agent thread replies the same way — PR Agent can only verify fixes against pushed commits.3513525. After pushing, allow approximately 60 seconds for the exact-HEAD `Gitar` check to appear, and for the `PR Agent` status to flip to `pending` when PR Agent is running (it picks up pushes automatically; its review typically completes within one to three minutes):353354 ```powershell355 pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `356 -Wait `357 -StatePath $reviewState `358 -ExpectedHeadSha $expectedHeadSha `359 -ReviewRequestedAt $reviewRequestedAt `360 -ReviewStartGraceSeconds 60 `361 -TimeoutMinutes 25 `362 -PollSeconds 10363 ```364365 If this returns `review_not_started`, and only then, request review once for that pushed HEAD:366367 ```powershell368 gh pr comment $prNumber --repo $baseRepository --body "gitar review"369 ```370371 Do not post the fallback comment when an exact-HEAD Gitar check appeared during the grace period, even if it is still queued or processing.3723736. If the grace-period watcher returned `review_not_started`, resume the bundled watcher against the same baseline:374375 ```powershell376 pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `377 -Wait `378 -StatePath $reviewState `379 -ExpectedHeadSha $expectedHeadSha `380 -ReviewRequestedAt $reviewRequestedAt `381 -TimeoutMinutes 25 `382 -PollSeconds 20383 ```384385 Run it as a long-lived tool call. While it runs, use only the environment's wait mechanism and remain silent unless the user interrupts. The watcher keeps repeated polling out of model context.3863877. Handle its terminal result. The watcher converges on both reviewers: when PR Agent is running (`prAgentRelevant` true in the result), a `PR Agent` status on the exact HEAD is part of every terminal state, and PR Agent's inline findings are delivered through `newFeedback` like every other reviewer's:388 - `feedback`: fetch all feedback for context, but action only IDs in `newFeedback`. This may include inline threads (from PR Agent, Gitar, or any other reviewer), PR-level feedback from any reviewer, Gitar's dashboard when its verdict is `Approved with Suggestions`, `Changes Requested`, `Blocked`, or `Needs Review`, and a synthetic `pragent_status` item when PR Agent reported `failure` without captured comments. If a new comment extends an old unresolved thread, read the full thread and handle only feedback after the last agent response. PR Agent findings follow the same agree-and-fix / push-back rules, and it will re-verify pushed fixes and resolve its threads automatically.389 - `approved`: the exact-HEAD Gitar check completed successfully with a fresh `Approved` dashboard verdict (when Gitar is running) AND the exact-HEAD `PR Agent` status is `success` (when PR Agent is running). Re-fetch checks, dashboards, PR-level feedback, and threads once; finish only if the full definition of done still holds.390 - `gitar_failed`: inspect the Gitar check and dashboard details. Treat provider/integration failure as a blocker unless repository evidence gives a scoped fix; never describe the PR as reviewed successfully.391 - `review_not_started`: post the single fallback `gitar review` comment, then resume step 6. This outcome is never returned while PR Agent is still processing a review.392 - `timeout`: report that a reviewer did not reach a terminal state; do not claim readiness.393 - `head_changed`: fetch and inspect the new state. Stop when another actor's push makes continued mutation unsafe.394 - `pr_closed`: stop and report the PR state.3953968. For new feedback, repeat fix → verify → commit → serial reply → audit → baseline → push → automatic-review grace period → wait.397398If no push is needed, never post `gitar review`: the fallback is only permitted after this run pushes a new HEAD. Capture the current state and wait read-only. A completed successful `Gitar` check on the exact current HEAD plus an `Approved` dashboard verdict — and a `success` `PR Agent` status on the same HEAD when PR Agent is running — is sufficient; no Pro approval signal is required. Otherwise wait for an already-running automatic review and stop on timeout without posting a trigger.399400```powershell401$expectedHeadSha = (git rev-parse HEAD).Trim()402$reviewRound++403$reviewState = Join-Path $runStateDirectory ("review-round-{0}.json" -f $reviewRound)404pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `405 -CaptureBaseline `406 -StatePath $reviewState `407 -PrNumber $prNumber `408 -Repository $baseRepository `409 -Hostname $githubHostname410pwsh <skill-directory>/scripts/wait-for-pr-review.ps1 `411 -Wait `412 -StatePath $reviewState `413 -ExpectedHeadSha $expectedHeadSha `414 -ReviewRequestedAt ([DateTimeOffset]::MinValue) `415 -TimeoutMinutes 25 `416 -PollSeconds 20417```418419The watcher verifies that Gitar's check belongs to the exact expected SHA. After a push, it also requires the dashboard comment to have changed after the baseline and in the same processing window before accepting its verdict, because Gitar edits one persistent dashboard comment in place. Never use the fallback comment without a preceding push from this run. When PR Agent is running, the watcher additionally waits for the exact-HEAD `PR Agent` status to reach `success` or `failure` before reporting `approved` or `feedback`, and never reports `review_not_started` while PR Agent is processing.420421Bound convergence to five pushed review rounds or two hours overall. Stop earlier for a clean combined result, timeout, closure, unexpected head movement, or a genuine blocker.422423## Final audit and response424425Re-fetch rather than relying on cached state:426427- PR head, mergeability, and base;428- latest base commit and a fresh local `git merge-tree --write-tree --messages HEAD <base-commit>` conflict probe;429- all checks;430- required checks queried separately with `gh pr checks --required`;431- the exact-HEAD Gitar check and Gitar dashboard Code Review verdict;432- the exact-HEAD `PR Agent` status state (when PR Agent is running for this repository);433- PR-level reviews/comments;434- all review threads and reply submission states;435- local/remote branch state and worktree.436437Report concisely:438439- PR number and URL;440- conflict and CI outcome, with commits;441- thread counts: actioned, awaiting reviewer, and disagreed;442- fixes, focused verification, and commit SHAs;443- push result and Gitar review rounds;444- terminal Gitar Core status for current HEAD: successful completed check plus `Approved` dashboard verdict;445- terminal `PR Agent` status for current HEAD: `success` (or `not running` when no `PR Agent` status exists on the pull request);446- pending review replies: `0`;447- review-thread resolution mutations: `0`, with baseline audit result;448- any blocker or required check still pending.