PR review mode: pluggable platforms and two-way review threads

Author: backnotpropCreated Sep 21, 2026Updated Sep 21, 2026
Labelsenhancementacceptedtriage

Provenance stamp: This issue was triaged on September 20, 2026 as part of the older-than-90-days GitHub issue triage exercise.

Source issues: #671, #754

Summary

PR review mode is a closed, one-directional integration. It activates only for two hard-coded platforms, and even on those it can only post a new review — it cannot continue a conversation that already exists. Both source issues are consequences of that single shape.

The common requirement is that PR mode be described by a provider contract rather than a URL regex, and that a review thread be a two-way object rather than a read-only sidebar entry.

What the source issues requested

  • #671 requested an override mechanism so third-party integrations (an MCP server, a custom tool, Bitbucket) can activate the rich PR review UI with their own data — the way the External Annotations API already lets external sources push inline comments. Today parsePRUrl() rejects any other URL and prMetadata stays null, so the header PR controls, Post Comments, thread UI and viewed sync never appear. The reporter offered to contribute.
  • #754 requested that GitHub review threads already fetched onto PRContext be rendered as markers anchored to the diff lines they belong to, visually distinct from the reviewer's own annotations, and that those threads be continuable from inside Plannotator — reply via POST /pulls/{n}/comments with in_reply_to, and resolve/unresolve via the GraphQL resolveReviewThread mutation.

Triage determination

Kept together because they touch the same boundary from opposite sides and would otherwise be designed twice. A provider contract that only supports "open a PR and post one review" would not be enough for a Bitbucket integration either — replying to an existing thread is table stakes on every platform. Conversely, building reply/resolve directly against gh's GitHub shapes would harden the two-platform assumption that #671 is asking to remove.

Current state verified on main (2026-09-20):

  • parsePRUrl recognises only GitHub/GHE /pull/ and GitLab /-/merge_requests/ (packages/shared/pr-types.ts:347-380); PRRef.platform is a closed union (:305-314); every PR route requires a prMetadata produced by fetchPR through gh/glab (packages/server/review.ts:220,295). No injection path exists.
  • reviewThreads are fetched and rendered only in the sidebar (packages/review-editor/components/PRCommentsTab.tsx:160-166); DiffViewer and AllFilesCodeView reference them zero times. in_reply_to and resolveReviewThread have zero occurrences repo-wide; hideResolved is a client-side filter, not a mutation.
  • What did ship and lowers the cost: launchable Review Agents (#611) put non-session-author findings on diff lines as inline comments, so the machinery for rendering a line-anchored marker that is not the reviewer's own already exists.

Acceptance criteria

  • PR mode activation is expressed as a provider contract (identity, metadata, threads, submit, viewed-sync), not as a URL regex over two platforms.
  • An external source can supply PR metadata and threads without Plannotator shipping that platform's client — the External Annotations API is the precedent for the shape.
  • A provider may declare partial capability (for example: threads yes, viewed-sync no) and the UI hides what is unsupported rather than failing.
  • Existing review threads render as markers anchored to their diff line, visually distinct from the reviewer's own annotations, with resolved threads hidden behind a toggle.
  • A thread can be replied to from the diff or the PR Comments panel, and the reply appears in the thread without refetching the whole PR context.
  • A thread can be resolved and unresolved from Plannotator, with local state updated accordingly.
  • GitHub and GitLab remain fully supported through the same contract, with no regression to the current gh/glab paths.
  • The --patch-file static-patch mode stays the documented answer for "just show me a diff", distinct from PR mode.
  • #671 and #754 can be closed once their requirements are represented here. #754 carries an accepted commitment, which this issue inherits.

Notes

If the maintainer would rather not couple these: the alternative is to keep #754 open on its own (it is the better-specified and more-demanded half, 4 ) and close #671 with a direction for the contributor. Consolidating is recommended because the provider contract is what decides where the reply/resolve code lives.