---
title: Frozen-panel retention (instant switch-back to recent sessions)
---

# Frozen-panel retention (instant switch-back to recent sessions)

## What it is

Normally, when you switch away from a session its chat panel is torn down to a
lightweight shell to save memory. When you switch back, Omniscio has to rebuild the
heavy view — re-parse the markdown, re-highlight the code, rebuild the DOM — which
on a long conversation can show a brief "loading" shell before the chat appears.

**Frozen-panel retention** keeps the sessions you've looked at most recently
**fully built in memory while they're hidden** — the way a web browser keeps a
handful of background tabs ready — so switching back to one is **instant**. There
is no rebuild and no loading shell; the already-built panel is simply shown again.
The name is the model: a hidden retained panel is "frozen" (mounted but not
updating), and revealing it is just a visibility flip.

On top of keeping the panel built, Omniscio re-applies its **scroll position before the
panel is painted** (the _pre-paint reveal_), so a retained session reappears already
scrolled to where it belongs — with no momentary jump or flash on the way in. This is
on by default and also smooths switching into inbox / Needs-You panels; its own field
kill switch is `AMC_DISABLE_PREPAINT_REVEAL`. The engineering detail lives in the
[session-switch-prepaint contract](../../.claude/memory/contracts/session-switch-prepaint-contract.md).

This is a performance setting, not a workflow change. With it on, recent sessions
just feel snappier to return to. Nothing about how you use sessions changes.

**It is on by default (opt-out, since 2026-06-07)** — switching back to a recent
session should feel instant out of the box. It is still a fully reversible layer on
top of the existing renderer: turn the setting off (or use the kill switch) and Omniscio
behaves exactly as it did before the feature existed — the off path is unchanged.

## Where to find it

### Turning it off

It is already on — there is nothing to enable. To go back to the old
rebuild-on-switch behaviour: **Settings → Performance → "Keep recent sessions
instant"** and turn it off.

The toggle's own description reads: _"Keep the sessions you've looked at recently
fully built in memory (the way a browser keeps background tabs ready) so switching
back to one is instant instead of rebuilding it. Only applies to sessions that
aren't actively streaming, and a small limit caps how many are held so memory
stays bounded. On by default."_

There is no restart required — flipping it off immediately reverts hidden panels to
shells and lets memory reclaim them; flipping it back on starts retaining panels
again from your next session visit.

## How it behaves

### When it applies

- The session is **not actively streaming** (it's idle / ended / paused / waiting
  on you / errored — anything except a `running` or `starting` session).
- You have **viewed it recently** — retention follows the visit. A session only
  becomes retainable after it has been the on-screen session at least once this
  app run (that visit is what loads its conversation into memory in the first
  place).
- It is among the **most recently viewed** sessions, within the cap (see _Limits_
  below). Ping-pong between two or three sessions and they all stay instant.

### When it does NOT apply

- **Streaming sessions** (green — `running` / `starting`). A live session's view
  is changing token-by-token, so "instant return to the same view" is meaningless
  for it; those are already kept responsive by the separate keep-alive pool.
- **Sessions you haven't visited this run.** Retention never pre-builds a panel you
  haven't opened — it only keeps already-built recent ones around.
- **Sessions popped out into their own window** (detached) — they already have
  their own live panel; retention won't mount a second copy.
- **When the cap is exceeded.** Only the most-recent N are retained; older ones
  fall off and rebuild normally on next click (graceful — never a blank, just the
  same rebuild you get today).
- **When the feature is off** — every session switch behaves exactly
  as it did before this feature shipped.

A retained panel will never show **stale or blank** content: if a hidden session's
conversation has been dropped from memory, it is removed from the retained set and
falls back to the normal fetch-on-click path with its loading shell — i.e. it
degrades to today's behaviour, never to a wrong empty chat.

### Limits and memory

Each retained panel is a full heavy chat view (markdown + syntax highlighting +
DOM), so the feature is deliberately bounded:

- **At most 12 panels** are retained at once (`MAX_RETAINED_PANELS`), most-recently
  viewed first; the rest rebuild on click.
- Omniscio remembers the **last 32 session ids you viewed** (`VISITED_ORDER_CAP`) as the
  input to that selection — a cheap list of strings, not panels.
- **Runtime-only.** The retained set lives in memory for the life of the app
  process and is **not saved to disk** — every launch starts empty and only fills
  as you navigate. So there is no boot-time memory cost.

These caps are conservative on purpose. They stack on top of the keep-alive pool's
own budget rather than replacing it, so the two never fight over the same panels.

### The kill switch

There are **two** independent off-switches, and the kill switch always wins:

1. The **Settings toggle** above (`frozenPanelRetentionEnabled`, default on).
2. An environment kill switch: launch Omniscio with **`AMC_DISABLE_FROZEN_PANELS=1`** and
   the feature is forced off **even if the setting is on**. This is the field
   escape hatch — if retention ever misbehaved, this disables it without touching
   your settings. A missing or malformed switch is treated as "not killed," so the
   setting alone governs in the normal case.

### How it relates to the other "instant session" features

Three separate layers make sessions feel fast; this is the third:

- **Lazy content load** makes the _first_ time you open any session paint quickly,
  regardless of length.
- **Scroll position memory** returns you to _where you were scrolled_ when you come
  back to a session.
- **Frozen-panel retention** (this page) keeps the _whole built panel_ of recent,
  non-streaming sessions in memory so the _return itself_ is instant — no rebuild.

It is an additive layer on top of the **keep-alive pool** (which keeps the active
session and live/attention sessions mounted). The two sets never overlap: a session
kept alive by the pool is never separately retained, so there's no double-mounting
and no double memory cost.

## For agents

### Where it lives in code

- [src/renderer/src/features/dashboard/frozen-panel-retention.ts](../../src/renderer/src/features/dashboard/frozen-panel-retention.ts)
  — the pure LRU selector `selectRetentionIds(...)`, the `isRetainableStatus`
  non-streaming gate, and the `MAX_RETAINED_PANELS` / `VISITED_ORDER_CAP` bounds.
- [src/renderer/src/lib/frozen-panel-flag.ts](../../src/renderer/src/lib/frozen-panel-flag.ts)
  — `isFrozenPanelRetentionEnabled(setting)`: setting first, then the
  `AMC_DISABLE_FROZEN_PANELS` kill switch wins.
- [src/renderer/src/features/dashboard/Dashboard.tsx](../../src/renderer/src/features/dashboard/Dashboard.tsx)
  — tracks the recently-viewed order, computes the retained set, unions it into the
  conversation-cache eviction guard, and mounts pool ∪ retained as one panel set.
- [src/renderer/src/features/sessions/SessionPanel.tsx](../../src/renderer/src/features/sessions/SessionPanel.tsx)
  — `shouldRenderHeavy` folds in a `retained` term so a retained hidden panel
  renders heavy instead of as a shell.
- [src/preload/index.ts](../../src/preload/index.ts) — bridges the
  `AMC_DISABLE_FROZEN_PANELS` env var to the renderer before first paint.

The full engineering contract (test-locked invariants + safe-change checklist) is
the "frozen-panel retention" section of
[.claude/memory/contracts/keep-alive-pool-contract.md](../../.claude/memory/contracts/keep-alive-pool-contract.md).

## Related

- [lazy-content-load.md](lazy-content-load.md) — instant _first_ cold-mount of a long session.
- [scroll-position-memory.md](scroll-position-memory.md) — restores scroll position on return.
- [real-conversation-layout.md](real-conversation-layout.md) — the default chat render that retention keeps built.
