cmux version
0.63.1
macOS version
macOS 26.4 (Tahoe)
Mac chip
Apple Silicon (M1/M2/M3/M4)
Installation method
Direct download (DMG)
Can you reproduce this on cmux NIGHTLY?
I could not test NIGHTLY
Bug description
cmux consumes 65–101% CPU continuously when the sidebar is visible in a session with many workspaces and panes. Hiding the sidebar immediately drops CPU to 4–12%. The high CPU usage causes the machine to heat up significantly and WindowServer also stays elevated at 40–60%.
The issue appears to be caused by sidebar row recomputation: every metadata/status/branch/PR/directory update triggers a full recomputation of all workspace rows, including expensive panel ordering and branch-directory aggregation, even when the update only affects a narrow section of the sidebar.
Expected behavior
With the sidebar visible, cmux CPU usage should remain low during normal operation. Metadata and status updates from shell integration should not cause continuous high CPU.
Steps to reproduce
- Open cmux with a session containing many workspaces and panes (my session: 1 window, 10 workspaces, 35 panes, 8 status entries, 8 Yazi panes, several dynamic titles from Claude Code)
- Keep the sidebar visible with branch-directory and PR display enabled (default settings)
- Observe CPU usage via Activity Monitor — cmux stays at 65–101%, WindowServer at 40–60%
- Hide the sidebar (toggle sidebar visibility)
- Observe CPU immediately drops to 4–12%
- Show sidebar again — CPU spikes back up
Shell and environment
zsh. Multiple panes running Yazi (file manager) and Claude Code (which emits frequent set_status, report_pr, report_pwd shell integration updates).
Relevant logs or crash reports
**Pre-hide `sample` output** (5s, sidebar visible):
Hot leaf frames are dominated by sidebar-specific symbols:
- `Workspace.sidebarBranchDirectoryEntriesInDisplayOrder(...)`
- `Workspace.sidebarOrderedPanelIds()`
- `Workspace.sidebarHomeDirectoryForCanonicalization(...)`
**Post-hide `sample` output** (5s, sidebar hidden):
These sidebar symbols no longer appear in the hot path.
**Yazi is not the direct cause**: sampled Yazi processes show 0.0% CPU, mostly sleeping in `pthread_cond_wait` and `kevent`. Yazi increases sidebar complexity (more panes/branches to aggregate) but is not actively consuming CPU.
Screenshots or screen recordings
No response
Additional context
Root-cause analysis
I investigated the source code and identified the following chain:
- Shell integration emits updates (
set_status, report_pr, report_pwd, report_shell_state)
- These mutate Workspace
@Published fields (statusEntries, panelPullRequests, panelDirectories, etc.)
Workspace.sidebarObservationPublisher (Workspace.swift:5604) merges ~19 signals into a single invalidation stream
TabItemView subscribes to this merged publisher and bumps workspaceObservationGeneration on each coalesced event (ContentView.swift:11793)
TabItemView.body reads workspaceObservationGeneration at the top (ContentView.swift:11445), forcing full body re-evaluation
- The body then recomputes
sidebarOrderedPanelIds() (bonsplit tree traversal), branch-directory aggregation, and PR display for every workspace row
- The existing 40ms debounce (ContentView.swift:11166) is not sufficient because each debounced update still triggers the full expensive recomputation
Suggested fix direction
The cheapest structural fix would be to split the sidebar row into two view groups:
- Parent
TabItemView: keeps lightweight sections (title, pin, color, remote, metadata, log, progress, ports) — subscribes to a narrowed publisher with $title, $isPinned, $customColor, $remoteConfiguration, $remoteConnectionState, $remoteConnectionDetail, $activeRemoteTerminalSessionCount, $statusEntries, $metadataBlocks, $logEntries, $progress, $listeningPorts
- Child view: branch-directory + PR sections — subscribes to a separate narrowed publisher with
$panels, $panelDirectories, $currentDirectory, $panelGitBranches, $gitBranch, $panelPullRequests, $remoteConfiguration
This way, a metadata/status update only re-evaluates the parent (cheap), without triggering the expensive panel ordering and branch-directory aggregation in the child view.
Key implementation notes:
- Publisher split alone is not enough — the view must also be split, because the current single
workspaceObservationGeneration counter forces full body recomputation regardless of which signal fired
$panels only needs to route to the child view (no panel count display exists in the basic row)
$pullRequest (singular) can be excluded from both publishers — fallbackPullRequest is hardcoded to nil in sidebarPullRequestsInDisplayOrder
- PR display also depends on
$panelGitBranches for branch-matching filter
- Branch-directory canonicalization depends on
$remoteConfiguration via isRemoteWorkspace
Hardware note: The chip dropdown only goes up to M4; this machine is an Apple M5.
I have a detailed investigation write-up with a full dependency matrix and verification plan available if it would be helpful to the maintainers.
cmux version
0.63.1
macOS version
macOS 26.4 (Tahoe)
Mac chip
Apple Silicon (M1/M2/M3/M4)
Installation method
Direct download (DMG)
Can you reproduce this on cmux NIGHTLY?
I could not test NIGHTLY
Bug description
cmux consumes 65–101% CPU continuously when the sidebar is visible in a session with many workspaces and panes. Hiding the sidebar immediately drops CPU to 4–12%. The high CPU usage causes the machine to heat up significantly and WindowServer also stays elevated at 40–60%.
The issue appears to be caused by sidebar row recomputation: every metadata/status/branch/PR/directory update triggers a full recomputation of all workspace rows, including expensive panel ordering and branch-directory aggregation, even when the update only affects a narrow section of the sidebar.
Expected behavior
With the sidebar visible, cmux CPU usage should remain low during normal operation. Metadata and status updates from shell integration should not cause continuous high CPU.
Steps to reproduce
Shell and environment
zsh. Multiple panes running Yazi (file manager) and Claude Code (which emits frequent
set_status,report_pr,report_pwdshell integration updates).Relevant logs or crash reports
Screenshots or screen recordings
No response
Additional context
Root-cause analysis
I investigated the source code and identified the following chain:
set_status,report_pr,report_pwd,report_shell_state)@Publishedfields (statusEntries,panelPullRequests,panelDirectories, etc.)Workspace.sidebarObservationPublisher(Workspace.swift:5604) merges ~19 signals into a single invalidation streamTabItemViewsubscribes to this merged publisher and bumpsworkspaceObservationGenerationon each coalesced event (ContentView.swift:11793)TabItemView.bodyreadsworkspaceObservationGenerationat the top (ContentView.swift:11445), forcing full body re-evaluationsidebarOrderedPanelIds()(bonsplit tree traversal), branch-directory aggregation, and PR display for every workspace rowSuggested fix direction
The cheapest structural fix would be to split the sidebar row into two view groups:
TabItemView: keeps lightweight sections (title, pin, color, remote, metadata, log, progress, ports) — subscribes to a narrowed publisher with$title,$isPinned,$customColor,$remoteConfiguration,$remoteConnectionState,$remoteConnectionDetail,$activeRemoteTerminalSessionCount,$statusEntries,$metadataBlocks,$logEntries,$progress,$listeningPorts$panels,$panelDirectories,$currentDirectory,$panelGitBranches,$gitBranch,$panelPullRequests,$remoteConfigurationThis way, a metadata/status update only re-evaluates the parent (cheap), without triggering the expensive panel ordering and branch-directory aggregation in the child view.
Key implementation notes:
workspaceObservationGenerationcounter forces full body recomputation regardless of which signal fired$panelsonly needs to route to the child view (no panel count display exists in the basic row)$pullRequest(singular) can be excluded from both publishers —fallbackPullRequestis hardcoded tonilinsidebarPullRequestsInDisplayOrder$panelGitBranchesfor branch-matching filter$remoteConfigurationviaisRemoteWorkspaceHardware note: The chip dropdown only goes up to M4; this machine is an Apple M5.
I have a detailed investigation write-up with a full dependency matrix and verification plan available if it would be helpful to the maintainers.