Skip to content

Explanation

The drawer

The right-hand drawer is where anything a chat opens beside itself lives: an app the coder built, a saved artifact, a delivered file, the chat's files, the code review. It used to be three drawers that forgot what they showed when closed; it is one now, with a tab per thing. This page explains the choices behind it.

One tab per thing, per chat

A tab is keyed by what it shows — an artifact snapshot, a workspace app, a file, the code review — so opening the same thing again focuses its tab instead of adding one. Tabs belong to the chat they were opened in and are remembered in the browser's storage with the chat's id: after a reload they come back closed, the header's drawer button shows their count, and a deleted chat's tabs are forgotten. A tab whose file no longer exists says so rather than pretending.

Ten tabs at most; the eleventh closes the least recently viewed one and the status line says so. Closing the last tab closes the drawer; closing the drawer keeps every tab.

One app running at a time

An app in a tab is a real running program — a workspace app with its own server-side lease — and several would compete for the machine. So only the shown tab's app runs; a tab that is not shown keeps its container but releases its runtime (the server stops the app after a grace period), and its pill shows a dot. Showing it again relaunches it. Nothing runs while the drawer is closed. This is also why a reopen during the closing animation has to cancel the close's completion step: otherwise the close would stop the app the reopen just launched.

Refresh on reopen; resume when selected

Opening a card whose tab already exists — a rebuilt app, say — refreshes that tab from the current files. Switching selects the existing tab rather than creating a new one, but an app whose runtime was released must start again. Do not rely on unsaved in-app state surviving a close or switch.

Files and code changes are panes of the same drawer

A delivered file opens as a file tab with the file pill's own icon and name, showing the files pane on that workspace and path; the code review is one changes tab per chat. The drawer's own close, expand and resize controls serve every pane, and its opening motion runs once: a pane paints its light header on the opening frame and its cached body when the motion finishes, so a heavy file tree or diff never fights the animation. Sources stayed a separate drawer on purpose: it belongs to an answer, not to the chat, and is read differently.

Why

  • Remembering tabs per chat, and refreshing on reopen rather than on switch, were explicit owner decisions: the card in the transcript should be a way back to the same thing, and switching tabs should be free.
  • One running app at a time keeps the drawer honest about resources without hiding anything: the dot says an app is stopped, and showing it starts it.
  • One drawer with panes removed three sets of open/close/resize/expand rules and three theme framings, and made the header button one thing that means "what this chat has open".

Evidence: docs/drawer-tabs-2026-09-19.md in the source tree, with the live test that drives the real server through every rule above.