Skip to content

TUI redesign: Shoreline, one palette across both clients - #6222

Draft
Hmbown wants to merge 10 commits into
mainfrom
tui-redesign
Draft

Hmbown wants to merge 10 commits into
mainfrom
tui-redesign

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Re-inks the TUI to the GPUI client's palette and moves it toward the conventions the terminal-agent market converged on. Draft: the headline item is not done — see "What is left" below.

Pushed primarily because it was local-only. Five of these ten commits are not the redesign at all: they were stranded on a local main that is 129 commits behind origin/main and had never been pushed anywhere — a runtime-api settings-schema route, a config Float setting kind, the web /plugins page, the Computer Use 0.2.2 sync, and the 0.9.13/GPUI-direction doc. Publishing this branch is what rescues them; main itself is untouched and still needs reconciling separately.

The argument

Not aesthetic, structural. AGENTS.md asks for "one coherent runtime, one store, one design system", and TRANSITION.md makes the GPUI app the product client. A terminal that opens on a saturated navy gradient with decorative sea life while the desktop opens on warm charcoal is not two themes, it is two design systems. SHORELINE_UI_THEME cites the same slots codehwhale-gpui/src/workspace/mod.rs:147-164 installs into GPUI's Theme, which collapses that.

underwater is not deleted. It keeps its water column, ombre and ambient life, and stays selectable — it stops being the ground the product opens on.

Why it holds rather than half-applies

  • adapt::theme_remap_active lists both new presets, so all 84 direct WHALE_*/TEXT_* call sites land on Shoreline slots. Without it the frame repaints while every widget keeps its cold grey, which looks worse than not doing it.
  • The mode ramp stays separate from accent_primary. theme_semantic_foreground_role resolves mode slots before the action lane, so equal values collapse the ANSI-16 role matrix. Caught by every_selectable_theme_keeps_mode_badges_distinct, and fixed in the theme rather than the test.
  • Every audited pair clears its contrast floor under contrast::theme_contrast_violations.

What is left, and why it matters

The one-status-row merge is not started. The market survey in docs/design/TUI_REDESIGN.md found exactly one convergent rule we violate — one status row, never two — and it is untouched, so this branch delivers roughly the first half of what the doc argues for. The blocker is real: the metrics line owns the /model and context-inspector pointer targets, so re-homing them has to land in the same commit that hides the row or the slice ships a regression.

Goldens record no colour. golden_harness.rs:27-49 dumps cell.symbol() only, so this entire re-ink is invisible to all 41 golden buffers — and so is the next one. The harness documents an "ink plane" at :84-94 that would close the hole and is unimplemented. That should be in scope here, not adjacent to it: shipping a design system whose correctness is unfalsifiable is the same mistake #6193 identifies for performance, and right now both holes are open.

One product decision: making underwater non-default means the pet and ambient life (#6155, and the in-flight pet_sim/pet_widget work) ship to zero fresh installs. Either the pet gets a home in Shoreline or it becomes a deliberate opt-in. Not a bug — a call someone has to make.

Verification

cargo test -p codewhale-palette --lib --locked — 81 passed, 0 failed, including the contrast floor, mode-badge distinctness, permission-lane and ANSI-16 audits over both new presets (re-run independently on this tree).

Two failures on this branch are pre-existing and unrelated: runtime_api::tests::set_config_rejects_unknown_key_with_bad_request (runtime_api/tests.rs:8250 expects "unknown config key", settings.rs:1758 emits "unknown setting") and tui::views::tests::every_settings_row_reaches_a_store. Both verified present at the branch point 4a85cb7877.

🤖 Generated with Claude Code

CodeWhale Bot and others added 10 commits September 12, 2026 20:54
Vendor canonical Computer Use 85eae07 through the existing embedded plugin.
Keep app observations scoped, use semantic background input, and stop raw
gestures when the user changes focus. Preserve unrelated concurrent Core work.

Validation: matching marketplace runtime passed npm test && npm run check:web:
389 Node tests, 374 passed, 0 failed, 15 platform skips; 4 browser checks passed.
Universal macOS helper compiled and signed. Packaged daemon/MCP background
trials passed with 400 and 195 unchanged foreground/cursor samples.
Core runtime/test mirrors match upstream. Full Core Rust build and installed
Engine/model acceptance were not run; no install, public push or release.
/v1/settings/schema projects SETTINGS_SCHEMA for GUI clients: every
declared row with resolved labels, current value from the owning store,
persisted state, row kind (setting/action/diagnostic/session), and the
TUI's conditional-visibility and editability rules. POST /v1/config's
unknown-key arm now delegates to Settings::set, so every declared
settings.toml key persists through the shared validator instead of a
curated allowlist.

Adds SettingRowKind to the schema, Settings::value/is_set accessors,
and live-server tests covering all 82 rows plus the write fallthrough.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
auto_compact_threshold_percent is stored as f64 (10-100, accepts
"82.5") but the schema declared Int, so schema-driven clients rejected
the served "80.0" as invalid. Add SettingKind::Float, map it to
"float" in the runtime API payload, and declare the threshold row
with it. Clients that do not know "float" fail closed to read-only
text, so this is additive to the v1 schema contract.

Verification: cargo test -p codewhale-tui --lib settings_schema
(3 passed), cargo test -p codewhale-config --lib (704 passed),
native GPUI dogfood shows "Compact threshold: 80.0" as an editable
text field with no phantom unconfirmed-change state.
…copy

New top-nav Plugins surface on the public site: leads with Computer
Use actual capabilities (39 MCP tools, accessibility-first control,
macOS background input, screenshots/OCR, registered-computer switching,
receipts, fail-closed verification, platform qualification status), then
the GitHub-repo marketplace, install sources, and trust lifecycle.

- app/[locale]/plugins/page.tsx + lib/content/plugins.ts (en/zh)
- navPlugins/navPluginsSecondary keys in all 19 chrome dictionaries
- primary nav + footer product link; sitemap registration
- portal-topic-list CSS widened to cover non-link rows
- docs-ia tests updated for 5-link nav and 100-entry sitemap

Gate: 446 tests / 50 files pass; lint clean (2 pre-existing img
warnings); tsc clean; build prerenders /[locale]/plugins for all
locales. check:latest-release fails on pre-existing v0.9.13 sync
drift unrelated to this slice.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
v0.9.13 shipped 2026-09-14 (tag v0.9.13, GitHub release with 34 assets, npm
codewhale@0.9.13, 25 crates on crates.io), and the 2026-09-14 founder
decision (codewhale-ops/CURRENT_DECISIONS.md §14) makes the GPUI native app
the product client while the hosted web app sunsets in phases.

Files:
- README.md + 18 localized README.*.md: clients bullet now names the GPUI
  desktop app as the product-client direction and notes the web-app sunset;
  translation source stamps updated to sha256:ebf1c69de0dc
- docs/INSTALL.md: v0.9.13 source-candidate framing -> published release;
  stale "public latest is v0.9.11" update example fixed
- web/data/latest-published-release.json + docs/public-surface-facts.json:
  refreshed to v0.9.13 (2026-09-14T03:48:56Z) via
  web/scripts/sync-latest-release.mjs; docs/cloud-facts/stable.json release
  pin updated to match; web/lib/facts.generated.ts regenerated via prebuild
- docs/GUIDE.md + docs/zh_hans/GUIDE.md: dated sunset/GPUI-successor note on
  /rc (mechanics unchanged)
- docs/REBRAND.md, docs/AGENT_RUNTIME.md: version snapshots re-dated
- docs/RUNTIME_API.md: dated note that the Tauri desktop shell retires,
  DESKTOP-APP-BRIEF is a dangling pointer, and the GPUI client is the
  successor daemon consumer

Checks (real output):
- python3 scripts/check-readme-translations.py:
  "README translation check OK — 18 translations in sync with README.md
  (sha256:ebf1c69de0dc)" (exit 0)
- bash scripts/check-readme-locales.sh:
  "OK — all linked locale READMEs exist" / "OK — no orphaned locale
  READMEs" / "PASS" (exit 0)
- npm --prefix web run check:facts:
  "[check-facts] OK — committed facts.generated.ts matches workspace"
  "check-cloud-facts: OK (facts_version=1, 1 active production keys)"
  (exit 0)
- npm --prefix web run check:latest-release:
  "[sync-latest-release] already current at v0.9.13" (exit 0)

No issue reference; CHANGELOG receipt not required for docs-only.
The terminal and the GPUI desktop window now cite one palette. Shoreline is
the warm charcoal ground (`#211F23`), one raised plate (`#2B282E`), one
restrained blue for action and selection (`#90B9FF`), Signal Gold for the
human lane, and the whale's ivory ink — the same slots
`codehwhale-gpui/src/workspace/mod.rs` installs into `Theme`.

It ships as two presets (`shoreline`, `shoreline-light`), and it is the
fresh-install default in `Settings::default`, the settings schema, the
theme picker's reset value, and the malformed-selector fallback. The
`underwater` theme keeps the painted water column, the ombre and the
ambient life; it is a choice now, not the ground the product opens on.

Shoreline is listed in `adapt::theme_remap_active`, so every direct
terminal constant lands on the preset's slots instead of a navy-tuned
value. Its mode badges keep the shipped mode ramp: a mode colour must
differ from `accent_primary`, because `theme_semantic_foreground_role`
resolves modes first and would otherwise read the action lane as
`ModeAgent`.

Evidence:
- `cargo test -p codewhale-palette --lib --locked` — 81 passed, 0 failed.
  That includes `every_selectable_theme_clears_the_text_floor`,
  `every_selectable_theme_keeps_action_and_working_roles_distinct_on_ansi16`,
  `every_selectable_theme_keeps_mode_badges_distinct` and
  `every_selectable_theme_keeps_permission_lanes_distinct` over the two new
  presets.
- `cargo build -p codewhale-cli --locked` — ok.
- Real PTY capture of `target/debug/codewhale` on a fresh `CODEWHALE_HOME`:
  field `#211F23`, chrome `#1A181C`, plates `#2B282E`, accent `#90B9FF`,
  muted `#B0A7B2`, gold `#F6C453`. The braille whalemark is unchanged.
- Not yet run: `codewhale-tui` tests. Expected fallout is the
  `theme_picker_*` goldens (two new rows) and tests asserting the old
  default string; reconciled in the next commit.
The repo's brand/mark.svg + wordmark traces were an earlier lower-fidelity
trace of the C-curl whale (black currentColor instead of the navy family),
and crates/tui/src/runtime_web/codewhale-192.png was still the retired
diving-whale tile served by the embedded runtime web client.

- brand/ and web/public/brand/ now carry byte-identical copies of the
  canonical family (codewhale-apps/packages/brand/svg/), adding the missing
  mark-mono and mark-reversed variants.
- extensions/vscode/media/codewhale.svg uses the family mono mark.
- runtime_web/codewhale-192.png is the canonical 192 tile (same bytes as
  codewhale-apps apps/web/public/icons/codewhale-192.png).
- opengraph-image.tsx reads mark-reversed.svg (the family's white-on-navy
  variant) instead of string-replacing currentColor, which the family
  mark.svg does not contain; wordmark aspect corrected to the family's
  1024x160 viewBox.
- Deleted brand/mark-navy.svg (duplicate of the family navy mark),
  brand/wordmark0901.png + wordmarkinverted.png (only consumer was the
  retired generator; founder rasters preserved in
  codewhale-apps/packages/brand/source/), and scripts/brand/trace-brand.py
  (regenerated the retired trace; not referenced by CI). The founder brand
  sheet brand/codewhalemarkfinal.png stays as scripts/brand/braille-mark.py's
  input.
- PRODUCT.md and the public-auth-routes provenance comment updated to name
  the canonical family home.

Checks: npx tsc --noEmit (web) exit 0. Asset swap + comments; runtime_web
route tests reference the icon path, not bytes.
Two new presets mean the theme list is 17 rows where it was 15, and the
fresh-install selector is `shoreline` where it was `underwater`. This is the
expectation fallout, not a behaviour change: the picker's reset value, the
digit-jump and wrap tests, the row-count assertions in both theme-list
suites, and the four `theme_picker_*` / `edit_theme_*` golden buffers.

The digit tests keep their intent. `3` now jumps to Shoreline (it still
follows System and Terminal); the persistence test uses `9` -> Grayscale
because Catppuccin Mocha moved past the 1-9 jump range. The theme-list test
now anchors its boxed selection on index 6 (Blue Stage) since Shoreline and
Shoreline Light sit ahead of Underwater.

Evidence:
- `CODEWHALE_BLESS_GOLDENS=1 ./scripts/dev-test.sh tui theme` —
  56 tests run: 56 passed, 0 failed, 12424 skipped. The four goldens were
  deleted first because `assert_matches_golden` only blesses a *missing*
  file, never a drifted one.
- Running the same filter as a bare `cargo test` (no hermetic HOME) failed
  two tests — `arrow_navigation_wraps_at_picker_edges` and
  `theme_picker_uses_shared_settings_controller` — because they read the
  real user theme directory and saw a `custom:` row. Both pass under the
  sanctioned wrapper; that flake is pre-existing, not introduced here, and
  is named in the handoff rather than papered over.
- `crates/tui/src/tui/views/mod.rs` carried one line of another agent's
  in-flight work (`ModalKind::PetHabitat`). My three hunks in that file were
  staged apart from it; that peer has since committed them into
  `116a57b81` on this branch. The `PetHabitat` line is still unstaged and
  untouched.
The settings stage and the config panel both render the theme list, so both
carry the two new rows. The stage anchors its boxed selection on index 6
(Blue Stage) rather than 4, which is now Underwater.

Evidence:
- `CODEWHALE_BLESS_GOLDENS=1 ./scripts/dev-test.sh tui views::` —
  323 tests run: 322 passed, 1 failed. The one failure,
  `tui::views::tests::every_settings_row_reaches_a_store`
  ("auto_compact_threshold_percent shows a row that settings.toml will not
  take"), is pre-existing on `main` at the branch point: the schema row and
  that exact assertion are both present in `4a85cb7877`, and
  `Settings::set` has never accepted that key. It is not this change.
- `./scripts/dev-test.sh tui-integration palette_audit` — 3/3 passed.
- `python3 scripts/export-design-tokens.py --check` — up to date, 64 tokens.
  The new `SHORELINE_*` constants are deliberately outside the exporter's
  `(WHALE|LIGHT)_*` pattern, so the web's `tokens.css` is untouched.
`docs/design/TUI_REDESIGN.md` is the anchor for this branch: the Shoreline
palette table and the three mechanisms that make the re-ink hold, the
seven-project market survey and its convergent rules, the two things the
survey says we already get right, and the two deliberately not done (the
composer stays full width; the ocean is not deleted).

It also names the remaining work with the seams already located: the
one-status-row merge, and the interaction re-homing that has to land in the
same commit or the slice ships a regression (the metrics line owns the
`/model` and context-inspector pointer targets).

`DESIGN.md` carried two defects this change exposed:

- The palette owner was written as `crates/tui/src/palette/tokens.rs`. That
  path has not existed for some time; the owner is `crates/palette/src/tokens.rs`.
- Anti-slop rule 2 stated that "the ocean column's field is the TUI's own
  chrome → bg descent". That was true of the TUI's default and is not any
  more — the default is Shoreline. The rule now says what is true: the
  column is the site's descent, and the navy water column is the terminal's
  selectable `underwater` theme.

Also records, without fixing, the two failures that pre-date this branch on
`main` at `4a85cb7877`, and the two picker tests that are order-dependent
under a bare `cargo test` because they read the real user theme directory.

Checks: `cargo test -p codewhale-palette --lib --locked` 81/81;
`./scripts/dev-test.sh tui` 12461 run, 12459 passed, 2 failed (both
pre-existing); `./scripts/dev-test.sh tui-integration palette_audit` 3/3;
`python3 scripts/export-design-tokens.py --check` up to date.
Hmbown pushed a commit that referenced this pull request Sep 16, 2026
The merge of feat/shoreline-redesign-rebased-20260915 lands the palette itself;
this is its user-visible receipt, which check-versions.sh requires for a
feature commit that references an issue.

States the part a user needs and the code does not say out loud: existing
installs keep whatever theme they have saved. Shoreline is the fresh-install
default (settings.rs:575), and the only theme migration in the file runs the
other way — it folds a retired `ocean_treatment` key into `underwater`. So an
upgrading user does not switch, and should not be surprised into it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: CodeWhale Bot <bot@codewhale.net>
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