Skip to content

feat: calmer, plain-language web UI for everyday users - #683

Merged
pedronauck merged 103 commits into
mainfrom
ui-normie-pass
Sep 29, 2026
Merged

pedronauck merged 103 commits into
mainfrom
ui-normie-pass

Conversation

@pedronauck

@pedronauck pedronauck commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

What & why

CompozyOS was hard to use for anyone who isn't a heavy technical user. Screens were dense, internal terms leaked onto the page (Layer project_profile, Top-K, BM25, Slice 1, configured=true, compozy.loop/v1, "daemon", raw state tokens like waiting-for-input), status colors competed with each other, and several screens hand-built copies of @compozy/ui primitives. This PR is a plain-language, lower-density pass over the whole web/ app. Behavior, routes, HTTP/DTO contracts, config keys and test ids are unchanged; technical detail is still there, one step deeper (a closed Advanced / Technical details section, a tooltip or an inspector) instead of on the first screen.

How it was produced

  1. Audit: 8 parallel read-only audits (OS shell, Loops, Settings, Sessions/chat, Tasks and automation, Marketplace/Knowledge/Vault, Agents/projects/onboarding, and a cross-cutting pass on view transitions, primitive duplication, token hygiene and jargon). About 400 findings, each with a file:line reference.
  2. Implementation: 7 Claude Code (Opus 5.5, medium effort) workers orchestrated with herdr, each in its own git worktree with its own set of files. They did two follow-up rounds: consolidating @compozy/ui primitives, and the remaining shell and session copy.
  3. Integration: I merged every branch here. One QA-scenario text conflict was resolved by hand. I applied the COPY.md/glossary changes, reviewed the diffs and screenshots, and ran typecheck and lint on the combined tree.

Highlights by area

  • Home: the "workspace" label is now "project", the zone header is plainer, the metric labels are plainer, and zero counters are hidden on first run.
  • Agents: one source label ("This project" / "All projects") replaces the three separate pills (Global/Workspace, Layer …, Shadows …). Rows no longer show the raw provider or model id in mono. Overview and Configuration no longer repeat each other. Permission labels match between the create dialog and settings.
  • Sessions/chat:
    • Session states use plain words ("Needs your answer", "Stuck", "Having trouble"), and only states that need the user get a color.
    • Internal markers, queue ids and compozy__* tool names are gone from the transcript.
    • Each status is announced once, not twice.
    • The approval prompt reads as a question ("Allow fraud-ops-agent to run command?", "Don't allow").
    • Empty and error panes use the shared Empty/Alert.
  • Settings:
    • Groups are renamed Basics / Personal / Agents / Advanced.
    • Memory goes from about 45 rows to 3 controls plus an Advanced fold.
    • General moves its internals behind Advanced.
    • The provider dialog opens on a status summary.
    • The MCP table goes from 5 status columns to a single status column (Server | Status | Actions).
    • A new shared SettingsPageState replaces 18 hand-built loading/error states, and raw error text never becomes the headline.
    • The restart notice now uses RestartBanner from @compozy/ui.
  • Loops:
    • Debug strings, CLI commands, digests and compare-and-swap/422 copy are gone from the screen.
    • The catalog and detail pages are calmer, and limit values are plain.
    • MonoTag is deleted in favor of Pill.
    • Hand-built headers, stats and dots now use ListGroup/MetricGrid/StatusDot.
    • Spacing is back on the grid.
  • Tasks and automation:
    • Schedules and events read in plain language ("Every day at 03:00 UTC").
    • There is no green ENABLED pill; only "Disabled" is shown.
    • IDs, CLI commands and event names are in the Inspect drawer.
    • Approval controls appear in one place.
    • The dashboard leads with useful numbers, and queue plumbing sits in a fold.
    • Job detail has a visible on/off switch.
    • Bugs fixed: "Average duration" was showing wait time, and the inbox showed "now ago".
    • Hovering a task now preloads its detail.
  • Marketplace/Extensions: the installed detail is reorganized into What's inside / Setup / Problems / Activity / What it can do / Advanced, mostly closed. Trust is one sentence. Signal colors are reduced. The trust dialog uses ConfirmDialog.
  • Knowledge: a row shows at most one pill. Content renders as formatted markdown, with a "View source" toggle. The overview has 3 rows plus Details. History is closed by default.
  • Vault:
    • Rows show friendly names instead of mono vault: refs.
    • Results appear as toasts.
    • The vault: prefix is added automatically, and the stored value keeps the same shape.
    • The create dialog has two fields, and the CLI footer is gone.
  • OS shell:
    • Layout-sync problems show as one plain menubar pill.
    • The menubar is calmer, and the update button is no longer accent-filled.
    • Desktop cards use one overflow menu.
    • Window and setup error screens no longer print raw error messages.
    • Count badges use Pill.Count.
    • The palette says "CompozyOS isn't reachable right now" instead of "runtime unavailable".
    • "project" is used everywhere.

View transitions

The app had none. Router-level defaultViewTransition is deliberately not used, for two reasons:

  • TanStack commits routes through React.startTransition, so the snapshot would capture the old DOM.
  • In the OS shell every window focus pushes a URL, so the whole desktop would cross-fade.

What this PR does instead:

  • New runViewTransition(update, { types, reduced }) and viewTransitionName(...) in @compozy/ui. React 19.2 stable has no <ViewTransition>, and this helper is the single place to swap to it later.
  • CSS in tokens-runtime.css: the root never animates, pointer events pass through during a transition, and there are reduced-motion overrides.
  • The window manager animates drill-in / drill-out inside the focused window only. Pop is optimistic only when the expected route matches the top of the navigation stack.
  • Local cross-fades for Settings section switches, the provider Overview↔Configure switch and the session pane switch.

New or extended @compozy/ui primitives

  • Disclosure: one generic fold replacing 7 hand-rolled copies (marketplace, knowledge, vault, About, job detail, tasks dashboard, task form).
  • TranscriptDisclosure promoted from web.
  • Pill.Count.
  • EntityDialogHeader with an optional eyebrow.
  • StatusDot info tone.
  • SplitButton actionProps.
  • RestartBanner default label no longer says "daemon".

Each comes with its story and tests.

Copy system

COPY.md §6 and docs/_memory/glossary.md (edited together) gain these surface aliases. They are UI labels only; canonical names stay in code, the wire and the CLI:

  • settings groups → Basics / Agents / Advanced
  • Loop generation → "round"
  • quarantined → "set aside"
  • fork → "Copy and edit"
  • memory dream → "tidy up"
  • extension dev overlay → "local development copy"
  • session status tokens → plain words

The site Loops guides are updated for "Copy and edit".

Screenshots

Every image is a Storybook route story rendered with the same MSW fixtures before (main) and after (this branch), at 1440×900. All 321 route stories were captured on both sides; these are the most representative 25.

Home

Home — before and after

Home — first run

Home — first run — before and after

Agents list

Agents list — before and after

Agent detail

Agent detail — before and after

Agent settings

Agent settings — before and after

Sessions

Sessions — before and after

Session — approval

Session — approval — before and after

Settings — Memory

Settings — Memory — before and after

Settings — General

Settings — General — before and after

Settings — Providers

Settings — Providers — before and after

Settings — MCP servers

Settings — MCP servers — before and after

Loops catalog

Loops catalog — before and after

Loop detail

Loop detail — before and after

Loop editor

Loop editor — before and after

Loop run

Loop run — before and after

Tasks dashboard

Tasks dashboard — before and after

Tasks list

Tasks list — before and after

Task detail

Task detail — before and after

Jobs

Jobs — before and after

Trigger detail

Trigger detail — before and after

Knowledge

Knowledge — before and after

Vault

Vault — before and after

Vault — new secret

Vault — new secret — before and after

Marketplace — installed

Marketplace — installed — before and after

Extension detail

Extension detail — before and after

How you verified it

  • bunx turbo run typecheck --filter=./web --filter=./packages/ui on the fully merged tree: pass (3/3).
  • bunx oxlint --deny-warnings on all 735 changed TS/TSX files: exit 0. Pre-commit oxfmt and oxlint passed on every commit.
  • Each worker ran the vitest suites for its own area. Examples: Loops 932 tests, Tasks and automation 912, Session and assistant-ui 1,155, OS runtime/menubar/palette 351, Settings 181 after the group rename, and packages/ui for the new primitives, including new view-transition helper tests and window-manager guard tests (animates on push in the focused window; does not animate on focus change or with reduced motion).
  • Visual check: 321 route stories captured before and after with the eng-ui-screenshot CDP helper, and representative pairs reviewed by eye.
  • Not run locally, on purpose: make gate, E2E/Playwright and the full web suite. The heavy lanes run in CI. Playwright specs and docs/qa/scenarios that quote changed strings were updated to the new copy but not executed here. This PR is delivered only once CI is green.
  • Home route story fix: /api/observe/overview had no MSW handler, so the Home story showed "Failed to fetch" on main. This PR adds a typed fixture (story mocks only) and re-captured the "before" Home with it.

Impact

  • Web surface: yes, broadly (copy, density, layout). No routes, HTTP/UDS DTOs, CLI verbs, config keys or compozy__* IDs change. User state is untouched.
  • Docs: COPY.md and glossary aliases added; site Loops guides updated for "Copy and edit"; affected docs/qa/scenarios updated and reset to untested where behavior changed.
  • Cross-surface audit:
    • Native tools: none.
    • Extensibility, hooks and config: none.
    • Workspace data isolation: none.
    • Official skill (skills/compozy/): none; it drives CLI/HTTP, not UI labels.
  • Follow-ups and owner decisions, intentionally not done:
    • Remove or fold the Go menu.
    • Merge the Loops/Jobs/Triggers dock launchers (COPY.md keeps these pending the owner's decision).
    • Hide worktrees from non-technical users.
    • Merge the nearly identical text-subtle / text-faint tones: a token change that needs design sign-off.
    • Collapse the composer's Queue/Steer/Interrupt into one SplitButton: blocked on dropdown items that can be disabled and stay mounted. actionProps landed as the first step.
    • Phase 2 shared-element transitions (list row → detail header).
    • Delete unused components (SkillExposePanel, SessionVaultPanel, RuntimeConnectionIndicator).

  • make gate passes locally; this PR is delivered only after its required CI checks are green. (Gates delegated to CI by request, see above.)
  • New or changed behavior is covered by tests, or I explained above why not
  • If an agent wrote or co-wrote this, I named it above and verified the result myself

🤖 Generated with Claude Code

pedronauck and others added 30 commits September 28, 2026 12:06
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Humanize schedules and trigger events, badge only exceptions (Disabled,
managed source), sentence-case run statuses, add a head enable switch to
job detail, and fold scheduler internals into Advanced details.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rows and cards title secrets by name with the ref path as meta and the
full ref in the hover title; the empty kind placeholder and namespace
tone pills are gone. The security note drops the triple counts, save and
delete confirm with toasts instead of a dismissable banner, and typed
delete confirmation asks for the friendly name. The create hook now adds
the vault: prefix to a bare name before the unchanged PUT request.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The create dialog is Name + Secret value with a live saved-as preview and
the optional label behind More options; one hint replaces the section
help and boundary notice. The sheet uses the shared copy button, a ghost
close button with a focus ring, an Updated/Created fact list, a single
Saved/Missing word, and a plain delete foot instead of the CLI footer.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
One plain permission vocabulary shared by create, settings, overview and
configuration; fleet rows drop layer provenance and the provider meta
segment; Overview keeps Setup + Live sessions on the shared Panel;
Sessions tab uses filter counts instead of a second stats grid, drops the
Iterations column, and gains a Retry action.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Approval is decided once in the window head; the rail and run pages drop
raw ids, CLI hints, and event-type microtext (kept behind Inspect); the
subhead keeps only exception pills and freshness; operator verbs read in
plain language.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Rows show one plain type word and at most one Outdated pill, single-scope
lists render flat, and search reads as "Search knowledge" / "N matches".
Detail leads with the memory name and description, renders content as
markdown with the source one toggle away, keeps three overview rows, and
moves the remaining facts and the decision history into closed folds.
Edit/Delete sit in the header; delete confirms by typing the memory name.
Copy aliases workspace to project and drops controller/runtime jargon.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…utralize the live chip

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…sions, and marketplace settings

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Replaces internal strings (wire fields, CLI hint, digest, debug query)
with plain copy, aliases generation as round and quarantined as set
aside, snaps the run page to the shared gutter and 4px grid, unifies
run durations, and crossfades Inspect tabs with runViewTransition.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
pedronauck and others added 16 commits September 28, 2026 14:12
…nts below complexity limits

Resolve the React Doctor findings in the ui-settings slice by extracting
focused child components and hooks instead of suppressing the rule:
move generalUpdateNeedsAttention into its own module, split the update,
providers, MCP authorize, provider detail/inspect views, RestartBanner,
and SplitButton into cohesive pieces, and move the provider editor tier
state into hooks/.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolve the React Doctor no-high-complexity-react-function findings in the
loops slice by extracting render branches into child components and moving
derivations into pure lib helpers (binding counts, editor node readouts,
node verb commit mode, request context blocks) with lookup tables in place
of if-chains. Behavior, copy, test ids and props contracts are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…mand

The UI pass moved the chord into a styled tooltip and dropped the native
title, which also removed the only machine-readable signal that the palette
keymap had hydrated. Derive aria-keyshortcuts from the live palette.open
binding and wait for it in the E2E navigation fixtures.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolve React Doctor no-high-complexity-react-function findings across the
tasks system and the OS tasks app by extracting per-state render branches
into child components, moving the task-card meta derivation into a pure
view-model helper, the completed-run result lookup into a hook, and the
catalog mode views into their own module. Behavior, copy, and test ids are
unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The UI pass kept every raw error off the setup gate, which also hid the
daemon's fixed non-loopback HTTP refusal and claimed CompozyOS wasn't
responding. A 403 from onboarding now shows the daemon-authored message;
other failures keep runtime messages off screen.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Follow intentional copy, fold, and markup changes: composer ids on
data-detail, update phase on data-phase, source badge words, settings nav
order, Advanced folds, bell pill count, Home first-run state, and renamed
empty/permission copy.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
…iews

Extract focused hooks, pure view-model helpers, and render-branch
components so every React Doctor no-high-complexity-react-function
finding in this slice lands at or below the 15/15 threshold, with no
behavior, copy, test id, or prop-contract change.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Settings nav order, update phase on data-phase, and the palette chord on
aria-keyshortcuts instead of the removed native title.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolve react-doctor no-high-complexity-react-function for AgentAuthoredFileEditor,
AgentCommandSelect, AgentSettingsRuntimeSection, AgentStatsGrid, useHomeSystem,
GatewayAuditPanel, useOnboardingDefaultModel, AgentDetailLocation,
AgentsCatalogLocation, RuntimeSelectorTrigger, and WorktreeRow by extracting
focused child components, topbar hooks, and pure view-model helpers.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@greptile-apps

greptile-apps Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Rewrites UI text and labels across the web interface.

The PR is not yet ready to merge because the previously reported QA-verification requirement remains unsatisfied.

Findings

  1. P2 Delete confirmation loses identity ▶
  2. P2 Fast responses skip transitions ▶
  3. P2 Changed scenarios remain unverified ▶
Summary

This PR makes the web UI less technical and less dense, adds shared UI primitives and scoped view transitions, and updates related tests and QA scenarios. Since the previous review, the change is limited to cold-daemon palette E2E copy assertions.

Reviews (3) · Last reviewed commit: "test: align the cold-daemon palette E2E ..."

@@ -227,26 +214,24 @@ function VaultDeleteDialog({
onConfirm,
}: VaultDeleteDialogProps) {
const sessionScope = target ? isSessionScopedVaultRef(target.ref) : false;
const confirmTypingValue = target && !sessionScope ? target.ref : undefined;
const title = target ? vaultSecretTitle(target.ref) : "";
const confirmTypingValue = target && !sessionScope ? title : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Delete confirmation loses identity

For non-session secrets, the user now types only the last part of the name to confirm deletion. vault:providers/openai/api-key and vault:mcp/server/api-key both accept api-key, so the typed check no longer confirms which secret the user intends to delete. The full name is still shown in the dialog, but this weakens the safeguard against deleting the wrong secret.

Comment on lines +183 to +190
const applyIntent = () => {
// A transition's update runs a frame later; never resurrect a settled intent.
if (settled) return;
windowManagerStore.trigger.routeIntentSet({ intent: { id: intentId, windowId: id, route } });
this.publish();
};
if (transition && this.animatesInWindow(id)) {
void runViewTransition(applyIntent, { types: [transition] });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Fast responses skip transitions

The command starts before the browser runs the transition update. If the command finishes first, settled makes that update skip the route change, so the in-window drill animation is lost. The current tests run the update immediately and keep the command pending; covering the opposite order would protect this transition.

Knowledge Base Used: Web application

expected: Overview Setup panel lists Model (live selector) and Permissions in plain language (no Command row, no At a glance rail); Instructions AGENT.md renders markdown prose without a meta strip and SOUL/HEARTBEAT tabs carry no missing-file warning pills; Configuration Runtime shows "Defined in" with layer/override provenance, Access lists Allowed/Blocked tools and Tool groups as neutral pills, and MCP uses hairline rows; Sessions empty New session opens the launch dialog and, after creation, navigates through the created session owner workspace to its composer.
entry_points: web /agents/$name?tab=overview|instructions|configuration|sessions
qa_status: pass
qa_status: untested

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Changed scenarios remain unverified

This scenario has updated expectations but is marked untested; the PR also says the affected browser scenarios were not run locally. The repository requires changed user-visible behavior to have its affected QA scenarios both updated and verified before delivery. Please satisfy that requirement before merging. The changed marketplace and Vault scenarios show the same unverified pattern.

Context Used: CLAUDE.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@pedronauck
pedronauck merged commit ecb3abc into main Sep 29, 2026
50 checks passed
@pedronauck
pedronauck deleted the ui-normie-pass branch September 29, 2026 02:22

This branch was previously deployed

1 inactive deployment
Preview — 242d3cd9 Deployed Sep 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant