Skip to main content

Zed agent UI lessons for EXEPERT

This note records what makes Zed's agent conversation feel compact and smooth, how its visible Thinking and Raw Input surfaces work, and which parts are useful for EXEPERT.

The comparison was verified against the local Zed reference at commit d9ad6aff67e4 and the EXEPERT source on August 28, 2026. EXEPERT uses a modified, vendored GPUI layer while its resolved Zed dependencies remain pinned to cc053a4a6fa2fd0e8793201ed9099466af1be0b1, so the two applications share a rendering lineage but not an identical API or source snapshot.

Thinking is not hidden chain-of-thought

Zed renders structured thought chunks supplied by an agent protocol. It does not infer, reconstruct, or expose a model's private hidden reasoning. EXEPERT must preserve the same boundary: show only provider-authorized reasoning summaries or ordinary status text, and never relabel hidden chain-of-thought as user-visible content.

The short answer

Zed's perceived quality comes from three layers working together:

  1. A structured event model distinguishes messages, thoughts, tool activity, and generation state.
  2. A quiet visual hierarchy keeps assistant prose flat while thoughts and tool details use compact disclosures and timeline lines.
  3. A virtualized variable-height list updates and remeasures only the entries that changed, while stable state preserves scroll position and tail follow.

EXEPERT now applies that third layer to both Chat sources. Codex and Native Chat share one adaptive transcript core, while the persistent EXEPERT | ZED selector changes presentation semantics without changing models, transports, privacy, or stored messages.

Implemented EXEPERT and ZED presentation contract

The Chat header exposes one global presentation preference from CodexUiPreferences.chat_presentation. Missing settings default to EXEPERT, and the additive field remains compatible with settings schema version 2. Both Native Chat and Codex read the same value. Below 720 px of Chat stage width, the visible tabs become an opaque two-option menu so the header does not jump or clip.

Changing presentation closes geometry-dependent message and composer popups, then remeasures the affected stable rows. It does not clear drafts, switch chats or tasks, stop speech, cancel a turn, alter attachments, or issue a network request. Logical list bookmarks therefore survive style changes.

EXEPERT preserves the established card and disclosure hierarchy. ZED uses EXEPERT's own palette, type, icons, and Rust/GPUI components with:

  • compact 8 px user cards inside a centered 760 px reading column;
  • flat assistant prose without a repeated assistant label;
  • quiet timeline guides and borderless contextual actions;
  • a 12 px composer with no shadow;
  • a stable three-dot Working row before the first visible Native answer token; and
  • compact Thinking and developer-activity disclosures in Codex.

This is a presentation comparison, not a performance tier. Both modes use the same optimized transcript implementation.

How Zed presents agent thinking

The ACP thread model stores assistant content as distinct message and thought chunks. A live thought can therefore be rendered independently from the final answer instead of parsing special markers from prose.

Zed provides four display policies through ThinkingBlockDisplay:

PolicyBehavior
AutoExpands the currently streaming thought, then collapses it when the stream moves on unless the user explicitly toggled it.
PreviewOpens the live thought in a constrained preview; an explicit user toggle reveals the full body.
AlwaysExpandedStarts thoughts open while still respecting an explicit user override.
AlwaysCollapsedStarts thoughts closed while still allowing the user to open one.

The visual treatment is intentionally quiet: a muted thinking icon and label, a small disclosure affordance, and a thin left guide beside the open body. The preview is height-constrained and fades at its edge. A separate synthetic generation row uses a small Braille-frame spinner while the agent is working.

The apparent smooth dropdown is primarily fast native re-layout with stable state. In the inspected source, the body is conditionally mounted and the chevron changes; there is no general-purpose animated height tween for this disclosure. That distinction matters because EXEPERT can achieve the same calm feel without animating a large, continuously changing Markdown region.

A safe EXEPERT equivalent

For Codex, the matching UI should be a Working status plus an expandable Reasoning summary that is fed only by the App Server's summary events. The existing protocol boundary already opts out of item/reasoning/textDelta and removes raw or encrypted reasoning fields before state reduction.

For Native Chat, a thinking surface is truthful only when the selected backend provides an explicit, displayable summary field. Otherwise EXEPERT should show a generic activity state such as Working, not fabricated internal thoughts.

Why Zed scrolling feels smooth

Zed does not lay out the full conversation on every streamed update. Its conversation view uses GPUI's variable-height virtual list and keeps stable entry state outside the visible row tree.

The important mechanics are:

  • ListState tracks variable row heights and the current scroll anchor.
  • A SumTree finds the visible item range without scanning every message.
  • Only visible rows plus an overdraw buffer are rendered.
  • Cached measurements are reused for unchanged entries.
  • A streaming update remeasures its affected row rather than rebuilding the entire transcript.
  • Insertions and removals splice the entry list at the affected range.
  • Tail follow is conditional, so inspecting older content is not interrupted by incoming tokens.

The overdraw buffer is deliberate. Pre-rendering a limited region above and below the viewport prevents blank flashes when a wheel or touchpad moves faster than a frame can be measured.

How EXEPERT compares

EXEPERT Codex already follows the same architecture in desktop/exepert-desktop/src/ui/codex_transcript.rs:

  • a GPUI ListState virtualizes the transcript;
  • stable row keys and revisions preserve row identity;
  • prefix/suffix reconciliation splices only the changed range;
  • only changed rows are remeasured;
  • 512 px of overdraw protects fast scrolling;
  • a 48 px near-bottom threshold controls automatic tail follow;
  • each task retains its own scroll bookmark; and
  • non-precision wheel input receives a bounded 140 ms glide, while precision input and reduced-motion behavior remain direct.

Completed agent Markdown also retains a stable TextView identity so unchanged responses are not reparsed on every parent repaint.

This means a Zed-like Codex experience should preserve the existing EXEPERT transcript engine. Replacing it would add risk without addressing the main visual differences.

Native Chat now projects setup, empty, message, footer, failure, and streaming states into stable NativeTranscriptRow values and renders them through the same adaptive engine. Bookmarks are keyed by ChatId, so returning to an older chat restores its logical reading position. Native SSE deltas are drained in the existing 40 ms batch and update one bounded provisional row once per UI batch. The provisional buffer is process-local, capped at 512 KiB, and is atomically replaced by the authoritative stored response. It is never persisted, sent back as history, or described as reasoning.

How Zed styles Raw Input

Zed converts tool input into Markdown before rendering it:

  • null produces no block;
  • booleans, numbers, and strings render as plain content; and
  • objects and arrays are pretty-printed into a fenced json code block.

The surrounding tool timeline uses a small muted, buffer-font label such as Raw Input, a thin left guide, compact spacing, and an inset code surface. The shared Markdown code renderer supplies syntax highlighting, horizontal scrolling, and hover actions for copy and wrapping. The result feels like part of the conversation rather than a separate diagnostics console.

EXEPERT should borrow this presentation only for explicitly safe structured data. Its Codex reducer currently keeps bounded, allowlisted developer details and strips raw reasoning, encrypted content, credentials, and unrestricted protocol payloads. A future details card should retain that policy:

  • render only allowlisted keys;
  • pretty-print bounded JSON;
  • cap string length, collection size, and nesting depth;
  • exclude prompts, authorization headers, tokens, encrypted fields, and raw reasoning;
  • label task-level metrics as task-level rather than response-level; and
  • provide wrap and copy controls without copying hidden fields.

Calling an allowlisted projection Structured details is more accurate than calling it Raw Input. The latter label should be used only when the entire displayed value is both intentionally exposed by the provider and safe to show.

Visual hierarchy worth adopting

Zed's assistant output is mostly flat rather than placed in a large bubble. User prompts retain a compact card treatment, while assistant prose, thoughts, and tool activity share one aligned reading column. Tool events use small icons, muted labels, and vertical guides; detailed content appears only after a disclosure. A centered maximum content width prevents long lines without making short replies look like oversized cards.

For EXEPERT, the useful translation is:

  • keep user messages compact and right-aligned;
  • keep authoritative agent prose flat and left-aligned;
  • use a quiet icon disclosure instead of prominent EXPAND/COLLAPSE text;
  • show one synthetic Working row during generation;
  • let an Auto or Preview policy manage provider-authorized summaries;
  • present tool and developer activity as a restrained timeline; and
  • keep contextual actions under completed responses rather than inside the prose surface.

These changes can make the agent feel more alive without pretending that a UI animation is evidence of consciousness or emotion.

Current architecture comparison

ConcernZed referenceEXEPERT CodexEXEPERT Native Chat
RuntimeNative Rust/GPUINative Rust/modified GPUINative Rust/modified GPUI
Conversation modelStructured agent entries and chunksServer-authoritative thread, turn, and item eventsUser/assistant messages with bounded metadata
Visible thinkingProvider/ACP thought chunksProvider-authorized reasoning summaries onlyGeneric working state unless a backend supplies a displayable summary
Raw reasoningDoes not imply reconstruction of hidden reasoningExplicitly opted out and strippedNot part of the message contract
Transcript layoutVariable-height virtual listShared variable-height virtual listShared variable-height virtual list
Incremental updateSplice/remeasure the affected entryStable-key reconciliation and changed-range remeasurementStable rows, changed-range remeasurement, and one provisional streaming row
Tail behaviorFollow only while anchored at the endNear-bottom follow, per-task bookmark, unseen-content stateResponseFollowState and scroll-to-bottom state
Tool detailsRaw values rendered through Markdown/code blocksBounded allowlisted developer projectionNo equivalent rich tool timeline yet
Primary opportunityMature baselineContinue measuring disclosure usabilityAdd structured backend events only when providers expose truthful safe fields

Implemented privacy and disclosure boundary

  1. Codex Thinking consumes only the reducer's authorized ReasoningSummary; the App Server raw-reasoning notification remains opted out and recursively stripped.
  2. An actively streaming summary may open automatically in a 256 px faded preview. It collapses when it becomes authoritative unless the user made an explicit expansion choice. Explicit expansion shows the full summary, and explicit collapse overrides automatic preview.
  3. Developer Structured details are generated only from the reducer's bounded allowlisted item.details value. Wrap and copy never consult raw protocol payloads.
  4. Native Working and provisional text represent request state and visible answer tokens. They are not an inferred thought trace.
  5. Presentation expansion state, provisional output, and Codex automatic preview state are process-local and excluded from settings and diagnostics.

Status-rail cleanup

Human collaboration now enters from the desktop status toolbar rather than a floating bubble over workspace content. The stable collaboration-popup-trigger is a 28×20, 2 px-radius action at the non-shrinking right edge of the status rail's left group. It retains the room connection, peer state, connected accent, unread badge, tooltip, accessible label, and focus handle. Its 16 px user-group glyph is byte-identical to the checked-out Zed assets/icons/user_group.svg reference at commit d9ad6aff67e47de43abb270d22de75dd950f1b48, isolated under assets/third_party/zed/ with both the repository-level GPLv3 text and the source icon directory's Lucide ISC notice. That icon-directory notice does not enumerate whether user_group.svg is Lucide-derived, so EXEPERT records the ambiguity instead of declaring which license controls the glyph. The production asset source also embeds both notices and THIRD_PARTY_NOTICES.md so the standalone executable retains the legal materials. The collaboration panel remains bottom-right and opens 12 px above the rail.

The visible EXEPERT brand now occupies the first passive status slot instead of the primary title bar. The primary title area remains a native drag surface, its Windows TitlebarOptions title remains EXEPERT, and the detached Inspector and Runtime Log title bars are unchanged. During ambient activity the flexible status slot renders muted ACTIVITY / followed by one accented AMBIENT; its flexible width lets that activity text truncate before collaboration and build controls at narrow sizes.

The adjacent desktop-version-badge also uses EXEPERT's sharp 2 px radius. Collaboration and build-details surfaces are mutually exclusive visually: opening one dismisses the other, but dismissing the collaboration panel does not leave or end the room. Left/Right toolbar navigation moves between the two interactive controls. Benchmark mode omits collaboration and presents the version as non-interactive status text.

Source map

The following local files support this comparison. Symbol names are more durable than line numbers as the reference checkouts evolve.

TopicLocal source
Zed message and thought chunks; raw JSON conversionrepo-reference/zed/crates/acp_thread/src/acp_thread.rs (AssistantMessageChunk, markdown_for_raw_output)
Zed thought expansion policiesrepo-reference/zed/crates/settings_content/src/agent.rs and repo-reference/zed/crates/agent_ui/src/entry_view_state.rs
Zed thought, spinner, message, and tool renderingrepo-reference/zed/crates/agent_ui/src/conversation_view/thread_view.rs
Zed incremental entry reconciliationrepo-reference/zed/crates/agent_ui/src/conversation_view.rs
Zed virtual-list range and measurement enginerepo-reference/zed/crates/gpui/src/elements/list.rs
Zed code-block copy and wrap controlsrepo-reference/zed/crates/markdown/src/markdown.rs
Zed user-group glyphrepo-reference/zed/assets/icons/user_group.svg at d9ad6aff67e47de43abb270d22de75dd950f1b48
Bundled glyph, GPL text, and icon-directory ISC noticedesktop/exepert-desktop/assets/third_party/zed/
EXEPERT shared transcript reconciliation and scroll statedesktop/exepert-desktop/src/ui/transcript.rs
EXEPERT Native and Codex transcript viewsdesktop/exepert-desktop/src/ui/native_chat_transcript.rs and desktop/exepert-desktop/src/ui/codex_transcript.rs
EXEPERT stable Codex Markdown rowsdesktop/exepert-desktop/src/ui/codex.rs
EXEPERT raw-reasoning firewalldesktop/exepert-desktop/src/codex/protocol.rs
EXEPERT authoritative Codex reductiondesktop/exepert-desktop/src/codex/state.rs
EXEPERT Native Chat bounds and message modeldesktop/exepert-desktop/src/chat.rs

No Zed Rust code is copied to implement these lessons. The sole copied asset is the unmodified user-group SVG described above; all surrounding Rust/GPUI components remain original EXEPERT code. THIRD_PARTY_NOTICES.md records its pinned provenance, bundled-file checksums, both potentially relevant upstream license notices, and the requirement for legal review before public release. That attribution is not a claim that either license conclusively applies, that the asset is compatible with EXEPERT's MIT distribution, or that the repository as a whole is license-cleared.