Repository navigation
Closed as not planned
Closed as not planned
Copy link
Description
Describe the feature
Problem
The sidebar currently fetches GitHub PR status one workspace at a time using individual gh pr view CLI calls. Each call spawns a child process, waits for the GitHub REST API round-trip, and parses the JSON response — all sequentially gated behind a hover interaction. This means:
- PR status is invisible until the user hovers over a workspace item.
- With 10+ workspaces, the N+1 pattern causes noticeable latency and unnecessary GitHub API usage.
- Each
gh pr viewcall is ~200-400ms, so 15 workspaces = 3-6 seconds of sequential shell spawns.
Solution
Replace the per-workspace gh pr view calls with a single batched GitHub GraphQL query that fetches PR status for all active workspaces at once, then distributes results into per-workspace React Query caches.
Architecture
Main process (Electron)
- New
batchFetchGitHubPRStatuses()function that:- Groups all active worktree workspaces by GitHub repository (via cached
RepoContext) - Builds a single GraphQL query with aliased
repositoryandpullRequestsfields - Executes via
gh api graphql(one shell spawn total, with 30s timeout) - Parses response with Zod
discriminatedUnionschemas, normalizes GraphQL shape → existingGHPRResponseformat - Populates the in-memory
githubStatusResourcecache and persists meaningful changes to SQLite
- Groups all active worktree workspaces by GitHub repository (via cached
- New
batchGetGitHubStatusestRPC procedure exposes this to the renderer
Renderer (React)
- New
useBatchGitHubStatus()hook called at theWorkspaceSidebarlevel- Polls
batchGetGitHubStatusesevery 15 seconds - Seeds empty per-workspace
getGitHubStatusReact Query cache slots viasetData - Never overwrites richer data from per-workspace fetches (which include
previewUrl, accuratebranchExistsOnRemote)
- Polls
- Removed
hasHoveredgate fromWorkspaceListItemandWorkspaceRow— PR status appears immediately - Aligned
workspace-list-itemstale time with batch polling interval (15s)
Key design decisions
- GraphQL over REST: One query fetches PRs for all repos/branches with status checks and review requests. Stays well within GitHub's 5,000 points/hour rate limit.
- Seed-only cache strategy: Batch results only fill empty cache slots. Per-workspace queries (triggered on hover/focus) return richer data — we never regress it.
- Discriminated unions: Zod schemas use
__typenameas the discriminator forCheckRun/StatusContextandUser/Teamunions — correct GraphQL pattern, better parse performance. - Branch deduplication: Multiple workspaces on the same branch within a repo share a single
pullRequestsfield in the query, with O(1) Map-based dedup. - Graceful degradation: If the batch query fails (auth, network, timeout), the sidebar falls back to the existing per-workspace fetching on hover — zero breakage.
Files changed
| File | Change |
|---|---|
batch-pr-status.ts |
New — Core batch logic: repo grouping, GraphQL query builder, response parsing, cache population |
useBatchGitHubStatus.ts |
New — React hook for sidebar-level batch polling with seed-only cache distribution |
types.ts |
Added GraphQL Zod schemas (GHGraphQLPRNodeSchema, etc.) and normalizeGraphQLPR() |
git-status.ts |
Added batchGetGitHubStatuses tRPC procedure |
index.ts (github) |
Re-exported batch function and type |
pr-resolution.ts |
Exported formatPRData and sortPRCandidates for reuse |
githubQueryPolicy.ts |
Exported BATCH_GITHUB_STATUS_REFETCH_INTERVAL_MS, aligned stale time |
githubQueryPolicy/index.ts |
Re-exported constant |
WorkspaceSidebar.tsx |
Integrated useBatchGitHubStatus hook |
WorkspaceListItem.tsx |
Removed hasHovered gate from isActive |
WorkspaceRow.tsx |
Removed hasHovered gate from isActive |
batch-pr-status.test.ts |
New — Tests for schema parsing, normalization, and GHPRResponseSchema compat |
githubQueryPolicy.test.ts |
Updated assertions for new stale time values |
Performance impact
| Metric | Before | After |
|---|---|---|
| Shell spawns per refresh | N (one per workspace) | 1 (single batch query) |
| Time to show PR status | Hover + 200-400ms per workspace | Immediate (pre-populated cache) |
| GitHub API calls/min | N × (60s / staleTime) | 4 (one batch every 15s) |
| User interaction required | Hover over each workspace | None — status visible on load |
Metadata
Metadata
Assignees
Labels
No labels
Activity
github-actions commentedon Mar 27, 2026
Triage Notes
This issue is a feature request, not a bug report — there is no broken behavior to reproduce with a test.
The current per-workspace PR status fetching logic works correctly via
gh pr view/gh pr listcalls inapps/desktop/src/lib/trpc/routers/workspaces/utils/github/. The proposed change is a performance optimization to replace N sequential shell spawns with a single batched GraphQL query.Current architecture (confirmed by code review):
fetchGitHubPRStatus()ingithub.tscallsgetPRForBranch()inpr-resolution.ts, which tries up to 3ghCLI strategies per workspaceWorkspaceListItemandWorkspaceRowuse ahasHoveredgate — PR status only loads on hover viagetGitHubStatusQueryPolicy()getGitHubStatusprocedure ingit-status.tshandles per-workspace fetching with local DB cachingThe issue provides a thorough implementation plan with file-by-file changes, cache strategy, and graceful degradation. No reproduction test is applicable here.
vaishcodescape commentedon Mar 27, 2026
@saddlepaddle Can you Take a Look at this ?
Kitenite commentedon May 6, 2026
Thanks for the detailed write-up — closing as a duplicate of #2845, which proposes the same GraphQL batch fetch. Consolidating discussion there.
vaishcodescape commentedon May 6, 2026
Hey @Kitenite Could you guide me where I could contribute more in the codebase ? it's a very interesting piece of software and I would love to contribute more !