[FEATURE] Re-run statusLine command on terminal resize (SIGWINCH)

Status Open
Reported on v2.1.153
Maintainer reply None cached
Activity 3 comments · opened Jul 12, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

The statusLine command re-runs only on: new assistant message, /compact completion, permission-mode change, vim-mode toggle, and the optional refreshInterval timer (per the "When it updates" section of the statusline docs). Terminal resize is not a trigger.

Since v2.1.153 Claude Code sets COLUMNS/LINES before running the script, which encourages width-adaptive status lines (progress bars, flex layouts, responsive tiers). But when the terminal or pane is resized, the previous render — sized for the old width — stays on screen until the next trigger fires. In an idle session with the default configuration (no refreshInterval), a resized status line stays truncated or wrapped indefinitely; with refreshInterval set, it stays stale for up to the full interval.

The only mitigation today is refreshInterval: 1, which trades a rare event (resize) for constant polling: one subprocess spawn per second per open session, multiplied across tmux/multi-pane fleets — while still leaving up to 1s of visibly broken layout.

Proposed Solution

Treat a terminal dimension change as a status line update trigger: on SIGWINCH (or the equivalent dimension-change detection already used to set COLUMNS/LINES), re-run the statusLine command with the updated values. The existing 300ms debounce and in-flight cancellation semantics can apply unchanged, so rapid drag-resizes batch into one execution.

With this, event-driven configurations (no refreshInterval) stay crisp on resize, and polling configurations can drop back to long intervals.

Alternative Solutions

  • refreshInterval: 1 — works, but worst-case 1s of stale layout plus a ~40ms node spawn every second per open session (measured with a Node-based status line), i.e. continuous CPU churn to catch an event that happens a few times an hour.
  • Detecting the size from inside the script is impossible by design: output is captured, so tput cols/ioctl report nothing (documented), and the script only runs when Claude Code invokes it.

Priority

Medium - Would be very helpful

Feature Category

Interactive mode (TUI)

Use Case Example

  1. Run Claude Code in a tmux/Ghostty split with a width-adaptive status line that sizes meters from COLUMNS.
  2. Resize the pane (e.g. zoom a split from 220 to 90 columns).
  3. Today: the status line keeps its 220-column render — clipped or wrapped mid-meter — until the next assistant message or timer tick (10-30s in practice).
  4. With a resize trigger: one debounced re-run, correct layout within ~350ms, no polling needed.

Additional Context

  • Docs "When it updates" lists only new-assistant-message, /compact, permission-mode, vim-mode, and timer triggers; COLUMNS/LINES support (min-version 2.1.153) explicitly directs scripts to be width-aware — resize is the natural missing trigger for that contract.
  • Observed on Claude Code 2.1.207, macOS (Ghostty + tmux panes).
  • A resize-triggered run costs the same as any other trigger (~40ms for a typical Node renderer) and is strictly cheaper than the refreshInterval: 1 workaround it replaces.

View original on GitHub ↗

3 Comments

jakesciotto · 1 month ago

Still relevant on 2.1.268.

The docs now tell scripts to read COLUMNS and LINES, which invites width-adaptive layouts, but the "When it updates" list still has no resize trigger. So a right-anchored segment padded for the old width stays on screen after a drag until the next assistant message.

Reproduction:

  1. Configure a statusLine command that pads to COLUMNS (printf '%*s' "$COLUMNS" "model" is enough).
  2. Start a session and wait for the first render.
  3. Widen the terminal. The padded text keeps the old right edge.

Scripts cannot work around this from inside the output. Cursor-positioning CSI sequences such as \e[<col>G are sanitized (#64565), and leading whitespace is trimmed, so only SGR colors survive.

The only workaround today is refreshInterval: 1, which re-runs the script every second whether or not anything changed. A resize trigger could reuse the existing 300ms debounce, so the script would run once when the drag stops.

misselvexu · 1 month ago

Still reproducible on 2.1.270, the latest release on npm as of 2026-09-14 (macOS, Terminal.app, native install). Adding measurements of the refreshInterval workaround, and a pointer to where resize handling already exists.

What the workaround costs. I use a right-aligned bash status line with refreshInterval: 5:

  • One run of the script takes ~21 ms (~17 ms CPU). With 8 sessions open, the script alone costs ~2.7% of a core around the clock, idle sessions included, to catch the occasional resize.
  • After each resize the old layout stays on screen until the next tick. From the end of a drag to the corrected render I measured 2.9 s (281 → 252 columns) and 1.5 s (252 → 279). The worst case is the interval plus the 300 ms debounce.
  • Both re-runs rendered correctly at the new width. COLUMNS and the script are fine; the only thing missing is a trigger.

Resize handling already exists next door. subagentStatusLine receives a documented columns field. In the 2.1.270 bundle, the logic that drives it also takes the terminal width as an input, so it re-runs when the width changes. The state changes that trigger a main statusLine update (token usage, permission mode, vim mode, model, fast mode, effort, thinking, PR status, a new assistant message) don't include the width. Adding it there, behind the existing 300 ms debounce, looks like it would be enough to close this.

BorisTkachenko · 2 days ago

Still reproducible on 2.1.296 (macOS, native install, tui: fullscreen). The comments above cover widening; narrowing is worse, because the layout doesn't just sit in the wrong place — it loses content.

The status line text is drawn with wrap: "truncate", which cuts from the end. A line padded to the old COLUMNS is wider than the new terminal, so it's truncated from the right with …. With a right-aligned layout, that drops exactly the segments the padding was there to anchor (in my case cache state, model and session cost), while the padding in the middle survives. The row stays like that until the next trigger.

Repro:

  1. Set a statusLine command that prints left, then spaces up to COLUMNS - 4, then right.
  2. Wait for the first render, then make the terminal ~30 columns narrower.
  3. Expected: left … right re-laid out at the new width. Actual: left …, and right is gone until the next assistant message or refreshInterval tick.

No output-side workaround exists: cursor-positioning CSI is stripped, leading whitespace is trimmed, and right/center alignment was closed as not planned (#64565). So padding to COLUMNS is the only way to right-align, and it depends on a re-run when the width changes. In 2.1.296 the update triggers are still token usage, permission mode, vim mode, model, fast mode, effort, thinking, PR status and a new assistant message. Adding terminal width there, behind the existing debounce, would fix both directions.