Skip to content

feat(web): beta Working sidebar section (upstream) - #991

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-10-03-working-shelf
Oct 3, 2026
Merged

rynfar merged 2 commits into
pylonfrom
upstream/2026-10-03-working-shelf

Conversation

@rynfar

@rynfar rynfar commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

Busy threads crowd the active list even when they don't need you. Upstream T3 added a beta Working section that hides them until they finish or need attention. The maintainer approved adopting it with Pylon adaptations.

What this does

A new Settings → General → Working section (beta) toggle. It is off by default and is a client setting. When it's on, threads that are working, delegating to background fleets, or monitoring move into a collapsible Working section at the bottom of the sidebar. A thread goes back to the top of the active list when it finishes, fails, hits a usage limit, has a plan ready, or needs an approval or input.

Source

Upstream Title Outcome
b33eda13998b5b0571daaf266c87f6f31af41f7d (#13926) feat(web): beta Working section hides busy threads until they need you Adopted with the Pylon changes below

Decision brief: issue #981, second comment, section b33eda1399. The brief was written against 00884406f7. Everything here was re-checked against orchestrator v2 at b4c210ea5d.

Pylon adaptations

  • Delegating included. In v2, background fleets (subagent tasks) and monitors arrive as pendingBackgroundTasks. The shell parks those threads at runtime idle, so the sidebar shows them as waiting. isSidebarThreadWorking folds working and waiting. It also accepts delegating/monitoring, so the section keeps working if those statuses come back. Pylon's status precedence, colors, static activity visuals and progress counts are unchanged.
  • Unread replies stay in the inbox. A run that finishes with a monitor or background agent still open parks at waiting. The thread now stays in the active list until its reply is visited, judged by the same visited watermark as the row's Done indicator. A never-visited thread counts as read, as it does elsewhere.
  • Precedence is explicit. resolveSidebarThreadSection takes an optional working flag, checked in the order snoozed, settled, pinned, working, active. Only inbox threads fold.
  • Return clock is a pure function. observeSidebarInboxReturns is a pure function in Sidebar.logic.ts, with a thin module-scope holder in Sidebar.tsx. It works like this:
    • Keys are environment-scoped, so threads with the same id on local, remote and tunnel environments never share a stamp.
    • It watches the whole roster, not the project-scoped list, so changing project scope keeps every stamp.
    • The first observation only records a baseline and stamps nothing.
    • Threads that leave the roster (deleted, or their environment disconnected) drop out. After a reconnect they are ordered by server timestamps only.
    • Stamps clear when a thread folds back into Working.
    • Stamps are device-local and in memory: they reset on reload and don't sync between devices.
    • Stamps use the device clock and are compared with server timestamps, so clock skew on a remote or tunnel server can shift a row's position. Sections are unaffected.
    • Updating module state inside the memo is idempotent: a repeated run with the same input stamps nothing.
  • Order restores. sortSidebarInboxThreads uses newest-return-first while the beta is on and activeOrderKey while it's off. Drops into a time-ordered inbox only change lifecycle (order: null, no key writes). That means turning the beta off brings back the saved manual order.
  • Drag. Working rows can't be dragged and can't receive drops. The drag preview places a row by return time. This works in the compact (icon) sidebar as well; the Working header shows a CircleDashed icon there.
  • Presentation only. No changes to ThreadSettlementPolicy, lifecycle rules, ThreadNotificationCoordinator, contracts wire events, projections or migrations.
  • Already present from the v2 adoption (4843d5a): isSidebarThreadWorking, sortInboxThreadsByReturn, their tests, the settings-search entry and a docs paragraph. That docs paragraph described a setting that didn't exist and was missing a blank line. It is now rewritten. This PR adds the setting, the wiring, drag/section handling, settings reset and the desktop fixture.
  • Not supported: mobile (unchanged) and the legacy sidebar. Both are recorded in the user docs. The toggle is disabled while the legacy sidebar is on, and its description says why.

Verification

  • vp test run src/components/Sidebar.logic.test.ts src/components/Sidebar.drag.test.ts src/components/settings/settingsSearch.test.ts src/components/settings/SettingsPanels.restore.test.tsx src/components/settings/settingsLayout.test.tsx (apps/web): 5 files, 330 tests passed. New tests cover:
    • working → approval / input / plan / failure / usage limit / completion
    • waiting with background work plus an unread reply stays in the inbox, and folds once visited
    • delegated fleet and monitor termination
    • pinned, snoozed and settled precedence
    • visibility of the open thread in a collapsed shelf
    • enable → disable order restoration
    • reconnect snapshots
    • duplicate thread ids across environments
    • Working rows not draggable or droppable, and the time-ordered drag preview
  • vp test run src/settings.test.ts (packages/contracts): 174 passed, including the new default-off and patchable test.
  • vp test run src/settings/DesktopClientSettings.test.ts (apps/desktop): 13 passed.
  • vp run -F @t3tools/web typecheck, vp run -F @t3tools/contracts typecheck, vp run -F @t3tools/desktop typecheck: all ran tsc --noEmit, exit 0.
  • vp lint on the changed TS files: 0 errors. The warnings are existing kinds, and the count matches the baseline. vp fmt --check on the changed files: clean.

Review fixes are in a1bcda205b: unread replies, the legacy-sidebar toggle, the clock-skew doc note and the memo comment.

Not verified

  • No UI run. Browser/computer use wasn't authorized, so there are no before/after screenshots. Header placement (mt-auto handoff between the Working, Snoozed and Settled headers), the compact-sidebar header icon and drag feel all need a manual web/Electron check.
  • If you unpin a pinned working thread by dragging it into the active list, the preview shows it landing in the inbox, but it then shows up in Working. Same as upstream.

Part of upstream cycle #981.

🤖 Generated with Claude Code

Port upstream b33eda1399 (#13926) for Pylon: a default-off
sidebarWorkingShelfEnabled setting folds working, delegating (background
fleets) and monitoring threads into a collapsible Working section on web
and desktop. Approvals, input requests, plan prompts, failures, usage
limits and unread completions stay in the inbox; pinned, snoozed and
settled precedence is preserved; the open thread stays visible and
search includes hidden rows.

While enabled the inbox orders newest return first and drops only change
lifecycle, so the saved manual order returns when the beta is off.
Return stamps are device-local, in memory and keyed by environment.
Presentation only: settlement, lifecycle and notifications are unchanged.
Mobile is unchanged.

Source: b33eda13998b5b0571daaf266c87f6f31af41f7d

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L labels Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 4.9 KiB 4.9 KiB +40 B (+0.8%) 6.8 KiB ✅
Codex Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.1 KiB 1.2 KiB +40 B (+3.4%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 20.4 KiB 20.4 KiB +41 B (+0.2%) 29.3 KiB ✅
Codex Live turn messages 1 2 +1 (+100.0%) 8 ✅
Claude Total thread wire 4.9 KiB 4.9 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.7 KiB 3.7 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 20.7 KiB 20.7 KiB 0 B (0.0%) 29.3 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Baseline: b4c210e · PR result: a1bcda2 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 106.1 KiB
  • Claude decoded thread snapshot: 106.4 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

A run that finishes with a monitor or background agent still open parks
at "waiting", so its unread reply folded into Working. Unseen completions
now stay in the inbox until visited, using each row's visited watermark.
Disable the beta toggle under the legacy sidebar, note device-clock skew
in return ordering, and explain why the memo-scoped observation is safe.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 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.

1 participant