The web UI: map and decisions
The browser client (cast server) is one page with a few surfaces around a conversation. This page is the map: where things are, how they move between a desktop and a phone, and the rules the layout follows. It is for people changing the client; for using it, see the server docs.
Surfaces
header sessions panel toggle . connection dot . [status] [dashboard] [settings] [shortcuts] [files panel toggle]
sidebar new session . quick session . date/project switch . search . project filter . pinned . sessions . model . log out
chat the thread: user, reasoning (folded), tool cards, agent text, turn meta
composer role line (persona, mode, folder, timer) . queued messages . input . attach . voice . send
files panel inputs . files . memory . changes (diff)
full pages /dashboard . /settings (routes, not modals: back button and reload work)
modals new session . share . shortcuts . command palette (type / in the composer)Flows
| Goal | Path |
|---|---|
| Start work in a folder | New session, pick persona and folder (or sandbox), type |
| Ask something throwaway | Quick session (bolt button): sandbox folder, assistant persona |
| Go back to earlier work | Sidebar row, or search; rows show title, folder and age |
| Steer a running turn | Type while it runs: the message is queued or steers, shown above the input |
| See what changed | Files panel, Changes tab; per-message fork and rewind |
| Hand a session to someone | Share, a read-only live link |
| Change how it behaves | Settings (model, persona, reasoning, appearance, memory, MCP) |
Responsive rules
- At 768px and below the sessions panel and the files panel become full-width overlays; only one is open at a time.
- The shortcuts button is hidden in portrait on a phone (a physical-keyboard feature). The dashboard stays: its header wraps and its charts scroll.
- Under a coarse pointer every stand-alone control grows to a 44px target; small ones (pin, more, copy) keep their look and grow their hit area.
- Inputs are 16px on iOS so focusing a field does not zoom the page.
- No horizontal page scroll at any width; long paths and code scroll inside their own box.
Chat components and offline shell
The Web transcript frame, message boundary and composer frame use @monos/ui/chat; the header, session creation actions and composer actions use Monos IconButton and Button primitives. Their isolated styles receive generated Monos utilities and Cast's active theme tokens. Cast still owns the session state, markdown, tool cards, streaming and message actions inside those components. The terminal keeps its existing pi-tui rendering and the same session behaviour.
The Web client is installable as a PWA. Its service worker caches the app shell and static UI assets; /api/* requests and event streams stay network-only. Remote installs require HTTPS; loopback development works on HTTP.
Decisions
- A session row says what it is. An untitled session is "New session" while it is empty, and every row carries the folder and its age. A persona name alone was the same on every row.
- Unused sessions are hidden. A session with no messages stays out of the list unless it is open, pinned or running, so clicking New session and leaving does not leave a trail.
- Finished reasoning folds to one line. It stays one tap away; while it streams it is open. A reply with several tool calls otherwise spends most of a phone screen on boxes of thought.
- The role line says "sandbox", not a path. The full path is in its tooltip.
- The new-session dialog is one screen on a phone. Persona cards put name and source on one row.
- The two panel buttons look like the panels. Both were chevrons pointing opposite ways; they are now a window with a left or right bar, so it is clear which panel each opens.
- Settings opens on its current tab, not on "Reload resources", whose tooltip covered the tab row.
- Signing in returns to where you were going. A link to a session, or an expired login mid-session, goes to
/login?next=...and comes back;nextis accepted only as a path on this site. - Losing the server is visible and recovers by itself: the dot turns yellow, the composer reads "Reconnecting..." and is disabled, and it returns without a reload.
- A plan is shown before it is approved. The review card carries the plan's summary and opens the plan file; approving a plan you cannot read was the gap.
- Settings say what is wrong. An MCP server that is not connected shows its error; hook, MCP and skill toggles are words, not icons.
- Previews are full screen on a phone, like settings and the new-session dialog.
Motion
- One scale:
--dur-instant(.1s, a press),--dur-fast(.15s, hover and small arrivals),--dur-base(.22s, a dialog or card arriving). New code uses these, not literals. - Arrivals have a direction. A dialog lifts in (
modal-in), a phone dialog slides up (sheet-in), menus and the palette drop from their button (pop-in), the backdrop fades. The transcript only fades (rise): movement there would fight the auto-scroll while a reply streams. - A press answers at once: controls sink to .97 under the finger.
- Waits are quiet at first: the "Loading" word appears after .15s, so quick loads show nothing.
- Reduced motion: arrivals just appear, transitions are instant; spinners keep turning, since they are the only sign a request is in flight.