Skip to content

[Feature] UI rewrite v2: replace packages/app + packages/ui with kit-based design #348

@Astro-Han

Description

@Astro-Han

What task are you trying to do?

Rewrite the desktop frontend (packages/app + packages/ui) end-to-end against the Claude-Design-derived kit, so that the UI feels coherent (today the right panel, context view, session sidebar, settings all feel patched), the underlying stack matches 2026 best practice (Solid + Tailwind v4 + Ark UI + TanStack Router + Effect Service), and the visual + structural foundation can absorb 12+ months of feature work without accreting more "patch on patch" debt. Backend (packages/opencode, core, plugin, function, sdk, shared, util, desktop-electron, desktop-api.ts) stays untouched.

What do you do today?

Today's frontend grew layer by layer. Concrete pain:

  • Sidebar logic split across 5 files (pawwork-sidebar.tsx + sidebar-workspace.tsx + sidebar-project.tsx + sidebar-items.tsx + sidebar.css). Adding any sidebar feature requires touching 3+ files.
  • Context view split across 4 files (session-context-tab.tsx + session-context-breakdown.ts + session-context-format.ts + session-context-metrics.ts).
  • 313 source files in packages/app/src with no clear feature boundary; 72 files exceed 200 lines, 23 exceed 500 lines, largest is pages/layout.tsx at 2392 lines.
  • Visual inconsistency between surfaces because each grew opportunistically rather than against a token spec.
  • Performance ceilings unaddressed: zero virtualization (grep virtual packages/app/src returns 0), zero IntersectionObserver, no requestAnimationFrame batching in token-streaming render path. Long sessions feel laggy on baseline hardware.

Workaround today: small targeted refactors per painful surface, which is exactly the "patch on patch" the rewrite would end.

What would a good result look like?

  • One coherent visual system across shell, sidebar, session, settings, dialogs, sourced from kit's colors_and_type.css tokens.
  • Feature folders with clear public API (sidebar/, session/, settings/, composer/, etc.), each self-contained with its own README.
  • Stack aligned with 2026 best practice: Solid (kept) + Tailwind v4 + Ark UI + TanStack Router + Effect Service for business logic.
  • 60fps streaming experience on baseline hardware via virtualization + RAF batching + lazy mount.
  • All 100 existing .test.* files preserved as the regression net.
  • Future feature work can land in one feature folder without touching others.

What would count as done?

Architecture decisions locked (30 items):

# Dimension Decision
1 Boundary Rewrite: packages/app + packages/ui. Keep: opencode + core + plugin + function + sdk + shared + util + desktop-electron + desktop-api.ts
2 Framework Solid (kept)
3 Styling Tailwind v4 + @theme injecting kit colors_and_type.css
4 Component primitives Ark UI replacing Kobalte
5 Router TanStack Router (Solid adapter)
6 Business layer Hybrid: IPC / state machine / error recovery → Effect Service; hover / scroll / view-local → Solid signal
7 Multi-end Desktop-only, no responsive
8 File organization Feature folder, kebab-case (no pawwork- prefix)
9 AI-friendliness <200 lines soft + per-feature README (Purpose / Public API / State Model / Dependencies) + tsdoc on exports
10 Perf budget Cold start <1.5s + streaming 60fps + Intel Mac/4GB Win compat
11 Animation Pure CSS restrained (kit spec: 100-150ms ease-out, no spring/bounce)
12 i18n All keys preserved, only rewrite t() calls
13 Tests 100 .test.* all preserved, adapt to new API
14 Icons Full rewrite per kit (79 done, ~1-2h to finish)
15 Theme Dual (dark/light) + token architecture reserves user-customizable override
16 Shortcuts Global registry + cmd+K palette
17 tool-call rendering Registry + <ToolCardShell>, MCP runtime register
18 Right panel Skip in 5-day window, future PR after Claude Design finalizes
19 Settings vs Dialog Settings = full surface, dialog = quick action
20 session/ 63 files Full rewrite
21 Old/new coexist packages/app/src/v2/ during rewrite, switch entry on Day 5
22 Dependency lock Day 0 lock current stable versions, no upgrades during 5 days
23 PR strategy Single PR + multi-commit
24 dev branch Normal PR flow continues, worktree daily-rebases to dev
25 Worktree claude/ui-rewrite-v2, EnterWorktree
26 AGENTS.md Update line 60 (packages/ui carve-out fact) directly during rewrite
27 Plan tracking This issue (umbrella), no separate plan markdown
28 Timing Day 0 = 2026-04-30 evening, Day 1 = 5/1, Day 5 = 5/5
29 Ready-to-merge 100 tests pass + bun dev smoke pass; Windows VM verification post-merge Day 6+
30 Day 0 today Discussion + this issue creation only, no code

5-day plan sketch:

Day Scope
1 Delete old packages/app/src/{components,pages,styles,theme}/** + packages/ui/src/{components,styles}/** is NOT done up-front; instead build new in packages/app/src/v2/. Day 1: install deps (lock versions), port kit styles.css to ui tokens via Tailwind v4 @theme, scaffold v2 Shell + Sidebar + Home (kit JSX → Solid 1:1)
2 Session view shell + Composer; rewrite pages/session/ 63 files as Effect Service + Solid signal hybrid; include message list virtualization + token RAF batching
3 Settings 8 panes (kit-given) + 16 dialogs rewritten via templated <DialogShell>
4 Permission flow + terminal panel + review-change-mode + file-tree; include tool-call lazy mount via IntersectionObserver; tool-call registry + <ToolCardShell>
5 Switch entry point from old to v2; delete old src/{components,pages,styles,theme}/**; smoke test; regression fixes; follow-up issue list for unfinished items

Required perf scope (must ship within rewrite, not deferred):

  • Message list virtualization via @tanstack/solid-virtual or @solid-primitives/virtual. Switching to a 500+ message session stays <100ms.
  • Token streaming RAF batching. A burst of 50 deltas in one frame triggers a single render pass.
  • Tool-call cards lazy-mount via IntersectionObserver. Off-screen cards keep only a placeholder in DOM.

Acceptance criteria:

  • All 30 architecture decisions reflected in the merged code.
  • All 100 existing .test.* files pass without modification (or with adaptations that preserve original behavioral assertion).
  • bun dev cold-start launches in <1.5s on M-series Mac.
  • Long-session (200+ messages) scroll holds 60fps with Chrome DevTools recording attached.
  • Manual smoke checklist (10 golden-path scenarios) passes on Day 5.
  • Windows VM packaging smoke verified Day 6+ (post-merge).
  • AGENTS.md line 60 updated to reflect packages/ui carve-out.

What should stay out of scope?

  • Backend rewrite (packages/opencode, core, plugin, function, sdk, shared, util).
  • Electron main process (packages/desktop-electron) and IPC contract (desktop-api.ts) — both stay untouched.
  • Right panel new design — handled in a separate follow-up PR after Claude Design finalizes.
  • tool-call visual redesign beyond the registry/shell architecture.
  • Mobile or responsive layouts.
  • Web mode anything beyond dev:web preview.
  • Plugin subsystem [Feature] Tighten plugin and external-skill loading in PawWork mode #263 — separate effort that benefits from the registry foundation but is not blocked by it.

Extra context

Status: not committed. This issue captures the locked architecture decisions and scope from the design discussion held 2026-04-30, but the go/no-go decision is still open. ROI analysis surfaced these tensions:

  • Pro: solves "patch on patch" structurally, gives substrate for design iteration, aligns stack with 2026 practice, solo-dev with no external paying users → low blast radius
  • Con: 5 days of high-intensity execution during a holiday window, no user-visible feature delivery, short-term bug risk during transition, opportunity cost vs feature/marketing work
  • Mitigation: worktree (claude/ui-rewrite-v2) does NOT merge to dev unless ready-to-merge criteria pass; old code stays live until Day 5 entry-point switch; rollback is real

If decision is "do it": Day 0 starts evening of 2026-04-30 with dependency install + version lock + baseline measurement; Day 1 starts 2026-05-01.

If decision is "defer": the three perf items above (virtualization + RAF batching + lazy mount) still ship as independent PRs, since they're independently valuable.

If decision is "kill": close issue, keep current frontend, revisit when product velocity hits a structural ceiling.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low priorityappApplication behavior and product flowsenhancementNew feature or requestuiDesign system and user interface

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions