What problem does this solve?
Supacode's sidebar title is a workspace-level activity aggregate, but the terminal tab titles do not consistently expose the tab that contributes that activity. In a workspace with multiple tabs—or a tab with multiple split panes—the sidebar can shimmer while no corresponding tab title identifies where the work is happening.
This is broader than agent presence. The sidebar currently shimmers for:
- actively working agents (
.busy or .compacting),
- terminal activity that reports running progress through Ghostty, and
- workspace lifecycle activity such as setup, archive, or delete operations.
Tab titles currently shimmer from TerminalTabItem.isDirty, which already covers per-tab Ghostty progress/blocking scripts, but they do not receive the sidebar's independent agent-working aggregate. The result is two related shimmer decisions that can drift.
Split panes must also be handled correctly. Each pane is a terminal surface (a leaf in the tab's split tree), each tab already projects the IDs of all its surfaces, and the sidebar projects the surface IDs across every tab. The desired hierarchy is therefore:
pane/surface activity → tab activity → workspace/sidebar activity
Proposed solution
Make terminal tab-title shimmer mirror the sidebar's activity decision, using the same underlying activity semantics and preserving the existing per-surface ownership:
- A tab shimmers when any pane/surface in that tab contributes activity that would make the workspace's sidebar title shimmer.
- Agent activity uses the same sidebar semantics:
.busy and .compacting shimmer; .idle, .awaitingInput, and .error do not.
- Ghostty progress/blocking-script activity continues to shimmer the owning tab.
- If multiple panes in one tab are active, the tab remains shimmering until all contributing panes become inactive.
- If panes in multiple tabs are active, every contributing tab shimmers; unrelated sibling tabs do not.
- The workspace's surface-derived shimmer should be the rollup/OR of its tab shimmer states rather than a separate decision that can diverge.
- Keep agent-driven shimmer independent of the agent-presence badge visibility setting, matching the sidebar.
- Reuse the existing
ShimmerModifier, including its Reduce Motion behavior.
- While a tab is in inline rename mode, shimmer only the normal title label—not the replacement
TextField. Preserve the tab's activity state and resume the title shimmer after editing ends if the tab is still active.
For workspace-only lifecycle activity that is not attributable to a terminal surface, use the selected tab as the representative when the workspace has tabs. The invariant should be:
Whenever a workspace has at least one tab and its sidebar title is shimmering, at least one tab title in that workspace is also shimmering.
The existing model already contains the required hierarchy: WorktreeTabProjection.surfaceIDs is built from every leaf in a tab's split tree, and the workspace projection aggregates leaves across every tab. Extending the per-tab activity snapshot and sharing/deriving the same predicate should not require a new agent protocol event.
The existing rename view swap already supports the intended presentation: TerminalTabView hides TerminalTabLabelView while isEditing and overlays a plain TextField. Keeping shimmer attached to the title label preserves that behavior.
Acceptance examples
- One busy agent in one pane: its tab and the sidebar shimmer.
- One busy pane among several splits: the containing tab and sidebar shimmer.
- Two busy panes in different tabs: both tabs and the sidebar shimmer.
- One pane becomes idle while another pane in the same tab remains busy: the tab keeps shimmering.
- A non-agent process reports running progress: its tab and the sidebar shimmer.
- Sidebar lifecycle shimmer with existing tabs but no attributable surface: the selected tab shimmers as the representative.
- An actively shimmering tab enters inline rename mode: its
TextField does not shimmer; after rename completes, the normal title resumes shimmering if activity is still present.
- No tab belonging to the workspace contributes activity: no tab title shimmers.
Alternatives considered
- Rely on the per-tab agent badge: it is smaller and communicates agent identity/state, but it is less scannable and can be disabled.
- Keep independently computed sidebar and tab predicates: minimal code movement, but makes future drift likely; the desired model is one pane-to-tab-to-workspace rollup.
Supacode version
0.10.6
Are you planning to build this yourself?
Before submitting
What problem does this solve?
Supacode's sidebar title is a workspace-level activity aggregate, but the terminal tab titles do not consistently expose the tab that contributes that activity. In a workspace with multiple tabs—or a tab with multiple split panes—the sidebar can shimmer while no corresponding tab title identifies where the work is happening.
This is broader than agent presence. The sidebar currently shimmers for:
.busyor.compacting),Tab titles currently shimmer from
TerminalTabItem.isDirty, which already covers per-tab Ghostty progress/blocking scripts, but they do not receive the sidebar's independent agent-working aggregate. The result is two related shimmer decisions that can drift.Split panes must also be handled correctly. Each pane is a terminal surface (a leaf in the tab's split tree), each tab already projects the IDs of all its surfaces, and the sidebar projects the surface IDs across every tab. The desired hierarchy is therefore:
pane/surface activity → tab activity → workspace/sidebar activityProposed solution
Make terminal tab-title shimmer mirror the sidebar's activity decision, using the same underlying activity semantics and preserving the existing per-surface ownership:
.busyand.compactingshimmer;.idle,.awaitingInput, and.errordo not.ShimmerModifier, including its Reduce Motion behavior.TextField. Preserve the tab's activity state and resume the title shimmer after editing ends if the tab is still active.For workspace-only lifecycle activity that is not attributable to a terminal surface, use the selected tab as the representative when the workspace has tabs. The invariant should be:
The existing model already contains the required hierarchy:
WorktreeTabProjection.surfaceIDsis built from every leaf in a tab's split tree, and the workspace projection aggregates leaves across every tab. Extending the per-tab activity snapshot and sharing/deriving the same predicate should not require a new agent protocol event.The existing rename view swap already supports the intended presentation:
TerminalTabViewhidesTerminalTabLabelViewwhileisEditingand overlays a plainTextField. Keeping shimmer attached to the title label preserves that behavior.Acceptance examples
TextFielddoes not shimmer; after rename completes, the normal title resumes shimmering if activity is still present.Alternatives considered
Supacode version
0.10.6
Are you planning to build this yourself?
ready.Before submitting
ready.