Skip to content

Sidebar v2 beta: flat thread list with a server-backed settled lifecycle - #4026

Merged
t3dotgg merged 46 commits into
mainfrom
t3code/new-sidebar-client-only
Jul 22, 2026
Merged

Sidebar v2 beta: flat thread list with a server-backed settled lifecycle#4026
t3dotgg merged 46 commits into
mainfrom
t3code/new-sidebar-client-only

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Jul 16, 2026

Copy link
Copy Markdown
Member

What

Opt-in Sidebar v2 (web) and Thread List v2 (mobile): one flat thread list ordered by creation time, replacing the project-grouped sidebar. Active threads render as status cards; finished work "settles" into a slim, paged tail at the bottom. Threads settle manually (hover ✓ / context menu / swipe), or automatically when their PR merges/closes or after N days of inactivity — and un-settle automatically on real activity (a user message, a session coming alive, a new approval/user-input request).

Settled is a first-class server-side lifecycle (this PR absorbed #4243): thread.settle / thread.unsettle commands, thread.settled / thread.unsettled events, and settled_override + settled_at columns on projection_threads (migration 033). Settled ≠ archived — settled threads stay in the live shell stream, so their history stays readable without un-settling, and archive keeps its original "hidden from lists" meaning.

BEFORE:
image

AFTER:
image

MOBILE:
IMG_2680

Safety / gating

  • All v2 UI is behind beta flags, default off: sidebarV2Enabled (web, Settings → Beta) and threadListV2Enabled (mobile device preference). Flags off, v1 renders unchanged.
  • Migration 033 is additive and idempotent (two nullable columns, PRAGMA-guarded); no backfill, no data rewritten. Threads archived before this lands stay archived.
  • Version skew is negotiated: servers advertise a threadSettlement capability. Clients never send the new commands to a pre-settlement server (absent capability = unsupported), and threads on such environments never classify as settled — no stranded tails with dead affordances.
  • The settle target is guarded three ways against hiding live work: client canSettle (running/starting sessions, pending approvals/user input, queued turn starts), the same blockers in effectiveSettled (auto-settle can't misclassify either), and a server-side decider invariant for raced or stale clients.

What was touched / review focus

Server (apps/server):

  • orchestration/decider.ts — settle/unsettle command handling, the live-session + queued-turn invariants, and the three activity-un-settle injection points (message send, session set, activity append). Real activity clears ANY override: settled threads wake, keep-active pins reset to neutral. Re-emissions are projected no-ops (idempotency without updatedAt churn). Best place to start.
  • orchestration/projector.ts + Layers/ProjectionPipeline.ts — event application: reason: "user" → the keep-active pin, reason: "activity" → neutral.
  • persistence/Migrations/033_ProjectionThreadsSettled.ts + row plumbing.

Shared:

  • packages/client-runtime/src/state/threadSettled.tseffectiveSettled / canSettle / hasQueuedTurnStart, heavily tested (172 tests incl. a truth table over all override states).
  • packages/contracts — commands/events (client-dispatchable unsettle reason is "user" only; "activity" is server-owned), threadSettlement capability, two client settings.

Web (apps/web):

  • components/SidebarV2.tsx — the new sidebar. Review focus: post-settle navigation (next card / project draft, validated against the current route), per-thread in-flight guards, capability-aware partition, bulk actions over exactly the rendered selection.
  • hooks/useThreadActions.ts — settle/unsettle dispatch + typed errors.
  • Shared chrome extracted to sidebar/SidebarChrome.tsx (v1 and v2 render identical header/footer); new /settings/beta page; minor chat-header/composer tweaks.

Mobile (apps/mobile): features/threads/threadListV2.ts + thread-list-v2-items.tsx + HomeScreen.tsx — the same model with native list anatomy (swipe actions, long-press menus, settled tail paging, ticking auto-settle clock).

Known follow-ups (beta-period, not blockers)

Mobile split-view v2 wiring, mobile PR auto-settle without virtualized row mounts, a11y polish (composite row labels, ARIA patterns), v2 search parity with project titles, and the auto-settle policy knob on mobile.

🤖 Generated with Claude Code

Note

Add flat thread list Sidebar v2 with server-backed thread settle/unsettle lifecycle

  • Introduces a new SidebarV2 on web and a thread list v2 on mobile, both rendering threads sorted by creation time with active threads as cards and settled threads as a paginated tail; enabled via a new Beta settings page (/settings/beta) guarded by a sidebarV2Enabled client setting.
  • Adds thread.settle and thread.unsettle commands and thread.settled/thread.unsettled events to the contracts, with full decider enforcement (no live session, no open blocking requests, no queued turn start within a grace window) and idempotent re-emit on already-settled threads.
  • Propagates settlement state (settledOverride, settledAt) through the server projection pipeline, persistence layer (migration 033 adds settled_override/settled_at columns to projection_threads), in-memory projector, client-runtime reducers, and shell/detail merge.
  • Exposes settleThread/unsettleThread in useThreadActions (web) and useThreadListActions (mobile), gated by a new threadSettlement environment capability flag; mobile also adds swipe-to-settle gesture support.
  • Auto-unsettle fires when a user message is sent, a session starts/runs, or an approval/user-input request is appended, emitting thread.unsettled with reason activity before the triggering event.
  • Risk: the migration is additive (nullable columns), but servers without migration 033 will not expose the threadSettlement capability, so clients silently suppress settle/unsettle actions on those environments.

Macroscope summarized cb57915.


Note

Medium Risk
Touches orchestration command invariants and projection schema with new user-visible lifecycle behavior, but it is gated behind beta flags default-off and capability checks with extensive test coverage.

Overview
Introduces thread settlement as a server lifecycle distinct from archive: thread.settle / thread.unsettle commands, matching events, and nullable settled_override / settled_at on projection_threads (migration 033). Settled threads remain in the live shell stream; the decider blocks settling during active sessions, open approval/user-input requests, and queued turn starts, and prepends thread.unsettled on real activity (messages, live session updates, blocking activities). Servers advertise threadSettlement so older environments never get settle commands or settled classification.

Web adds beta Sidebar v2 (sidebarV2Enabled, Settings → Beta): creation-order flat list, active cards vs paged settled slim rows, auto-settle via inactivity days and merged/closed PR signals, with shared chrome extracted from v1. Mobile mirrors the model behind threadListV2Enabled in device preferences—FlatList v2 path, horizontal project scope chips, settle/unsettle in useThreadListActions, and swipe full-swipe commits the primary lifecycle action (settle/un-settle) instead of delete.

Shared effectiveSettled / canSettle in client-runtime drive partitioning; thread shells and tests across apps pick up settledOverride / settledAt fields.

Reviewed by Cursor Bugbot for commit cb57915. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features
    • Added Thread List v2 for mobile and web, with project scoping, search, status indicators, settled-thread history, and paging.
    • Added settle/unsettle thread actions, including swipe, menu, and bulk actions where supported.
    • Added beta settings for Sidebar v2 and automatic settling of inactive threads.
    • Added project icons and improved new-thread project selection.
  • Bug Fixes
    • Prevented unrelated branch or worktree context from carrying into threads created in another project.
  • Style
    • Refined sidebar surfaces, animations, stage backdrops, and composer focus states.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚀 Mobile Continuous Deployment Trigger Expo preview build size:XXL 1,000+ changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants