---
title: Your own scrolling always wins (the reader owns the view)
---

# Your own scrolling always wins (the reader owns the view)

## What it is

A session's transcript changes while you read it: replies stream in, images finish loading, older
turns render, the keyboard opens, the header grows. Omniscio places the transcript for you when you
open a session (at the live bottom for a running session, at the start of the reply you came to
read, and so on). The moment you move the transcript yourself, that placement is over: **nothing
automatic moves it again during that visit**, with one exception — if you are sitting at the very
bottom, new output keeps you at the bottom so you can watch it arrive.

It applies on the phone and on desktop.

## What counts as "you moved it"

- Scrolling with a finger, the mouse wheel or a trackpad.
- Scroll keys (Page Up / Page Down, Home / End, the arrow keys, Space) outside a text box.
- Pressing and dragging the transcript's scrollbar.
- Any scroll control: the up and down arrows, the "N more replies" pill, the press-and-hold on the
  down arrow, the step keys (Shift+Up / Shift+Down), Ctrl+Home / Ctrl+End, and jumping to a search
  result.

Scrolling that you did not do — content collapsing, the browser keeping your place while something
above you renders — never takes the view on your behalf.

## Where you end up

- **You moved away from the bottom** — the transcript stays exactly where you put it. A late image,
  a new reply, the keyboard opening, the header changing, a turn finishing: none of them move it.
  The down arrow shows, so jumping to the latest is always one tap away.
- **You moved to the very bottom** (within about 32 pixels — the same line at which the down arrow
  appears) — new output keeps you pinned to the bottom, the way a chat should.

## What hands the view back to the app

- **Opening the session fresh**, or coming back to it after switching away — it lands the usual way
  for its state.
- **Sending a message yourself** — you are taken to the bottom to see it, and follow the reply.
- **Jump to latest** (the down arrow, or its hold on the pill) — you follow new output again.
- **Scrolling back down to the bottom yourself.**

A scheduled message you set up with Send Later still scrolls into view when its card appears; one the
Inbox Pilot, another agent or a scheduled job queued only does so if you have not scrolled away from
the bottom yourself.

## Why it works this way

Earlier, each automatic correction guessed on its own whether you were still scrolling, from how
long ago your finger last moved (a few seconds). Someone who scrolled and then **read** looked idle,
and a tap on a scroll control was never seen at all, so a correction could take the page back — the
reported "when I scroll up on mobile it still jumps me back down". Now one fact decides it for every
correction: who moved the view last.

## For agents and developers

- The engine is `useSessionScroll` in
  [useSessionScroll.ts](../../src/renderer/src/features/sessions/useSessionScroll.ts). The state is
  `landing` / `following` / `reading`; every automatic write asks `engineMayMove`; the decisions are
  the pure `nextViewControl` and `engineMayMoveFor` in
  [scroll-classifiers.ts](../../src/renderer/src/features/sessions/useSessionScroll/scroll-classifiers.ts).
- The scroll tape records each handover as `[scroll:reader] <from> -> <to>` and each refused move as
  `HOLD reader is reading` (or `following`), so a report of an unwanted jump can be traced.
- The rule is `the-reader-owns-the-view-once-they-move-it` in
  [session-scroll-contract.md](../../.claude/memory/contracts/session-scroll-contract.md); a build
  guard ([session-scroll-reader-control.test.ts](../../tests/unit/lint/session-scroll-reader-control.test.ts))
  refuses any new automatic scroll write that does not ask.
- There is no setting: this is how scrolling is meant to behave.
