Skip to content

Refactor App.tsx god render-root into a thin composition root + surface registry #494

Closed

Description

@Juliusolsson05

Problem

src/renderer/src/app/App.tsx is a god render-root: 1152 lines, 52 imports, ~34 feature surfaces mounted directly (every modal / panel / overlay: AgentActivityModal, PathPickerModal, TileTabsModal, RewindToPromptModal, BulkProviderSwitchModal, the 5 debug panels, SpotlightView, VoiceDictationOverlay, UsageModal, …), plus 13 root useEffects wiring cross-cutting concerns.

The state is not the problem (only 6 useState — most state is in the store). The problem is that App.tsx is a manual mount-list for every feature UI in the app + a dumping ground for cross-cutting effects. Every new feature edits App.tsx, so it only ever grows, and "the app shell" is inseparable from "every feature's surface."

Proposed restructure

1. Surface registry, not a mount-list. Each global modal/overlay/panel self-registers { id, when(state), Component }; App renders one <GlobalSurfaces/> that maps the registry. Adding a surface = a new file, zero App.tsx edits. Group them:

  • <GlobalModals/> — path-picker, tile-tabs, rewind, bulk-switch, reorder-tabs, close-old-agents, view-mode-picker, …
  • <GlobalOverlays/> — dispatch-count, new-agent-placement, voice-dictation, …
  • <DebugSurfaces/> — the 5 debug panels; only mounted when dev-debug is on, so they leave the production tree entirely.

2. Effects → feature hooks. The 13 root effects (keybinds, IPC wiring, focus, incident hooks, …) each move to their owning feature as a useXxx() hook. App calls a handful of named hooks instead of inlining 13 effect bodies.

3. App.tsx becomes a thin composition root (~120 lines): providers → layout shell (TileTree + bars) → <GlobalSurfaces/> → a few orchestration hooks.

Acceptance

  • App.tsx under ~150 lines; no direct feature-surface imports (they route through the registry).
  • Adding a modal/overlay requires zero App.tsx edits — a new registry entry file only.
  • Debug surfaces mount only under dev-debug (never in the prod render tree).
  • No behavior change — pure extraction; renderer tests + a manual pass confirm every surface still opens.

Companion to the app-wide layer-isolation refactor (the ingest → decide → render separation) — same theme: to add a feature, you must not have to edit a shared god-file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions