Appearance
Terminal History & Full Reload
Opening a session does not download its entire scrollback. The daemon collapses the session's output into a snapshot. Non-touch desktop and web clients initially request the last 3000 rows (tail_rows), while mobile and other coarse-pointer touch clients initially request the last 600 rows so a long-running session attaches without overwhelming the interface. Older rows remain available in 1500-row pages as you scroll to the top of the terminal.
The daemon records PTY output throughout the active session's lifetime. Long sessions no longer stop saving after 10000 output chunks, so reconnecting does not join an old beginning to a disconnected recent tail. This is live-session history, not a permanent archive: existing cleanup on session termination, PTY exit, and daemon restart still applies. Output already discarded by an older version cannot be recovered by updating or reloading.
That is the right default, but sometimes you want the whole thing at once:
- You need to search (Ctrl+F) across output older than the loaded tail.
- The terminal drifted from the owner's screen (a flaky link dropped frames, a stale persisted preview was restored, or a take-over swapped the writer).
- You scrolled up far enough that paging through it one page at a time is slow.
Reconnect recovery
After a reconnect, Clusto eagerly refreshes history only for terminals that are mounted and visible. A terminal that is not visible does not keep feeding live output into an xterm parser. Clusto marks it as needing recovery instead, then replaces its display with a fresh authoritative daemon snapshot when you return to it. This avoids leaving a hidden full-screen TUI to accumulate stale parser and renderer state during a long session. If a mobile workspace has multiple visible terminals, Clusto refreshes them one at a time to keep terminal replay work from freezing the app.
Clusto also forces an authoritative redraw when you reopen a terminal session after more than 30 seconds away. The client requests a fresh daemon snapshot, resets the local terminal, and rewrites it even when the snapshot has the same sequence number as the last replay. The same redraw runs for every attached terminal whenever the app returns from a minimized or background state. This repairs missed output and stale terminal rendering without requiring a manual resize or Reload full history.
Each session separately remembers the columns and rows used for its last authoritative redraw. This state stays with a terminal while the app keeps it in the off-screen pool, so switching between sessions does not mix their resize recovery state.
When you are reading older output, a refresh preserves the visible text instead of moving you to the newest rows. The reading position survives snapshot replacement, width changes, and switching away long enough for the app to release the off-screen terminal. If that text is no longer available, Clusto uses the nearest remaining position. A terminal already following live output continues following it.
Rows loaded by scrolling up, or by Reload full history, remain available after later refreshes. While you are reading above the bottom, recovery requests the available full history so a bounded tail cannot erase the reading position. If you have not loaded older pages or requested a full reload, returning to the bottom restores bounded history requests. The initial 3000-row and 600-row limits remain unchanged, and the daemon's reconstruction ceiling still applies.
If a missing output range has already left the replay buffer, delivery pauses until a fresh snapshot is ready. The client then resumes from the snapshot's sequence boundary. This avoids clearing the terminal and applying an incomplete fragment of a TUI repaint.
Stable replay and resize
Clusto opens xterm only after its visible pane exists, rather than initializing it inside a hidden holding area. New terminals therefore start with measurable geometry and avoid a synthetic tiny first render. Initial geometry is estimated from the actual viewport without forcing an 80x24 minimum. On Windows nodes, the client also enables xterm's ConPTY-aware behavior even when the viewer is running on another operating system.
Opening or closing the mobile keyboard does not resize the remote PTY, so it does not enter the ordered resize path. The terminal is translated, scaled, or left natural-size and scrollable entirely in the client according to the selected keyboard presentation mode.
For a real pane or window resize, the owner publishes an ordered geometry boundary. The client parses all older output at the old size, applies the new rows and columns at that boundary, then parses newer output. It does not clear and refetch history while the resize is still moving. This keeps the PTY responsive and lets a live TUI repaint at each intermediate geometry.
After the final ordered resize boundary has remained stable for 5 seconds, Clusto compares the settled columns and rows with the dimensions used for that session's last authoritative redraw. If either dimension differs, it requests a fresh daemon snapshot and rebuilds that terminal at the settled size. Every new boundary restarts only that session's timer. This repairs stale or garbled TUI cells left by intermediate repaints without repeatedly replaying history while you drag the window or pane.
Returning to a terminal that was pooled off-screen rechecks its own settled size. If the app was resized while another session was visible, Clusto schedules the same repair even when the PTY already reports the desired final geometry and therefore emits no new resize boundary. A snapshot response carries the owner's actual geometry at the captured boundary. The client uses that geometry to restore it, so an older in-flight response cannot incorrectly mark a newer size as repaired.
History replacement remains ordered when output is still arriving. Clusto writes the collapsed snapshot first, restores the TUI's captured terminal modes at the snapshot boundary, and only then appends live frames newer than the snapshot. The restored state covers application cursor keys and keypad, origin, line wrap, cursor visibility, insert/newline, focus reporting, mouse reporting, and bracketed paste. Snapshots also restore the current and saved cursor positions, their text styling, and the scrolling region. This keeps subsequent cursor restores and partial-screen scrolling aligned with the restored prompt. Alternate-screen and synchronized-output modes are deliberately excluded because restoring either around a collapsed snapshot can hide or stall the replacement. A newer live frame that changes any restored mode wins. Live output is held while the snapshot is applied, so replacement cannot splice or roll back a busy terminal.
Each history response belongs to one request, including every chunk of a large response. Overlapping requests cannot mix their chunks, and a late response or persisted preview cannot replace a newer authoritative history. The daemon captures the live boundary and durable recording position together, avoiding duplicated output when more text arrives while history is read. If output outpaces a response and leaves a gap, the client retries recovery.
Repeated recovery triggers share the pending history request while it is still making progress. A slow response can finish without being repeatedly restarted; an inactive request can still time out and be retried.
The daemon resets ANSI styling before each serialized row break. This keeps a TUI's background color from bleeding into blank rows created when restored history scrolls, which would otherwise appear as full-width color bars after a reload.
The instant terminal preview persisted on the device is a cache, not the source of truth. If the current app run does not already have a continuously subscribed live buffer, Clusto loads that preview while requesting fresh daemon history in parallel. A current live buffer appears immediately without waiting for the device cache. Fresh history replaces stale previews containing duplicated TUI frames left by an older app build. If no complete preview is available, Clusto waits for the snapshot before displaying buffered live updates, so partial TUI repaints do not appear as a broken initial screen.
A centered indicator accompanies the initial history fetch. Refreshes of a current live buffer use a small corner indicator.
Rendering and replay performance
Clusto uses WebGL terminal rendering on Linux, macOS, mobile, and browser clients. If WebGL cannot start or its graphics context is lost, the terminal falls back to the DOM renderer without interrupting the session. The native Windows desktop app stays on the DOM renderer because that is the reliable path in WebView2.
Bare HTTP(S) URLs remain one complete link when the terminal soft-wraps them across rows. Every visible segment is tappable, including on narrow mobile screens, and opens the full URL rather than only the text on that row.
Visible terminals share a bounded render scheduler instead of each terminal draining output independently. The foreground terminal is prioritized, while background terminals share a per-frame budget in round-robin order. Recent user input temporarily reduces background work to a small trickle so echo, cursor movement, and prompt interaction remain responsive during noisy builds. Writes are split into bounded blocks and serialized on xterm's completion callback, so the next block is not submitted until the parser finishes the current one.
If a visible terminal's pending render queue exceeds its safety limit, Clusto discards that incomplete local queue and requests an authoritative snapshot. This is safer than continuing to parse a partial or unbounded escape sequence stream. Terminals that are not visible bypass live xterm parsing completely and use the same snapshot replacement when reopened.
PTY input has a separate bounded queue in the daemon. Keystroke delivery never blocks the daemon's async control path: if a session process stops consuming input and the queue fills, Clusto reports backpressure rather than allowing an unbounded queue to consume memory or stall unrelated sessions.
On Windows, the desktop app also pins the upstream Tao fix for a lock held across PeekMessageW. This removes an event-loop deadlock that could freeze the whole native app during terminal activity.
Initial local replay is bounded before it reaches the terminal parser. Desktop clients accept at most 3000 rows or 768 KiB, while mobile clients accept at most 600 rows or 384 KiB. If a raw replay or cached preview exceeds those limits, Clusto requests the daemon's VT-collapsed snapshot instead of replaying a long sequence of obsolete TUI redraws. Older collapsed rows remain available through normal history paging.
These startup limits do not trim an authoritative full reload or a page of older history. Paging advances only after the older rows have been rendered. If a redraw overlaps a page request, obsolete pages are ignored without skipping those rows in the new history.
Provider-specific TUI stability
Clusto starts Claude Code PTY sessions with CLAUDE_CODE_NO_FLICKER=1 unless the session environment explicitly provides another value. This asks Claude Code to use its steadier rendering path without overriding a user's deliberate setting.
Clusto also enables CLAUDE_CODE_FORCE_SYNC_OUTPUT=1 so Claude Code wraps repaints in synchronized-output boundaries that xterm applies atomically. On Windows nodes, it additionally sets CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT=1. The full-frame alternate-screen repaint prevents ConPTY from leaving stale or misplaced prompt cells when positioned writes are combined during fullscreen input. Each value is only a default: an explicit session environment value, including an empty or disabled value, takes precedence.
Clusto passes Codex's terminal control sequences through unchanged. Rewriting its partial-screen scrolling as full-screen line scrolling can shift the saved cursor and make later typing appear beside a status line instead of the prompt. Preserving the original output avoids that source of cursor drift.
Some Codex transcript rows moved out of its scrolling region may not appear in the live client's scrollback. The daemon retains those rows when reconstructing history from the session recording; use Reload full history to bring them into the client.
Reload full history
Ctrl+Shift+H (or right-click -> Reload full history) throws away what the terminal currently shows and re-renders it from a fresh, complete daemon snapshot - no tail limit and no scroll-up paging left to do.
The client grows its scrollback to hold the rows returned by the daemon rather than passing the response through the startup tail limit.
On mobile there is no right-click (long-press opens touch selection instead), so the same action sits behind the chevron in the terminal's key bar as the Reload full history button.
The shortcut only fires for the terminal that has focus, so it never refetches every pane in a split workspace. While the snapshot is in flight the usual "Fetching session history…" indicator is shown, and the action is disabled so a repeated chord cannot stack requests.
Limits
The daemon reconstructs terminal history with a safety ceiling of 200000 scrollback rows, plus the visible screen. Its row budget accounts for line advances and wrapped text, rather than treating each output chunk as one row. Recordings can contain many lines in a single chunk. History beyond this reconstruction ceiling is not available through full reload or paging, even when the raw recording still exists.
A collapsed snapshot reconstructs the display and selected terminal state; it does not preserve every parser detail. Pending line wraps, character-set selections, and control sequences interrupted at the snapshot boundary can still differ from uninterrupted live output.
Reload is read-only: it re-reads the daemon's snapshot, it does not touch the session, the PTY, or its output on disk. Read-only viewers of a claimed session can reload just like the owner.
See Transport & Resume for stream ordering and reconnect recovery.