[Bug]: Desktop terminal (Cmd+J) forces viewport to bottom — cannot scroll scrollback without jump
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Summary
On macOS desktop, opening the integrated terminal (mod+j → terminal.toggle) and scrolling up into scrollback is unreliable: the viewport keeps forcing itself back to the bottom, so I cannot read earlier terminal output without the screen jumping down again.
This is desktop Ghostty-based terminal behavior (not the mobile “can’t scroll at all” case).
Expected
- Opening the terminal may land at the bottom (live prompt) — fine.
- Once I scroll up into scrollback, the viewport should stay pinned at my scroll position until I deliberately return to the bottom (or run a “scroll to end” action).
- New output should only auto-follow if I was already at the bottom (standard terminal “stick to bottom” UX, same as Terminal.app / iTerm / VS Code).
Actual
- After opening the terminal with Cmd+J, trying to scroll to the top / earlier output fails: the view jumps back to the bottom.
- It feels like something is continuously re-pinning the viewport to the live end, so history is effectively unreadable while that fight is happening.
Steps to reproduce
- macOS → T3 Code desktop (Alpha).
- Open a project thread with an integrated terminal that has enough scrollback (run a few commands, or any long output).
- Press Cmd+J (
terminal.toggle/mod+j) to open the terminal drawer/panel. - Try to scroll up (trackpad / mouse wheel / scrollbar) to read earlier lines.
- Observe the viewport snap / jump back to the bottom instead of staying where you scrolled.
Environment
| App | T3 Code (Alpha) desktop |
| Version | 0.0.32 (com.t3tools.t3code) |
| OS | macOS |
| Shortcut | mod+j → terminal.toggle (present in ~/.t3/userdata/keybindings.json) |
| Surface | Integrated terminal (Ghostty renderer) |
Related issues (searched — not duplicates)
| Issue | Why related / why not a duplicate |
|---|---|
| #2141 Cant scroll terminal in mobile web | Same area (terminal scroll), but mobile web / no scroll at all. This report is desktop and is scroll-then-forced-to-bottom. |
| #4568 Expanding “Worked for …” scrolls to the end | Same jump-to-end while reading history UX class, but chat thread, not terminal. |
| #5434 Scroll to End button on iOS | Mobile chat scroll affordance, not desktop terminal. |
No open desktop issue found that matches “terminal scrollback fights auto-follow / jumps to bottom.”
Possible code touchpoints (from reading main)
Not a diagnosis — just breadcrumbs for maintainers:
apps/web/src/components/ThreadTerminalDrawer.tsx—fit()paths callscrollToBottom()whenisAtBottom()is true (mount fit timer ~30ms; also ondrawerHeight/resizeEpoch/ terminal identity changes).apps/web/src/terminal/ghostty/surface.ts—isAtBottom()→core.isViewportActive().- Buffer updates write new PTY data without an explicit “only follow if at bottom” guard in the React effect; if Ghostty always keeps the cursor in view on
vt_write, or ifisViewportActivestays true while the user has scrolled up, that would match this bug.
Impact
Major degradation when using the integrated terminal for anything with history (build logs, test output, long agent/shell sessions). I have to leave T3’s terminal and use an external one to read earlier output.
What this is / isn’t
| Is | Desktop terminal viewport forced to bottom / cannot stably view scrollback |
| Is not | Mobile-only scroll failure (#2141) |
| Is not | Chat thread jump-to-end (#4568) |
Workaround
Use an external terminal (Terminal.app / iTerm / Warp) for anything that needs scrollback review.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the macOS issue in the integrated terminal, then inspect apps/web/src/components/ThreadTerminalDrawer.tsx, especially fit() and its scrollToBottom() paths. Read apps/web/src/terminal/ghostty/surface.ts for isAtBottom() and core.isViewportActive(), and review how PTY writes interact with viewport state. Done means scrolling into scrollback stays stable while new output follows only when already at the bottom.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli, desktop
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100