🤖 feat: pin chats to the top of the sidebar#3683
Conversation
Adds pinnedAt to workspace config/metadata schemas, a setPinned ORPC mutation with monotonic server timestamps, pin-aware sidebar sorting and age bucketing, and UI affordances (menu toggle, row icon, Ctrl/Cmd+Alt+P keybind, palette action). Archiving clears the pin; sub-agents and archived chats are not pinnable. --- _Generated with `mux` • Model: `anthropic:claude-fable-5` • Thinking: `off` • Cost: $ <!-- mux-attribution: model=anthropic:claude-fable-5 thinking=off costs=63.56 -->
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2e716de47f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0f2d9cd797
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…Context - setWorkspacePinned applies an optimistic pinnedAt locally (mirroring the server's append-only monotonic ordering) so the sidebar reorders on click; the metadata subscription reconciles, and failures revert. - AgentListItem row menu now uses the context wrapper instead of calling api.workspace.setPinned directly, fixing delayed reorder and the mock-client crash Codex flagged (optional hook keeps provider-less stories working).
|
@codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Extract parseTimestampMs helper for the repeated Date.parse(x ?? '') / Number.isFinite fallback pattern used as sort keys in buildSortedWorkspacesByProject. The pinnedAt keys (added by #3683) and the pre-existing createdAt keys now share one helper. Behavior-preserving.
Extract parseTimestampMs helper for the repeated Date.parse(x ?? '') / Number.isFinite fallback pattern used as sort keys in buildSortedWorkspacesByProject. The pinnedAt keys (added by #3683) and the pre-existing createdAt keys now share one helper. Behavior-preserving.
Summary
Adds chat pinning: workspaces can be pinned to the top of the project sidebar in a stable, user-controlled order that is immune to recency reshuffling.
Background
Sidebar ordering is recency-based, so long-running or reference chats constantly drift down as other workspaces see activity. Pinning gives important chats a fixed spot at the top of their project.
Implementation
pinnedAttimestamp onWorkspaceConfigSchema/WorkspaceMetadataSchema; sharedisWorkspacePinned/isWorkspacePinnablehelpers (src/common/utils/pin.ts). Only root chats can be pinned; sub-agents and archived workspaces cannot.WorkspaceService.setPinnedwith a server-generated monotonic timestamp (max(now, maxPinInProject + 1ms)) so pin order is append-only and stable even with client clock skew; exposed viaworkspace.setPinnedORPC route. Archiving clearspinnedAt; unarchive does not restore it.pinnedAtascending (id tie-break) inbuildSortedWorkspacesByProject;partitionWorkspacesByAgetreats pinned roots (and their children via tier inheritance) as recent so pins never fall into the aged bucket.pinnedAton click (mirroring the server's append-only ordering) so rows reorder instantly; the metadata subscription reconciles and failures revert.Ctrl/Cmd+Alt+Pkeybind, and a Pin/Unpin Current Chat palette action.Validation
Full UAT against a
dev-server-sandboxinstance driven with agent-browser (16 scenarios): pin/unpin via row menu, menu bar, keybind, and palette; stable append-below-existing-pins order; new workspaces landing below pins; persistence across reload;pinnedAtcleared on archive and not restored on unarchive; two-client live sync (pin in client A instantly reorders client B); pin icon rendering at 375px mobile width with no overflow. Rapid-pinning four chats via the row menu reorders the sidebar immediately on each click (verified with no-wait DOM snapshots) and converges with the server's persisted order.Risks
Low. Sorting changes are scoped to
buildSortedWorkspacesByProject/partitionWorkspacesByAgeand covered by new unit tests (pin ordering vs recency, stale-pin child attachment, archived-pin ignore, age bucketing). Unpinned workspaces keep the existing recency order; workspaces withoutpinnedAtare unaffected.Generated with
mux• Model:anthropic:claude-fable-5• Thinking:max• Cost:$75.72