Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions apps/web/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ rounded:
control-inner: "3px"
segment: "8px"
tooltip: "8px"
popover: "14px"
frame: "6px"
window: "8px"
pill: "999px"
Expand Down Expand Up @@ -297,7 +296,7 @@ A restrained neutral ledger with one indigo voice, three signal colours and a se

A fixed 224px sidebar sits beside the flat main column, separated by a 1px rule. Below 640px it becomes a 56px icon rail with accessible names and no clipped labels. The header is at least 56px tall, with a 20px/600 title and actions on the right; actions wrap onto a new line when the available width cannot contain them. The scrolling body uses `24px 24px 40px` padding and a 24px section gap; horizontal padding becomes 16px below 640px. Wide tables scroll within their own frame.

The recurring shapes in the body are the KPI strip (auto-fit columns, min 158px; three per row below 1180px), chart grids (two equal columns, single below 1180px), full-width resource tables, and a fact row on detail pages. Overview has its own arrangement: Getting started while a step is to do, a four-column metric strip separated by vertical rules, Session activity beside a compact fleet inventory, then flat attention and project usage tables. The activity and fleet grid has a 24px gap and stacks below 680px of content width; the metric strip uses two columns below 560px. Core and up to four nodes open anchored popovers with facts and links to their pages. When more nodes exist, offline and degraded nodes take priority and a link leads to the full list. Popovers are the overlay card (8px radius, overlay shadow, 16px padding): a 14px title, 12px labels over 13px values, links at a ruled foot. Nodes itself is a plain list with a detail page.
The recurring shapes in the body are the KPI strip (auto-fit columns, min 158px; three per row below 1180px), chart grids (two equal columns, single below 1180px), full-width resource tables, and a fact row on detail pages. Overview has its own arrangement: Getting started while a step is to do, a four-column metric strip separated by vertical rules, Session activity beside a compact fleet inventory, then flat attention and project usage tables. The activity and fleet grid has a 24px gap and stacks below 680px of content width; the metric strip uses two columns below 560px. Core, E2B and up to four nodes are plain rows that open their pages: Core metrics, Sandbox metrics and the node's page on Nodes. When more nodes exist, offline and degraded nodes take priority and a link leads to the full list. Nodes itself is a plain list with a detail page.

Spacing follows a 4px base: 4, 8, 12, 16, 24 (page gutter and section gap). Controls are 32px tall, segmented options 26px, table rows 44px (32px compact), table headers 36px.

Expand All @@ -313,7 +312,7 @@ Page structure comes from typography, spacing and dividers. Reserve elevation fo
- **Page surface**: flat and full-height, with no outer radius or shadow.
- **Card** (no shadow; a 1px `frame-line` ring at 11% ink): KPI strips, chart grids, Overview cards, the Session transcript and Settings row cards. Cards are flat; no page surface is translucent or blurred.
- **Control ring** (a 1px Firm Rule ring with an extra-small shadow): outline buttons, the active segment, and search fields and selects in toolbars. Inputs inside cards and dialogs carry only a Hairline ring.
- **Overlay** (a 1px Hairline ring with a large soft shadow): anchored popovers, menus, dialogs, help tips and chart tooltips.
- **Overlay** (a 1px Hairline ring with a large soft shadow): menus, dialogs, help tips and chart tooltips.

### Named Rules
**The One Card Rule.** Figures, charts and tables sit in one card divided by 1px internal rules. A card never contains another bordered, shadowed container; empty states remain unframed, including inside a card.
Expand All @@ -332,7 +331,7 @@ Compact and quiet; the primary button is the only filled button in a header.
- **Danger:** Fault Red fill, white text: the confirm button of every destructive dialog. On a page, a destructive button such as Delete on a detail page is red text on an outline button that takes a red tint on hover.
- **Ghost:** transparent with Graphite text; hover takes Ink on the Hover wash.
- **Focus / Press:** focus draws a 2px indigo outline 2px outside the button; press scales to 0.96.
- **Text action:** borderless Graphite 12.5px/500, 24px tall with 6px corners, that turns Ink on the Hover wash; used only for per-row actions in tables (Rename, Archive, Delete) and links in a popover's foot, never in a header. A destructive text action turns red on hover.
- **Text action:** borderless Graphite 12.5px/500, 24px tall with 6px corners, that turns Ink on the Hover wash; used only for per-row actions in tables (Rename, Archive, Delete), never in a header. A destructive text action turns red on hover.

### Refresh button
A 32px ghost icon button with the refresh glyph. Controls that scope the whole page (project filter, time range) come before it; on detail pages it leads, followed by any outline actions and Delete. It spins while reading; its tooltip carries the last update time instead of a visible timestamp.
Expand Down Expand Up @@ -412,7 +411,7 @@ Setting up hosted sandboxes is a set of pages inside Settings → Sandbox and sc

### Sandbox lifecycle

For deployments with a suspension policy, Nodes and Sandbox metrics lead with one shared KPI strip: active slots, suspended placements, retained slots, idle threshold and snapshot retention. The counts identify their Core accounting scope in help tips; offline nodes never contribute to online slot limits. Read failures preserve known counts with a visible unconfirmed notice, and absent evidence stays a dash. Policy values are read-only. Allocation rows show elapsed time in the recorded compute phase without estimating expiry. Sandbox metrics places recorded compute beside the separate Runtime status, retaining unavailable diagnostics. Supporting persistence and resume conditions belong in help tips.
For deployments with a suspension policy, the Nodes list adds Suspended and Retained / limit columns and a node's Capacity strip adds Suspended, Retained / limit and Snapshots; one-line help tips say what each limit counts. Overview adds the suspended total of all registered nodes under its sandbox slots. The idle threshold is edited in Settings → Sandbox and scheduling, where snapshot retention is read-only. Read failures preserve known counts with a visible unconfirmed notice, and absent evidence stays a dash. Allocation rows show elapsed time in the recorded compute phase without estimating expiry. Sandbox metrics places recorded compute beside the separate Runtime status, retaining unavailable diagnostics. Supporting persistence and resume conditions belong in help tips.

### Configuration generations
A single rollout row opens a details dialog for Core's target generation, previous-generation sandboxes and rollout counts. Poll rapidly only while Core reports preparing, or while the independent reset is active. Settled is preparation state, not proof that all nodes are ready or all older Sessions have ended. Retained old resources alone must not keep rapid polling alive. Render failed, update-required and unknown target states distinctly. Keep offline/live-provider status separate from a node's durable serving-generation pin; the pin alone never means the node is online or ready. Node detail shows the serving generation and target preparation; allocation detail shows the owned configuration generation. Do not calculate rollout completion from these rows or promise immediate placement on the target.
Expand All @@ -427,11 +426,11 @@ A persistent progress panel uses Core's busy, idle and cleanup counts, deadline
Read deployment progress independently of node details. Partial failures retain successful facts with a visible stale/unavailable notice. An uncertain write opens the recovery dialog and requires a new authoritative read before another mutation; refresh reads state and never resubmits the write. The connection's QueryClient owns both the authoritative deployment and pending or uncertain writes across route transitions. Leaving Sandbox configuration cannot cancel or forget a submitted reset, and a cached node snapshot cannot replace a newer reset or completion learned on Overview. Returning to Nodes or Sandbox configuration reads the shared deployment immediately and refreshes node evidence separately. Only a successful authoritative read begun after the write settles can release the mutation block; an earlier or still-pending read cannot. Submitting consumes the reset confirmation even if its outcome is uncertain; recovery uses the separate read-and-review dialog. Observation retries preserve applicable non-secret configuration drafts. A changed installation, owner epoch, backend, mode or generation discards the prior draft and confirmation. Logout clears this connection-scoped state.

### Settings page
Settings is the single platform configuration entry, with four tabs: Sandbox and scheduling, Workspace storage, Models and credentials, and Service and deployment. Each tab has a stable address; links from Nodes, metrics and Getting started open the owning tab and, where appropriate, its node editor or enrollment flow. Forms save independently through their resource APIs, never through one cross-resource Save all action.
Settings is the single platform configuration entry, with four tabs: Sandbox and scheduling, Workspace storage, Models and credentials, and Service and deployment. Each tab has a stable address; links from Nodes and metrics open the owning tab, and the Sandbox and scheduling header links back to Nodes. Forms save independently through their resource APIs, never through one cross-resource Save all action.

The hierarchy is page, tab, section, row. The page header loses its rule to an underline tab row: 40px text tabs in Graphite 13px/500, the current one Ink with a 2px Ink underline. The body is a left-aligned column at most 880px wide with 32px between sections. A section is the shared Section heading (14px/600, help tip, section-wide outline actions on the right) over one card of label/value rows (`settings.css`): a 200px Graphite label column with its help tip and an Ink value column, 8px by 16px padding, 32px minimum line height, Faint Rules between rows; below 640px the label sits above the value. An action that changes one value sits at the end of its row (Edit tenant capacity; Save beside the idle-seconds field, whose error appears beneath it). Read-only status is a row too (Configuration rollout, Snapshot retention); tables sit in one framed card. Settings never repeats the KPI strips of Nodes or the metrics pages. The irreversible operation closes the page in its own section: a red-ringed card with one Ink line stating the consequence and a red-text outline button.

Sandbox and scheduling contains sandbox setup or Deployment provider (Provider, Each sandbox, the E2B connection rows and the rollout row, with Change resources in the section header), then Capacity and suspension (the deployment-wide idle policy and read-only snapshot retention, shown only when the deployment declares suspension), then Sandbox nodes (Add node in the header, per-node limits in a table), then Reset. While a reset runs, its progress section leads the page with Force reset now and Cancel reset in its header. Add node opens the enrollment form here. Nodes remains an operational inventory: status, allocations, host figures and removal, with links to the canonical settings forms. Resource changes never imply rewriting existing allocations. Lower limits do not imply forced termination or snapshot deletion.
Sandbox and scheduling contains sandbox setup or Deployment provider (Provider, Each sandbox, the E2B connection rows and the rollout row, with Change resources in the section header), then Automatic suspension (the deployment-wide idle policy and read-only snapshot retention, shown only when the deployment declares suspension), then Reset. While a reset runs, its progress section leads the page with Force reset now and Cancel reset in its header. Nodes owns the nodes themselves: status, per-node limits, allocations, host figures and charts, Add node (with its enrollment form), Edit node and removal. Resource changes never imply rewriting existing allocations. Lower limits do not imply forced termination or snapshot deletion.

Workspace storage shows the selected configuration's adapter and tenant capacity (in bytes units, or No tenant capacity limit) under Storage configuration, with Select new configuration in the section header and Edit tenant capacity on the capacity row. The configuration ID and parameters JSON sit in a closed Configuration details disclosure at the end of the card. Select new configuration accepts an adapter identifier, configuration ID, parameters JSON object and optional write-only credential JSON object. Edit tenant capacity keeps the current configuration identity. Explain adapter preparation and existing-workspace behavior behind help tips, with a link to the owning configuration document; keep required form labels and validation visible. Never prefill credentials or persist their drafts across navigation. A failed read is not an unconfigured filesystem, and an uncertain write is not a safe automatic retry.

Expand All @@ -450,7 +449,7 @@ The self-hosted connection panel names Core's observed state, the bound key and
### Loading and motion
The console has no spinners and no "Loading…" lines. Reads are cached (TanStack Query) and prefetched on navigation hover, so revisits show data at once and refreshes keep the last data on screen. Only a first read shows a skeleton in the final layout's cards: table rows, a headline strip with chart panels, or a facts card with a table, with a sweep that repeats every 900ms and stops under reduced motion. Work in progress is the Agent's shimmering "Working…" line in the conversation and the breathing pending dot.

Motion reports state and never makes anyone wait: the navigation chip and segmented thumbs glide (Motion, one 320ms spring without bounce), figures roll, charts draw in once per range, new conversation messages settle 6px upward in 260ms, pages fade in 160ms, anchored popovers scale from 98% and dialogs from 96%. Reduced motion makes all of it instant.
Motion reports state and never makes anyone wait: the navigation chip and segmented thumbs glide (Motion, one 320ms spring without bounce), figures roll, charts draw in once per range, new conversation messages settle 6px upward in 260ms, pages fade in 160ms and dialogs scale from 96%. Reduced motion makes all of it instant.

## Do's and Don'ts

Expand Down
Loading
Loading