Skip to content

Header/title duplicates repeatedly when the terminal is narrowed #1

Description

@wilversings

Header/title duplicates repeatedly when the terminal is narrowed

Summary

When the terminal window is made narrower, the top chrome of the TUI (the ✻ Claude title, the Code / Chat / Scheduled tab row, and the / search… line) gets redrawn on top of the old frame instead of replacing it, so it stacks up multiple copies. Dragging a window/pane smaller (which fires many resize events in a row) produces several duplicated header blocks; the more you shrink, the more copies pile up.

Steps to reproduce

  1. Run claude-sessions in a terminal with at least one project that has sessions.
  2. Grab the window (or tmux pane) edge and drag it narrower, or run resize-window/SIGWINCH down to ~24–40 columns.
  3. Observe the header/title/tab/search block appearing two or more times, stacked vertically.

Reproduced on main (v2.5.0), Node 22/24, inside a clean Fedora container, rendering through tmux 3.7 (a faithful terminal emulator). Not tmux-specific — any terminal reflows wrapped lines the same way.

Expected vs actual

  • Expected: on resize the UI redraws once, cleanly, at the new width.
  • Actual: each narrowing step leaves the previous header rows on screen and draws a fresh copy below them.

Evidence

Image Image Image

Likely cause

Ink erases the previous frame by counting the number of logical lines it last emitted, then redraws. When the terminal gets narrower, lines that previously fit on one row now wrap onto several physical rows in the terminal. Ink's erase count no longer matches the physical rows the old frame actually occupies, so the stale (wrapped) rows are not cleared and the new frame is painted underneath them. Every SIGWINCH during a drag repeats this, so the header multiplies.

The app renders a fixed-width outer box (<Box … width={stdout.columns}> in src/index.tsx) and relies on Ink's built-in re-render on resize; there is no explicit resize/clear handling, which is what lets the artifact accumulate.

Fix estimate — Low (small, localized change)

This is a well-known Ink resize class of bug and the fix is a few lines in src/index.tsx, no architectural change:

  • Add a stdout "resize" handler that clears the screen (e.g. write \x1b[2J\x1b[3J\x1b[H) before Ink repaints, or
  • Render into the alternate screen buffer (fullscreen mode) so reflow can't leave scrollback residue.

Main cost is verification across a couple of terminals (native terminal, tmux) and both grow/shrink directions — call it a half-day including testing.

I'm happy to open a PR implementing the resize-clear (or fullscreen) approach with a short before/after check across terminals — just let me know which direction you'd prefer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwaitingBlocked on something outside our control

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions