Skip to content

Unified scrollback to the start of history: one disk-paged surface with the live turn, on by default #3856

Description

@acoliver

Part of #3868 (follow-ups to #854). This is #854 ask 1: trim scrollback to what is needed in memory, and let the user scroll back through the whole session, loaded from disk.

Problem

Today scrollback stops early. With the disk pager off (the default after #3852), the transcript is the in-memory fallback list, capped at 400 items or 4 MiB (DEFAULT_HISTORY_MAX_ITEMS, DEFAULT_HISTORY_MAX_BYTES, same as main). Older items are dropped and cannot be scrolled back to.

#854 added a file-driven scrollback pager (ui.scrollbackPagerEnabled). It pages the alternate-buffer transcript from the session journal through ProjectedJournalCursor, with a window bounded by viewport and eviction, and shows compression points as summary rows. It is off because it cannot render an interactive turn the way the in-memory transcript does; with it on, the Interactive UI (tmux) suite fails (approval dialogs, always-allow, long output, the issue 2208 and memory-profile scenarios).

What is missing:

  1. No live tail. ScrollbackPagerStore.setLiveTail and commitPendingRow have no production callers. Streaming text, tool groups and confirmation dialogs are never fed to the pager.
  2. No journal tailing. The pager reads the journal once in resumeFromJournal and does not extend on appends. A draft subscribes to SessionRecordingService.onCommitWatermark and calls ProjectedJournalCursor.extend.
  3. Journal rows are not display rows. The journal records tool response content, not the tool's resultDisplay, and has no UI-only items (info and error messages, slash-command output). A journal-projected tool row shows raw response JSON instead of the display string.
  4. Bootstrap race. useScrollbackBootstrap can render "scrollback unavailable: no journal" before the journal path is known, then rebind.

Options for item 3: record resultDisplay and UI-only rows in the journal as display-only records that the model-history fold ignores; or overlay committed tool-group items by call id, limited to the window.

Acceptance

  • One scroll surface: committed rows come from the journal, the live turn sits at the bottom, with no seam between them.
  • The user can scroll back to the session's first row, across compressions and resumes. No item-count cap.
  • Pager memory stays bounded by the window, the live tail and mutation events. Large old tool output is rendered within the visible-window budget (see Budget message component rendering to the visible window: diff and markdown process full buffers before clipping #3431).
  • With the pager on, LLXPRT_E2E_TMUX=1 bun test scripts/tests/interactive-ui.test.ts passes every scenario twice in a row.
  • Ink render tests cover the live tail, committed rows after append, the tool result after approval, and deterministic bootstrap.
  • The pager is on by default, and the fallback ledger's cap no longer limits scrollback.

Activity

  1. github-actions commented on Oct 11, 2026

    @github-actions
    Contributor

    LLxprt Issue Planner — infrastructure failure

    The autonomous planner failed with exit code 1. Please inspect the workflow logs (Run planner agent section) and re-run once resolved.

  2. changed the title [-]Scrollback pager cannot render live turns: journal rows lack tool resultDisplay and UI-only items[/-] [+]Unified scrollback to the start of history: one disk-paged surface with the live turn, on by default[/+] on Oct 13, 2026
  3. added theissue type on Oct 13, 2026
  4. added this to the 0.12.0 milestone on Oct 13, 2026
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

    Context ManagementIssues related to managing the context sent to the model.Ink UIthe packages/cli Ink based UI.

    Projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions