feat(rail): labeled sections + starred workspaces in the workspace rail#116
Merged
Conversation
The rail previously merged three invisible sort keys (attention, then scheduled, then recency) into one flat list — scheduled workspaces always floated to the top with nothing explaining why, and long lists were hard to scan. Redesign it around explicit, labeled sections (Claude-style): 1. Needs attention — pending approvals, failed or blocked tasks 2. Starred — user-pinned workspaces (new) 3. Recent — everything else, most-recently-updated first Scheduled workspaces no longer jump the queue: their cadence renders as a per-row label (an attribute, not a position). Headers only appear when grouping is in effect; a bare recency list stays headerless, and the collapsed rail separates sections with thin dividers instead. Starring: hover star toggle + overflow-menu item per row, persisted as WorkspaceConfig.starred_at (timestamp, 0 = unstarred) via the new workspace_set_starred command. Starring deliberately does not bump updated_at, so it never reorders the recency sort. Forks start unstarred. The flag is mirrored onto WorkspaceLocator so workspace_list derives it without re-reading configs.
juacker
marked this pull request as ready for review
July 23, 2026 08:14
juacker
added a commit
that referenced
this pull request
Jul 23, 2026
…concurrent config writes (#118) persist_decisions_to_agent wrote the workspace config via a bare load->mutate->save, bypassing the process-wide writer lock in workspace_config::update(). A permission decision racing another config write (starring a workspace, re-anchoring a schedule) could silently discard that write and refresh the workspace index from the stale snapshot — the same lost-update class already fixed for mark_opened in commands/workspace.rs. - Run the read-modify-write inside workspace_config::update() and refresh the index from the config returned under the lock. - Fast path: skip the lock + disk round-trip entirely when decisions contain nothing durable (Once-only, or Always with blank prefixes). - Extract the list surgery into apply_decisions_to_shell_policy(), a pure function over WorkspaceAgent, and unit-test it: allow/deny list moves, idempotency (no change reported on re-apply, no duplicates), trimming, and no-op decisions. Found by Codex during the PR #116 review.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Redesigns the left workspace rail around explicit, labeled sections (Claude Desktop-style) and adds a star workspace feature.
Problem
The rail merged three invisible sort keys — attention → scheduled → recency — into one flat, unlabeled list. Scheduled workspaces always floated to the top with nothing explaining why, and long lists were hard to scan (juacker feedback, 2026-07-23).
Design (mirrors claude.ai's Starred / Recents sidebar)
every 5m/ cron) stays as a per-row label — an attribute, not a position.:focus-within).Implementation
WorkspaceConfig.starred_at: i64(#[serde(default)], 0 = unstarred; timestamp for future "recently starred" sorts), mirrored onWorkspaceLocator, exposed asstarred: boolonWorkspaceListEntry.workspace_set_starredcommand via the atomicupdate_workspace_config_for_idhelper. Deliberately does not bumpupdated_at, so starring never reorders the recency sort. Forks start unstarred.setWorkspaceStarredclient fn, optimistic toggle with revert inFleetLayout, section partition + headers inWorkspaceRail.Tests
starred_atlegacy-config default + atomic-update roundtrip (cargo test --lib: 803 pass).WorkspaceRail.test.tsxcases — headerless plain list, scheduled no longer floats, section ordering, attention-outranks-star, hover + menu star toggles, cross-section filter, collapsed headers, lone-Starred header (vitest: 179 pass).Review
3 independent reviews (Codex, Minimax, Claude): all
production_quality, zero blocker/major. Applied minors::focus-withinkeyboard access, lone-Starred-header test. Accepted (documented) minors: optimistic-toggle vs 5s-poll flicker (pre-existing pattern shared with pause toggle); rapid-toggle last-write-converges. Pre-existing (out of scope, logged in TODO): bare load→save writers inpermissions.rscan clobber concurrent config writes; empty-workspaceId fallback inresolve_workspace_id.