Skip to content

Replace landing provider tree with nested thread sidebar - #304

Merged
SawyerHood merged 1 commit into
mainfrom
bb/landing-page-graphic-ideas-thr_tusdnxyxht
Jun 22, 2026
Merged

SawyerHood merged 1 commit into
mainfrom
bb/landing-page-graphic-ideas-thr_tusdnxyxht

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

What

Replaces the static org-chart graphic in the landing page's "The gang's all here" band with a bb-style nested thread sidebar.

  • Parent Claude Code · Ship the release thread with three worker threads — Codex, Cursor, Pi — nested beneath it on a connector rail.
  • Each worker's status flips ● running → ✓ done while the parent shows ● managing, then ships once they land. Reuses the run-receipt pill + reveal timing from AutomationRun; the list replays each cycle.
  • Adds Cursor, which the band copy names but the old graphic omitted.
  • Hides the now-redundant provider chip row under the copy on narrow screens (the stacked sidebar already shows every provider logo).
  • Honors prefers-reduced-motion: the sidebar rests in a static "all done" state.

Why

The org chart was the only static, diagram-style visual on the page — its neighbors (AgentChat, AutomationRun) are animated product mocks. The sidebar looks like the real product, literally shows "spawn and manage another, each in its own thread," and fits all four providers.

Tests

  • turbo run typecheck --filter=@bb/landing ✓
  • turbo run lint --filter=@bb/landing ✓
  • Manual: verified running, settled (done), and mobile-width states in the browser; confirmed the band chip row is display: none at mobile width while the hero "Works with" chips are unaffected.

Risks

Low — scoped to the landing app; no shared primitives or runtime code touched.

🤖 Generated with Claude Code

Swaps the static org-chart in the "The gang's all here" band for a bb-style
sidebar mock: a parent Claude thread with worker threads (Codex, Cursor, Pi)
nested beneath it on a connector rail. Each worker's status flips running →
done while the parent manages, mirroring the run-receipt pill and reveal
timing. Adds Cursor (named in the copy but absent from the old graphic), and
hides the now-redundant provider chip row in this band on narrow screens.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@SawyerHood
SawyerHood merged commit f211a27 into main Jun 22, 2026
6 checks passed
@SawyerHood
SawyerHood deleted the bb/landing-page-graphic-ideas-thr_tusdnxyxht branch June 22, 2026 21:05
ymichael added a commit that referenced this pull request Oct 22, 2026
## Human comments

## What was wrong

GitHub pull request status was core. The daemon ran `gh`, the server
assembled and watched the status, and the app, SDK, CLI and Tasks and
GitHub plugins each reached it through core routes and commands. Core's
PR UI couldn't leave core because there was nothing outside core to read
from.

## What changed

**New bundled, default-enabled plugin: `plugins/github-pr-status`
(`bb--github-pr-status`)**
- `host.ts` / `host/git-host.ts`: the in-worktree lookup moved from
`packages/host-workspace/src/git-host.ts`. It covers the current branch,
upstream and fork remotes (`getPullRequestTarget`), the merge-queue
GraphQL query, and `gh pr ready|ready --undo|merge`. It runs on the
environment's own machine with the daemon's shell `PATH`.
- `server.ts`:
  - resolves the environment;
- serves a keyed `pullRequests` read, one row per environment id (up to
200), so a list of rows loads in one request;
- serves `markReady`, `markDraft` and `merge`, each of which re-checks
state before acting;
  - registers `bb pull-request show|ready|draft|merge <environment-id>`.
- `store.ts` is the single place reads are cached (10 s), re-checked
while watched, and published when they change.
- PR snapshots are kept by PR URL, so environments sharing a PR share
one snapshot. Persistence, cross-row reuse and webhooks can feed this
one place later.
- While a row is watched (`bb.rpc.experimental_whileWatched`), it
re-checks every 30 s when checks are pending, auto-merge is on, the PR
is queued or mergeability is unknown. That is the same rule as core's
`pull-request-watch.ts`.
  - Other triggers match main's:
    - `status-changed` and environment create/delete fetch fresh;
    - a completed turn re-checks through the 10-second cache;
    - `git-refs-changed` only marks the cached row stale;
- `metadata-changed` re-checks only when the environment's branch
actually changed (one environment read, no `gh`);
- in the app, a cached row is re-fetched on mount, and again when the
page is shown if it's older than 30 s (1 h once merged or closed). Main
got this from TanStack's `refetchOnMount: "always"` and focus refetch.
Here it uses only the public read hook's `refetch`, in
`pull-request-queries.ts`.
- It invalidates the row's tag only when the row changed, and never for
a result a viewer is already receiving.
- `contract.ts` is the public contract. The read returns the fully
assembled shape the UI renders: state, attention, checks, review,
mergeability, auto-merge and merge queue.

**Watched reads**
- `bb.rpc.experimental_whileWatched` comes from `bb/5939-recut`,
mechanism only: the `plugin-read` subscription target, the server
registry and producer lifecycle, app query hooks holding the
subscription, per-target subscribe validation, and fake-host support.
- Left out: the SDK `experimental_watchRpc` /
`experimental_watchDiscovery`, the CLI `--watch` flags, and
plugin-signal scoping.

**Core reads and acts only through the plugin's public contract**
- The composer banner segment, Info row and thread view use
`experimental_useRpcKeyedQuery` / `experimental_useRpcMutation` with
`pluginId: "bb--github-pr-status"`
(`apps/app/src/hooks/queries/pull-request-queries.ts`). These are the
same calls another plugin makes, so moving the UI later is a cut and
paste.
- The app's RPC hook host now allows those hooks outside a plugin slot
when `pluginId` is explicit.
- `bb thread show`, Tasks (`listTaskPullRequests`, now one batched read)
and the GitHub plugin's `pullForThread` call the same RPC.

**Deleted from core**
- The server PR watcher, route, cache, `environment-pull-request` tag
and subscription target, and the PR action branches.
- The SDK `environments.pullRequest` / `markPullRequestReady` /
`markPullRequestDraft` / `mergePullRequest`, and `bb environment
pull-request …`.
- The `ThreadPullRequest` / `GitHostPullRequest` domain schemas.
- The daemon's `workspace.pull_request` and
`workspace.pull_request_action`. **`HOST_DAEMON_PROTOCOL_VERSION` 250 →
251**, compatible `[250, 251]`. 250 stays compatible because the server
no longer sends either command. 246–249 stay removed, as #6018 intended.

**`experimental_useSidebarThreadPullRequest`**
- Removed from `@get-bb/plugin-sdk/app`, the Plugin Guide and the docs.
- Published bundles keep working: the app installs
`retiredPluginSdkAppMembers` on the plugin runtime, backed by the
plugin's read. It returns `{ isLoading: false, pullRequest: null }` when
the plugin is disabled.
- **Builds never fail on it.** bb builds git-sourced marketplace plugins
at install and update, and rebuilds path and builtin plugins when the
SDK changes. So the `bb-plugin-build` runtime shim keeps the name in its
`@get-bb/plugin-sdk/app` export list. Importing it is a build warning
with the replacement call, which `bb plugin build`/`dev` print and the
server writes to the plugin's log.
- Migration guide:
`bb-plugin-authoring/references/frontend-pull-requests.md`. The runtime
shim is recorded in `docs/api_to_audit.md`.
- Plugin SDK 0.6.72.

**No wake.** Plugin host calls never wake a suspended host. A read on an
asleep or offline machine returns `unavailable`, which the UI renders as
no PR. Ready, Draft and Merge fail with "<machine> isn't available …".
**Behaviour change:** reads no longer wake a suspended host. On main,
`workspace.pull_request` used the `work` wake policy, so opening a
thread whose machine was suspended woke it.

## How you verified

**Request measurement in the real app.** Main and this branch ran as two
`pnpm start:worktree` instances side by side. Each had a thread on a
project checkout of PR #6117's branch while its checks were pending
(`checks_pending`, 0 failed). In each, a headless page opened the thread
and every `/api` request was recorded for 3 minutes, both runs at the
same time:

| | PR requests | when (s) | all `/api` requests |
|---|---|---|---|
| main | 6 × `GET /environments/:id/pull-request` | 1, 32, 64, 95, 127,
158 | 84 |
| branch | 6 × `POST /plugins/bb--github-pr-status/rpc/pullRequests` |
1, 33, 64, 96, 127, 159 | 88 |

The other `/api` differences changed from run to run (hosts, server-move
and execution-options in this run; system config, providers and timeline
in another). They come from background activity in the freshly restarted
branch instance and its extra sidebar threads, not PR traffic. An
earlier run found two bugs that are fixed here with tests:
- a re-check right after open published a result the opening read was
already fetching, costing one extra request;
- a watch that went idle when checks finished never resumed when a new
CI run started.

**Busy thread.** Main and this branch ran side by side again, each with
a thread on its own scratch PR in a private test repo
(`ymichael/test-project` #303 and #304, both closed and their branches
deleted afterwards). Each thread was open in a page. Both received the
same agent turn at the same moment: three commits, a `git fetch`, a
third commit between them, and a `git push`, which also started the
repo's CI. Over 5 minutes, a process monitor counted every `gh` started
by each instance, attributed by process ancestry and confirmed by
working directory. The page counted PR read requests. Two runs gave
identical counts:

| | `gh` calls | PR read requests |
|---|---|---|
| main | 7 (4 `pr view`, 3 merge-queue `api graphql`) | 4 |
| branch | 5 (3 `pr view`, 2 merge-queue `api graphql`) | 2 |

Before this fix the branch also re-checked with `gh` on every
`git-refs-changed` and `metadata-changed`, so a thread that commits and
pushes would have exceeded main.

**Focus refresh.** Main (`f909788625`) and this branch ran side by side
with the same open PR. A page on each hid and showed itself 5 times over
4 minutes, with gaps from 20 s to 60 s, so some shows were under the 30
s stale time and some over. A process monitor counted `gh` per instance:

| | `gh` calls | PR read requests |
|---|---|---|
| main | 5 | 5 |
| branch | 5 | 6 |

The extra read is the realtime connection resuming at the same moment
the page showed. Both reads hit the plugin's 10 s cache, so there's no
extra `gh`.

**Published plugins that use the retired hook.** On the review app, I
installed four git-sourced Community marketplace plugins that call
`experimental_useSidebarThreadPullRequest`. Each went through `bb plugin
install <plugin>@bb-community`, so bb cloned and built it at its
published commit. Each was then used as the sidebar thread list:

| Plugin | Commit | Builds | Warning in `plugin.log` | Renders PR badges
|
|---|---|---|---|---|
| t3sidebar | `8b535729dd` | ✅ | ✅ `src/ThreadCard.tsx:6` | ✅ |
| dockside | `e8736f3858` | ✅ | ✅ `components/inbox/thread-card.tsx:7` |
✅ |
| radar-sidebar | `9a20bfab7e` | ✅ | ✅
`components/radar/RadarThreadRow.tsx:23` | ✅ |
| thread-inbox | `c0981fb6fe` | ✅ | ✅ `src/ThreadCard.tsx:18` | ✅ |

gtd-sidebar fails to install on main too ("Could not resolve
@get-bb/plugin-sdk"), so it's unrelated. This test caught a real bug: T3
Sidebar crashed with a React hook-order error. React Compiler only
treats `use…` names as hooks, so it cached the
`experimental_useRpcKeyedQuery` call inside `useEnvironmentPullRequest`
and skipped it on re-renders with unchanged arguments. Core's own
callers pass a fresh options object on every render, which hid it. The
hooks are now imported under `use`-prefixed local names, and all four
plugins render.

**UI parity.** Screenshots of the same thread on main and on the branch
show the same composer banner segment (PR #6117 with the Merge split
button) and the same Info row (#6117, Open, Checks running). `bb thread
show` printed the PR through the plugin. On this PR, `bb pull-request
draft <env>` converted it to draft. The banner then showed "PR #6125 ·
Draft" with Mark ready, and clicking Mark ready showed the loading
toast, made the PR ready on GitHub, and returned the banner to the open
state with Merge.

**Tests**
- New plugin tests (75):
- host-entry fork, upstream and detached cases using a fake `gh`, moved
from host-workspace;
  - the parse, action-argument and merge-queue table;
  - the assembly table, moved from the server;
  - store polling, publish-on-change and the viewer race;
  - server reads, refusals, the no-wake refusal and the CLI.
- Also added: the `bb-plugin-build` retired-import warning test, the
focus-refresh staleness table and refetch tests, Tasks batched reads and
the disabled-plugin case, CLI `thread show` through RPC, and a hub test
for the `plugin-read` target.
- After merging #6135: `pnpm exec turbo run typecheck lint
--filter='...[origin/main]'` passes 162/162, and `turbo run test
--filter='...[origin/main]'` passes 115/115. That includes #6135's
host-workspace default-branch tests and the host-daemon
`watch-manager-startup` setup-window test. The host-workspace merge kept
#6135's code. This branch only removes the PR lookup from it.

**Not covered**
- `gh` ran only on a local host. Remote hosts use the same plugin
host-artifact path as the other host plugins but weren't exercised.
- Merge wasn't run against a real PR. It uses the same `gh pr merge
--<method>` arguments, covered by the host tests.

> AGENT GENERATED

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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