Skip to content

mini: every resize re-fetches and reprints the whole transcript, even when only the height changes #60979

Open

Description

@dhaern

Description

In opencode mini every terminal resize throws away the screen, re-fetches the session from the server and prints the whole transcript again. That's fine when the width changes and lines have to rewrap, but it also happens when only the height changes, and on a longer session it's pretty heavy. I run subagent viewers as tmux panes next to the parent (oh-my-opencode-slim opens one mini --session <child> pane per running subagent), so every time a pane opens or closes the panes around it get resized and each mini viewer re-renders everything it has.

I measured the viewer's CPU (utime+stime of the process tree, idle baseline subtracted) over 20 resizes in a 200x50 tmux window. With a 68-message session, mini spends about 300 ms per resize: 295-311 ms when the width changes and 302 ms when only the height changes. With an empty session it's around 31 ms. The full TUI on the same 68-message session costs 14 ms for a width change and 2 ms for a height-only change, so the cost comes from the mini replay path.

From reading the code (2.2.4, same on dev at 84f6605):

  • runtime.lifecycle.ts:355-366: onResize fires when either terminalWidth or terminalHeight changes.
  • runtime.ts:833-858: after a 250 ms debounce (RESIZE_DELAY) it calls item.handle.replayOnResize(...) with reset: () => shell.resetForReplay().
  • stream-v2.transport.ts:1663-1690: performResizeReplay resets the screen, clears all the per-message state and calls hydrate(attempt, { render: true }).
  • hydrate (:971) runs six requests in parallel (projectedMessages, inbox.list, permission.list, session.form.list, form.list, session.active) and then renderMessage for every projected message, up to the replay limit of 200.

The --replay help text says "Restore session history on resume and resize", so I get that replaying on resize is intended. What looks avoidable is that a height-only change goes down the same path. Already-printed lines don't rewrap when the height changes, so I don't think the transcript has to be printed again; laying out the footer for the new height should be enough. And when it does need a replay, rendering from what the stream already has in memory would skip the six requests. --no-replay turns the cost off, but then you lose history on resume too.

Plugins

oh-my-opencode-slim (only to open the panes; the cost shows up with a plain opencode mini --session <id> in a pane you resize by hand)

OpenCode version

2.2.4 (same code on dev 84f6605)

Steps to reproduce

  1. Open a session with 50+ messages in opencode mini --session <id> inside a tmux pane.
  2. Change only the pane height a few times (tmux resize-pane -y <rows>).
  3. Every resize clears the screen and reprints the whole transcript, and each one costs around 300 ms of CPU on a 68-message session. opencode --session <id> (full TUI) in the same pane costs about 2 ms per height-only resize.

Screenshot

No response

Operating System

Ubuntu 24.04 (aarch64)

Terminal

Alacritty, over SSH into tmux 3.8

Activity

  1. opencodejr commented on Oct 31, 2026

    @opencodejr

    Thanks for the detailed report and the measurements, @dhaern.

    To restate the request: in opencode mini, a resize that only changes the height shouldn't clear the screen and reprint the whole transcript, since printed lines don't rewrap. When a replay is needed, it could render from what the stream already holds in memory instead of fetching the session again. That would make tiled subagent panes in tmux much cheaper to open and close.

    Replaying on resize is intended at the moment (the --replay help text says so), so I've marked this as a feature request rather than a bug. The maintainers will consider it.

    Related:

  2. dhaern commented on Oct 31, 2026

    @dhaern
    Author

    Thanks, I hadn't seen #37971. One correction to my last paragraph: the stream doesn't keep the messages, only their IDs and the fragment reconciler, and resetForReplay clears the saved lines, so the re-fetch is needed and the time goes into re-rendering. What's left is the height-only case. Given the footer problems simonklee described there, I'm not sure skipping the replay is safe when only the height changes, so I'll leave that call to you.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions