Skip to content

feat(desktop,service,features): reviewer and label pickers in the Pull request tab's header - #3309

Merged
luke-agent[bot] merged 2 commits into
mainfrom
feat/pr-header-reviewer-label-pickers
Oct 18, 2026
Merged

luke-agent[bot] merged 2 commits into
mainfrom
feat/pr-header-reviewer-label-pickers

Conversation

@dastratakos

@dastratakos dastratakos commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This is F2 of the "Reviewers, labels and stack navigation" stack. F1 (#3268) has merged, so this now targets main, squashed to one commit on it. It adds pickers to add and remove requested reviewers (users and teams the repository allows) and labels (the repository's labels). Every write goes through W1's member write path (#3272): it is made as the member who pressed it, on their own GitHub sign-in, and never on the Luke GitHub App.

  • Reviewer picker: a person-plus button beside the reviewer faces, shown only while the PR is open or a draft. Its menu lists the teams that reach the repository, then its collaborators, with the PR author left out. Anyone currently requested is checked, and choosing an item requests a review or withdraws the request.
  • Label picker: a tag button at the end of the labels row. Its menu lists the repository's labels, each with its colour dot, and the ones on the PR are checked. Choosing one adds or removes it. It's offered on merged and closed PRs too, as GitHub allows that.
  • What the pickers offer comes from a new read, GET /api/agents/{id}/review-options: the repository's labels, its collaborators (named against the workspace's members) and its teams.
    • It uses the App's installation token, as the overview reads do, and is read once, when a picker first opens. It is read again only after a failure.
    • Each list is paged up to 300 entries. If the App may not read one of them (for example a user-owned repo's teams, or a 403), that list is empty, a warning is logged, and the rest still show.
  • Writes: pull-request-write-wire.ts's action union gains request-review, remove-review-request (a { kind: user | team, name } reviewer), add-label and remove-label (a label name).
    • coding-agents-app.ts's actionWrite dispatches them through memberPullRequestWrite.
    • They are REST writes on the member's token (setReviewRequested, setLabelled in github/pull-request-writes.ts). GraphQL has no mutation that removes a requested reviewer; requestReviews with union: false replaces the whole set, which races with other changes. So all four writes use REST, with GitHub's refusals told apart exactly as githubWrite's are (401 → sign in again; other statuses → GitHub's own words).
    • github-app.ts gains githubSendRequest next to githubPost, for the POST and DELETE.
  • The PR read now also carries requestedTeams (from requested_teams in the same REST read, so no extra request), which the reviewer picker uses to check teams.
  • After a write, the tab re-reads exactly as W1's pill does, and GitHub's refusal shows on W1's line under the bar. While a change is out, the pickers are disabled. The pill only shows "…" for its own actions now (pull-request-writes.tsx).

Screenshots

From a throwaway harness, redrawn after moving the header's CSS onto the shared --luke-* roles (#3524 removed the old aliases; this also fixes the F1 label and stack rules already on main): the tab with a fake window.luke and the built styles.css. One team and one user are requested, and the repository offers 2 teams, 4 people and 5 labels.

Dark Light
Header, dark Header, light
Reviewer picker, dark Reviewer picker, light
Label picker, dark Label picker, light

GitHub requests

  • Opening a picker the first time: 3 REST listings on the installation token, in parallel (/labels, /collaborators, /teams), one page each up to 100 entries. None after that for the life of the tab.
  • Each change: 1 REST write on the member's token.
  • The header read: unchanged, with requested_teams coming from the same response.

Wire

  • New answer schema: codingAgentReviewOptionsAnswerSchema, plus its view schema.
  • codingAgentOverviewPullRequestAnswerSchema: gains an optional requestedTeams.
  • pullRequestActionRequestSchema: gains four branches.
  • Goldens: re-recorded for those, and for codingAgentPullRequestActionParamsSchema, which embeds the action schema.
  • Plumbing: new gateway method and act codingAgents.reviewOptions, threaded through compose, operator, IPC and CodingAgentsControl.readReviewOptions.
  • Rewrites: new route shell apps/web/server/routes/agents/review-options.ts, with api-rewrites.json and vercel.json regenerated by pnpm --filter @luke/web functions:rewrites.

Evidence

  • pnpm check:affected runs out of memory in this sandbox, so I ran the per-package fallback:
    • tsc for @luke/desktop, @luke/service, @luke/features, @luke/host and @luke/gateway: pass.
    • ./scripts/oxlint.sh: 0 errors.
    • pnpm knip: pass.
    • pnpm discarded-effect: pass.
    • ./scripts/repository-checks.sh: pass, including the rewrites --check and the api-callers scan.
  • Tests:
    • coding-agents-app.test.ts: the new and W1 suites, 10 tests, pass.
    • agent-pull-request-tab.test.ts: 29 pass.
    • packages/host/src, IPC acts and Vercel functions: 179 pass.
    • Wire goldens: 336 pass.
  • node scripts/build.mjs in apps/desktop: within the bundle budget.

New tests:

  • Service: a teammate requests a team review, withdraws a user's request, adds a label and removes one, each as a REST write with the teammate's own bearer (method, path and body checked). A 422 from GitHub comes back in its words. A reviewer kind the wire doesn't define is refused before reaching GitHub. The options read returns labels and named collaborators, with teams empty on a 403, all on an installation token and never a member's.
  • Desktop: the reviewer picker reads the options only when first opened, lists teams then people (author excluded, requested ones checked), and requests and withdraws reviews. The label picker removes and adds labels. A merged PR offers no reviewer picker.

Invariants

  • ./scripts/check.sh green. (CI)
  • JSON Schema goldens: only the new schemas and the extended action union and overview answer changed.
  • Every behavior change has a test that fails without it.
  • No new as type assertion.
  • No Effect run outside the edges; no raw async primitives; no discarded Effect.
  • No member token logged or answered. Writes never fall back to the App.

Notes

  • Shared action union: pull-request-write-wire.ts and actionWrite keep both this PR's four actions and main's review-submit and thread reply/resolve actions. The reviewer and label writes go by REST on owner, repo and number; the rest go through the node id.
  • Follow-ups:
    • The picker has no search box yet; long lists scroll.
    • Requested teams aren't drawn in the header's facepile; only the picker shows them.
    • Collaborators are only a proxy for who can be requested. GitHub refuses anyone it won't accept, in its own words.

Made with Luke


Devin Review


Summary by cubic

Adds reviewer and label pickers to the Pull request tab's header. The reviewer picker offers the repository's teams and collaborators (the author left out) on open and draft PRs; the label picker offers the repository's labels and also works on merged and closed PRs. The header's labels, stack, and pickers now draw with the shared --luke-* design roles, since the legacy token aliases were removed in #3524.

  • A new read, GET /api/agents/{id}/review-options, fetches the repository's labels, collaborators, and teams once, when a picker first opens, on the App's installation token, paged up to 300 entries each. A listing the App may not read (403) comes back empty with a logged warning; any other failure fails the read, and the picker reads it again.
  • Four new write actions — request-review, remove-review-request, add-label, and remove-label — go out as REST calls on the member's own GitHub token, since GraphQL has no mutation that removes a requested reviewer. A 401 asks for a fresh sign-in; other refusals show GitHub's own words on the existing write line.
  • The pickers disable while a change is in flight and until the tab re-reads after it lands. The PR read now carries the requested teams, so each picker checks what already stands.

Written for commit 4466df2. Summary will update on new commits.

View guided diff Turn on auto-fix

@vercel

vercel Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
luke-web Ready Ready Preview Oct 18, 2026 6:12pm UTC

Request Review

@luke-agent
luke-agent Bot changed the base branch from main to feat/pr-header-labels-stack October 17, 2026 02:03
devin-ai-integration[bot]

This comment was marked as resolved.

@luke-agent
luke-agent Bot force-pushed the feat/pr-header-labels-stack branch from 4650e32 to f97c089 Compare October 17, 2026 02:06
luke-agent Bot added a commit that referenced this pull request Oct 17, 2026
…nd hold the pickers until the read after a change lands

Devin's review of #3309: only a listing the App may not read (403) stands
empty; any other failure fails the read, so the picker reads it again. And
the pickers stay disabled while the pull request is read again after a
change, so nothing is chosen from what it held before.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 951cd61 to a8f65b3 Compare October 17, 2026 02:12
Base automatically changed from feat/pr-header-labels-stack to main October 18, 2026 16:19
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 535173a to f5979b0 Compare October 18, 2026 16:29
@luke-agent
luke-agent Bot enabled auto-merge October 18, 2026 16:29
@luke-agent
luke-agent Bot disabled auto-merge October 18, 2026 16:35
@luke-agent
luke-agent Bot enabled auto-merge October 18, 2026 16:37
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 325b386 to 2156a70 Compare October 18, 2026 16:48
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 18, 2026
@luke-agent
luke-agent Bot enabled auto-merge October 18, 2026 17:02
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 2156a70 to 612a1d3 Compare October 18, 2026 17:02
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 612a1d3 to 3454c35 Compare October 18, 2026 17:15
@luke-agent
luke-agent Bot disabled auto-merge October 18, 2026 17:17
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 18, 2026
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 3454c35 to 3d9d415 Compare October 18, 2026 17:33
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 18, 2026
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 18, 2026
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from 3d9d415 to d91d443 Compare October 18, 2026 17:53
@luke-agent
luke-agent Bot enabled auto-merge October 18, 2026 17:53
@luke-agent
luke-agent Bot disabled auto-merge October 18, 2026 18:02
dastratakos and others added 2 commits October 18, 2026 18:06
…l request tab's header

The header gains a reviewer picker beside its reviewers and a label picker
at its labels' end, each a menu of what the agent's repository offers, its
teams and collaborators or its labels, read once on the App's token as a
picker first opens (`GET /api/agents/{id}/review-options`). Choosing one
asks a review of a user or a team, or asks it no longer, or puts a label on
or takes it off: four new actions on the member write path, each a REST
write on the member's own GitHub token, since GraphQL offers no mutation to
take a requested reviewer off. The pull request's read now carries the
teams it asks a review of, which the picker checks. A listing GitHub did
not answer fails the read so the picker retries it, and the pickers hold
until the read after a change lands.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
…hared --luke-* roles

#3524 removed the desktop's legacy token aliases, so the labels', stack's,
and pickers' rules read --space-*, --hairline, --text-*, and --raised to
nothing on main. Each now reads the role its alias pointed at.

Co-authored-by: luke-agent[bot] <339870089+luke-agent[bot]@users.noreply.github.com>
@luke-agent
luke-agent Bot force-pushed the feat/pr-header-reviewer-label-pickers branch from d91d443 to 4466df2 Compare October 18, 2026 18:09
@luke-agent
luke-agent Bot enabled auto-merge October 18, 2026 18:09
@luke-agent
luke-agent Bot added this pull request to the merge queue Oct 18, 2026
Merged via the queue into main with commit dd817f1 Oct 18, 2026
12 checks passed
@luke-agent
luke-agent Bot deleted the feat/pr-header-reviewer-label-pickers branch October 18, 2026 18:26

This branch was successfully deployed

1 active deployment
Preview — 4466df26 Deployed Oct 18, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant