Files
PaperClipAI/doc/connections/UNDERSTANDING-GITHUB-PR-REVIEW-BOTS.md
T
DottaandPaperclip 3b8324a233 fix(github): keep one main PR review comment and reconcile stopped work (#16901)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub connections send review requests to an assigned agent.
> - A PR needs one main comment that shows its current review state.
> - The response ledger used one comment per incoming request. Pushes
and follow-up messages created more placeholders.
> - Thread subscriptions also accepted requests addressed to external
bots. Recovery could leave an acknowledged request without a final
notice.
> - This pull request shares the main PR comment, filters other
recipients, and reconciles stopped work.

## Linked Issues or Issue Description

Related: #16874 showed the repeated placeholders. #15416 introduced the
per-request response path. The prior summary path used one PR-level
marker.

**What happened?**

Repeated pushes created new main PR comments. A subscribed `@greptile
review` message also woke the Paperclip bot. If execution stopped before
staging a milestone, its comment could keep claiming that work was
active.

**Expected behavior**

One bot keeps one main comment per PR. Progress and review results
update it. A message addressed to another recipient does not wake the
bot unless it also explicitly mentions this bot. Stopped work gets an
accurate notice.

**Steps to reproduce**

1. Accept two review requests in one PR conversation.
2. Add `@greptile review` to that subscribed conversation.
3. Fail the assigned run before it stages a milestone. Run channel
maintenance.

## What Changed

- Add a durable main PR response target. Keep per-request receipts and
the existing publication lease.
- Recover the target from App-owned provider markers. Adopt older
placeholders and point verified duplicates to the current review.
- Use a queued notice before a PR run starts. Preserve version ordering
and final responses.
- Filter leading mentions addressed to another recipient. Explicit
mentions of this bot take precedence. Incidental mentions keep normal
thread behavior.
- Reconcile acknowledged requests after terminal execution. Show paused
state for saved requests on a blocked task. Preserve newer work and
confirmed or uncertain tool delivery.
- Keep a request open when its stale acknowledgement is suppressed.
Close placeholders after replies published elsewhere. Retire old
coalesced placeholders before replacing their receipts. Resolve native
request identity when legacy wake fields are absent.
- Update guidance, connection documentation, and feature/access maps.

## Verification

- Red: all three behavioral regressions failed on the original code. A
second review created a second comment; an external-bot request was
processed; stopped execution retained its working placeholder.
- Green: the same three cases passed after the fixes.
- Review regressions also failed before their repairs: a delayed
acknowledgement closed a new request; normal and stored formal-review
receipts left a live placeholder; coalesced completion lost a duplicate
receipt; native terminal work without legacy wake fields stayed queued.
All 13 combined regression and safety cases passed after repair.
- The same legacy receipt-loss bug was also reproduced in the
superseded-acknowledgement branch. Its four affected cases passed after
adding retirement before that receipt replacement.
- A further review regression reproduced paused requests rejecting
resumed progress and skipping stopped-run cleanup. Four cases failed
before repair; all eight resume and neighboring safety cases passed
afterward. Both paused-notice branches keep the request open.
- Repeated paused maintenance reproduced two needless GitHub edits. The
writer now skips an identical complete comment body. Nine affected cases
passed, covering repeated maintenance, resumption, stopped work, final
assessment preservation, and main-comment reuse.
- Safety cases cover lost receipts, legacy adoption, newer progress,
published assessments, provider-verified mention aliases, and old
replies that must not complete new requests.
- `pnpm -r typecheck`, `pnpm build`, map validation, and module
boundaries passed. The server TypeScript check passed after the final
repair. The broader local GitHub workflow and policy run passed 188
tests. Full CI passed on the final commit
(`554979d79285b68bcbf90cd639e3d2d053f4ea4b`), including all three chat
shards, server/workspace/Runner suites, typecheck, build, and E2E gates.
Greptile is 5/5 with no open review findings. One serialized job
received a runner shutdown signal mid-test; its single retry passed.
- Preserved failure evidence: the first CI run exposed an overbroad
recipient filter and an old queued-text assertion. The next commit
passed all three CI chat shards. Greptile then found the receipt
transitions covered by the new regressions above. Local full-suite runs
were stopped when those defects required source changes; no clean full
local pass is claimed.
- Tests use real PostgreSQL and controlled provider responses. They do
not establish a live GitHub App rollout. The original instance needs the
fixed server before its comments change.

## Risks

- Leading mentions now select a recipient even when that account has no
Paperclip connection. A leading human mention also selects that person.
Mid-message incidental mentions retain normal subscription behavior.
- Existing comment adoption edits only comments proven by this
endpoint's request ledger or prior summary marker and App identity.
Deleted and replaced comments remain protected.
- Failure cleanup uses current authority and does not replace newer
progress or unresolved provider writes. It does not restart failed
execution.
- No schema migration is required.

## Model Used

OpenAI Codex, GPT-6. The exact serving model ID and context-window size
are not exposed in this session. The model used reasoning, tools, code
execution, and browser inspection.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 21:51:20 -05:00

16 KiB
Raw Blame History

Understanding GitHub PR review bots

A bot can review your PR, leave comments, and give it a 3/5 without preventing anyone from merging it. That can feel surprising: if the review failed, why would GitHub still allow the merge?

The missing piece is that making the bot a required PR check needs a separate GitHub repository setting. GitHub lets you get feedback from a bot without committing to making that feedback a merge requirement.

Installing the bot, deciding when it runs, and requiring its result before merging are three independent choices.

Here's how they fit together in what we built:

  1. Install the App: give the bot access to your repository and let GitHub send it notifications.
  2. Choose its triggers: tell Paperclip when those notifications should cause the agent to review.
  3. Require its check, if you want to: tell GitHub whether merging must wait for a passing result.

There is also a translation between the second and third choices: the agent's “3/5” or “5/5” has to become a check result that GitHub understands. We'll walk through that too.

Imagine we are setting up a bot for a repository that merges PRs into main. We want to understand each choice before turning all of them on. For the full onboarding procedure, see GitHub chat and review bots.

1. Installing the GitHub App gives the bot access and event notifications

First, the bot needs a way to participate in your repository. You install the GitHub App on the repositories you choose. Its permissions let it read code, post comments and reviews, and publish checks.

This establishes what the bot is allowed to do. It does not yet mean “review every PR,” and it does not mean “nobody can merge without this bot.” Those are the choices we'll make later.

The App also has a webhook URL pointing to Paperclip. A webhook is simply GitHub sending an HTTP notification to that address when something happens. This is how Paperclip learns about your PR without repeatedly asking GitHub whether anything has changed.

Here are the notifications involved:

What happens on GitHub Webhook received by Paperclip
Someone comments on an issue or in a PR's main conversation issue_comment
Someone comments in an inline PR review thread pull_request_review_comment
Someone opens a PR pull_request, with action opened
Someone pushes new commits to an existing PR pull_request, with action synchronize

For example, you write @your-bot please review this PR. GitHub sends the comment to the App's webhook, and Paperclip recognizes an authorized request in its text. There is no separate GitHub mechanism that understands what an AI review should do; that interpretation belongs to Paperclip.

Our connector does not require a GitHub Actions workflow file in the repository. Paperclip receives the event and runs the assigned agent in an ordinary Paperclip task. The bot's App identity supplies its governed GitHub tools.

GitHub installation access and Paperclip's enabled repositories are separate controls: the App needs access on GitHub, and the repository must also be enabled for this bot in Paperclip.

See GitHub's webhook documentation.

2. Paperclip's configuration decides which notifications start a review

Now the bot can hear about repository activity. The next choice is which of those notifications should actually start work.

That choice matters because you may want help only when you ask for it. Or you may want every eligible PR reviewed as soon as it opens. Both setups use the same GitHub App and webhook; Paperclip's configuration changes what happens after the notification arrives.

You can choose:

  • Mentions only: someone must explicitly ask the bot to review.
  • Automatic reviews: review new PRs, updated commits, or other selected events.
  • Both: review automatically and also accept requests to review again.

Opening a PR, reopening it, marking it ready for review, and pushing new commits are independently configurable events. Automatic reviews also respect the configured author, draft, branch, label, and repository restrictions.

Suppose you open our example PR with mentions only enabled. GitHub still notifies Paperclip that the PR opened, but Paperclip does not start an automatic review. When you add @your-bot please review, that authorized request starts the assigned agent.

If you enable automatic reviews on new PRs, opening the same PR starts the review without anyone mentioning the bot. You can separately enable reviews for new pushes, or require a fresh mention for those later assessments.

An authorized manual request can bypass automatic scheduling filters. It cannot bypass repository restrictions, excluded files, or the requester's permissions.

A mention in an ordinary issue starts a task conversation; a PR rating check concerns a particular PR commit. Ordinary follow-up discussion does not change the rating. Repeat review requests continue the PR's existing Paperclip task.

3. The agent's score becomes a GitHub check result

At this point the agent has done a review. Suppose it finds a problem and gives our PR a 3/5. What does GitHub do with that number?

On its own, nothing. GitHub has no built-in concept of 5/5. It does not read a bot's comment and infer that “3/5” should prevent merging. The score belongs to Paperclip's assessment format and rating policy.

To make the result usable by GitHub's merge rules, Paperclip translates the assessment into a check run named Paperclip Review. This is the same kind of GitHub object you see for a build or a test result.

The agent submits a structured assessment containing the reviewed commit, score, findings, rationale, and coverage. Paperclip validates the result and compares it with the configured threshold. The agent does not directly choose an arbitrary passing check result.

With a minimum score of 5:

Agent submits a complete assessment: 3/5
    → Paperclip validates it
    → Paperclip reports failure to GitHub

Agent submits a complete assessment: 5/5
    → Paperclip validates it
    → Paperclip reports success to GitHub

You can therefore see both a comment saying “3/5” and a red Paperclip Review check on the PR. The comment explains the result to a person. The check gives GitHub a result its rules can use. The check is attached to the exact commit the agent reviewed.

Review situation What the check reports
Waiting for the agent Queued
Agent is reviewing In progress
Complete assessment meets the threshold Success
Complete assessment falls below the threshold Failure
Incomplete assessment or execution that cannot finish A non-passing result requiring attention
Complete assessment in report-only mode Neutral; a low score does not fail the check

The threshold defaults to 5/5 and can be set from 1–5. An incomplete assessment cannot pass. Report-only mode is useful for feedback without enforcing a score; it is not a substitute for a required score threshold.

For our Storybook example, the configured review instructions ask the agent to generate and build stories, render the pages, and look for visible oogabooga. A complete run finding the word scores 5/5; a complete run finding no matching page scores 3/5. A build failure leaves the assessment incomplete. With a 5/5 threshold, only the first outcome passes.

See GitHub's Checks API guide.

4. GitHub's repository rules decide whether the check blocks merging

Our example PR now has a red Paperclip Review check. We still have one choice left: should that result prevent merging?

A bot can publish a failing check without preventing a merge. GitHub allows checks to provide optional feedback. The repository owner decides which checks are important enough to require before code reaches a branch such as main.

That is why installing the bot or enabling automatic reviews does not create a merge requirement. You might want to try a reviewer and inspect its feedback before making the whole team's merges depend on it.

To make its result mandatory, a repository administrator configures a rule that means: “PRs into main need a passing Paperclip Review check.”

A typical setup is:

  1. Install and configure the bot, then let it publish its first Paperclip Review check.
  2. Open the repository's Settings → Rules → Rulesets.
  3. Create or edit a branch ruleset targeting the branch you merge into, such as main.
  4. Enable Require status checks to pass and add Paperclip Review.
  5. Select the bot App as the expected source where available, so a result from a different integration does not satisfy the requirement.
  6. Set the ruleset's enforcement to Active and choose bypass permissions deliberately.

A classic branch-protection rule can also require the check. Organization rules may already impose requirements on a repository. Paperclip does not automatically change these GitHub rules when you install or configure a bot.

Requiring the check does not itself start the agent. It tells GitHub to wait for the result. The trigger configuration in Paperclip still decides when the agent runs.

For example, you can require the check while leaving the bot in mentions-only mode. That is a valid setup: someone must explicitly ask for a review before the PR can satisfy the merge rule. Turning on automatic reviews removes that manual initiation step; it does not make the merge rule stronger.

If nobody triggers a required review, the missing result prevents merging for users subject to the rule. If the connector receives a PR event but automatic execution is disallowed under its configured rating policy, it can publish Authorized manual review required. An authorized mention can then start the review.

GitHub plan and repository visibility affect whether these rules are available. Verify that the rule is active and applies to the target branch; a visible check alone does not prove merge enforcement. Configured bypass rights still apply.

See available rules for GitHub rulesets and creating a repository ruleset.

The four useful combinations

We can now put the two behavior choices next to each other. This is why “the bot reviews PRs” does not, by itself, tell you whether it runs automatically or whether its result is mandatory:

Review trigger GitHub requires Paperclip Review? What happens
Mentions only No Optional review when someone asks. Its failing check alone does not block merging.
Automatic No Automatic feedback. Its failing check alone does not block merging.
Mentions only Yes Merging waits until someone requests a review and the required check passes.
Automatic Yes Reviews run automatically. Merging waits for the required check to pass.

Other repository rules, including formal review requirements, may independently block a merge in any of these scenarios.

What happens when someone pushes again or mentions the bot again?

Suppose the agent gives our PR a 3/5 and the required check fails. You fix the problem and push another commit.

GitHub now needs an assessment of that new code. A check result belongs to the commit it assessed: even if the previous version had passed, that result would not establish that the new version is good.

What happens next depends on the trigger choice we made earlier:

  • Automatic push reviews enabled: the push notification starts a new review.
  • Push reviews disabled: you write @your-bot please review again to start it.

The agent reviews the new commit, submits a complete 5/5, and Paperclip publishes a successful check. The PR has now satisfied this merge requirement. Other required checks or human approvals may still be outstanding.

A repeat review mention can also request a fresh assessment of the same commit. The conversation continues in the same Paperclip task, with review history retained and one current summary updated. Old executions cannot overwrite the latest head's assessment.

See GitHub status checks.

How the agent replies

The agent chooses what to send through its task-scoped GitHub tools. For discussion, it uses comment. For a review, submit_review publishes the assessment summary and updates the check. It should not add another comment just to announce that the review is complete.

Paperclip keeps one main comment per bot per PR, beginning with “Review queued…”. Pushes and repeat requests reuse it. The agent can periodically edit it with update_comment as it makes progress. Its final comment or review summary replaces the same comment; inline-only reviews close it with a link to the finding. Coalesced PR requests share the main comment; issue and inline threads keep per-request responses. New requests no longer create eyes reactions.

The runner's final text stays inside the Paperclip task. If a run ends without a tool reply, Paperclip updates the working comment with a safe notice and a link to the task. A real question can link to its answer form in Paperclip. Maintenance clears stale working states after recovery stops, and requests saved while the task is blocked show a paused notice. A leading mention addressed to another recipient, such as @greptile review, does not wake this bot unless the message also explicitly mentions it. A confirmed reply suppresses fallback notices. Pending or uncertain tool delivery prevents a duplicate reply while its receipt is resolved. A check alone does not count as a conversation reply.

Formal Approve and Request changes reviews are separate

GitHub also supports formal PR reviews: Approve, Request changes, and comment-only reviews. These participate in GitHub's review policies, which are separate from required status checks.

This is another place where the word “review” can be confusing. We have been talking about an agent assessing code and producing a check. Clicking GitHub's Approve button—or having a bot perform that action through the API—is a separate operation.

You may want the agent's assessment to be mandatory while still reserving approval for a human. Requiring the bot's check and separately requiring human review lets you express both expectations.

Three things can therefore appear on the same PR:

Item What it means
A summary comment saying “5/5” The bot's explanation of its assessment.
A successful Paperclip Review check The validated assessment satisfied the configured rating policy for that commit.
A formal Approved review The bot explicitly performed GitHub's approval action under separately enabled permissions.

A 5/5 does not automatically submit a formal approval. A formal approval does not turn a failing check green. Neither replaces other required checks or human review requirements.

Paperclip's APPROVE and REQUEST_CHANGES permissions are individually configurable and both off by default. Enabling an action allows the agent to request it through a governed tool; it does not automatically perform it.

See GitHub's protected-branch and review requirements.

A practical setup for an automatic required reviewer

  • Install the App on the intended repositories and enable them in Paperclip.
  • Enable reviews on new PRs and updated commits, plus authorized repeat mentions.
  • Set the minimum score to 5/5.
  • In GitHub, require Paperclip Review for the target branch, using the bot App as its expected source where available.
  • Keep formal bot approvals off unless you specifically want that separate action.
  • Configure any human approval requirements independently.

With that setup, opening a PR starts the agent, the assessment becomes a check, and GitHub waits for that check to pass. A push starts a fresh assessment of the new code, and a mention lets you explicitly ask for another review. Each part has its own job, and you choose each one deliberately.