Skip to content

Show a Solo chat's pull request state in the sidebar - #1328

Merged
baxen merged 1 commit into
mbot/github-cli-panelfrom
mbot/solo-pr-link
Oct 19, 2026
Merged

baxen merged 1 commit into
mbot/github-cli-panelfrom
mbot/solo-pr-link

Conversation

@baxen

@baxen baxen commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #1325.

A Solo chat can be linked to one pull request. While it is linked, the chat's row in the sidebar shows the pull request's state in place of the chat bubble: draft, open, checks failing or running, merged, or closed. That makes "is this chat's work merged yet" visible without opening anything.

Solo sidebar rows showing real pull request states

The rows above use real states for #1325 and #1322 (draft), #1326 (open), #1299 (open, checks failing), and #1316 and #1319 (merged), read through gh. The last row has no link and keeps the bubble. The screenshot comes from a local harness that renders the real SoloPullIcon and store inside sidebar rows, with the relay read faked. It is not the full app.

How it works

  • Linking. The GitHub panel shows Link to this chat / Unlink under the checklist when it was opened from your own Solo chat. Agents get a link_pr tool ({url} or {unlink: true}) that works only in the Solo chat they are running in.
  • Storage. The link is a NIP-AR artifact (kind 45010) in the chat, with type buzz.solo.pr, d = uuidv5(channel, type), and content {version: 1, url}. Unlinking writes url: null as an update, because an artifact delete cannot carry content. Every device and agent in the chat sees the same link. It is always signed by the chat's owner, including when an agent calls link_pr. It is written through configArtifactWriter, so linking needs the desktop app. Reading works everywhere.
  • State.
    • One relay read covers the current heads of every shown chat (#h over the visible chats).
    • One gh api graphql query covers every linked pull request, with aliased fields for state, isDraft, mergeStateStatus and the head commit's statusCheckRollup.
    • Both repeat every 60s while the window is visible, and stop when no rows are shown.
    • If one pull request can't be read, the store reads each one alone so the rest still show.
    • Without gh, it falls back to public REST every 5 minutes and shows only open, draft, merged or closed.
  • Sidebar seam.
    • The conversation service gets registerChatIcon(component). The first registered icon renders for each Solo row, as <Icon session channelId fallback/>.
    • SoloInventory passes the existing bubble as fallback, so with no plugin, or no link, nothing changes.
    • The icon includes screen-reader text, e.g. "Pull request, open, checks failing:".

Needs approval: FOUNDATION edits

  • src/features/conversation/service.tsx: new chatIcons reader + registerChatIcon, modelled on registerTabs.
  • src/app/App.tsx: one prop, chatIcons={services.conversation.chatIcons}, passed to PrimarySidebar.

Testing

  • solo-pull.test.ts covers:

    • reading a link
    • create / update / unlink artifact tags, including no write when nothing changed
    • batched link and state reads, plus the 60s refresh, which stops when unwatched
    • per-PR fallback and the public fallback
    • local link before the next read
  • SoloPull.test.tsx covers:

    • icon states and spoken text
    • linking and unlinking from the panel, which only appears in a Solo chat
    • link_pr through apply, including its refusals
  • SoloInventory.test.tsx: a registered chat icon replaces the bubble once it registers.

  • Full vitest run passes (661 files). tsc, biome, the design checks and pre-push hooks also pass.

  • No browser spec. The browser fixture relay has no NIP-AR artifact support, and the web transport has no artifact writer.

  • Not yet verified:

    • a live write and read against the real relay
    • a native run

    I checked relay acceptance against buzz-core/src/artifact.rs and the artifact handler on block/buzz main: any namespaced type is accepted from any channel writer, and prev is required for updates.

Try natively: open a PR from a Solo chat, then Link to this chat. The row icon should switch within a few seconds. Merge it from the panel, and the row should turn into the purple merge icon on the next refresh, within a minute. Needs a native rebuild, because #1325 changed the plugin manifest.

🤖 Generated with Claude Code

A Solo chat can be linked to one pull request, from the GitHub panel or
by an agent with the link_pr tool. The link is a NIP-AR artifact in the
chat (type buzz.solo.pr), signed by the owner, so every device sees it.
The sidebar reads all shown chats' links and their pull requests'
state in one relay read and one gh GraphQL query each minute while the
window is visible, and shows draft, open, checks failing, merged or
closed instead of the chat bubble.

Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Bradley Axen <baxen@squareup.com>
@baxen
baxen merged commit c694d7f into mbot/github-cli-panel Oct 19, 2026
32 checks passed
@baxen
baxen deleted the mbot/solo-pr-link branch October 19, 2026 22:28
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