Prox OS Docs
Architecture

Refactor Guardrails

Engineering hub and consolidated anti-patterns: [core-architecture-thinking.md](./core-architecture-thinking.md).

Engineering hub and consolidated anti-patterns: core-architecture-thinking.md.

Purpose

This document records the repository-level guardrails used before large Próx OS refactors.

The current goal is to make future AI-assisted changes smaller, easier to review, and less likely to leak shell behavior into reusable packages.

Checks

Use these checks after refactors:

pnpm lint
pnpm typecheck
pnpm arch:check
pnpm check:file-size

Use this command when the dependency graph should be refreshed:

pnpm arch:update

ESLint Boundaries

The root eslint.config.mjs is the canonical lint configuration.

  • apps/os-shell/eslint.config.mjs re-exports the root config.
  • File size, function size, nesting depth, and cyclomatic complexity are warnings in normal lint.
  • pnpm lint:strict turns warnings into a failing check with --max-warnings 0.
  • React Hooks rules are enabled for React source files.
  • packages/os-ui is blocked from importing shell app code, Zustand, TanStack Query, and app i18n modules.
  • packages/app-contract is blocked from importing React or UI implementation modules.

Dependency Cruiser Boundaries

The root .dependency-cruiser.js owns architecture checks.

Current project-specific boundaries:

  • packages/os-ui must not import apps.
  • packages/os-ui must not import Zustand, TanStack Query, or app i18n concerns.
  • packages/app-contract must not import React or UI implementation code.
  • apps/os-shell/src/apps/** must not import apps/os-shell/src/shell/** internals; use @prox-os/app-contract, @prox-os/os-ui, app-local code, or explicit public adapters.
  • packages/os-apps must not import apps/os-shell/src/apps/*, apps/os-shell/src/shell/*, or apps/os-shell/src/window-manager/*.
  • Development-only diagnostics such as @tanstack/react-query-devtools may stay in devDependencies when guarded by import.meta.env.DEV.
  • Build output and worker temp output are excluded from architecture analysis.

Dependency Graph Notes

The dependency graph shows a few useful signals:

  • The pre-cleanup graph contained generated artifacts from apps/os-shell/dist and apps/api-worker/.wrangler; these make architecture review noisy and are now excluded.
  • apps/os-shell/src/App.tsx is the thin root entry and delegates shell composition to apps/os-shell/src/shell/DesktopShell.tsx.
  • The first mechanical shell split moved window chrome, desktop folders, drawers, overlays, dialogs, route/language helpers, and shared shell constants out of the former monolithic app entry.
  • The second mechanical shell split made apps/os-shell/src/shell/DesktopShell.tsx a small root composition file. Shell state now lives in focused hooks under apps/os-shell/src/shell/state and apps/os-shell/src/shell/settings.
  • Shell rendering is split across apps/os-shell/src/shell/DesktopScene.tsx, topbar/TopBar.tsx, dock/Dock.tsx, and window-manager/WindowLayer.tsx.
  • The window layer now has shell-local window-manager entry points for AppWindow, WindowTitlebar, windowStore, and windowSelectors; the older root window store remains the underlying Zustand implementation for compatibility.
  • packages/os-apps/src/apps/architecture is the package-owned Architecture Observatory and should be used as the reference for app folders that can run from runtime snapshots instead of shell-private imports.
  • Future passes should reduce remaining large function warnings in GlobalShortcuts, DisplayOptionsApp, ShellFloatingMenu, and the shell controller hooks without changing behavior.
  • apps/os-shell/src/apps/AppRuntime.tsx now hosts runtime context and delegates bundled app imports to apps/os-shell/src/apps/localAppComponents.tsx; future lazy loading should evolve that registry rather than expanding the runtime host.
  • apps/os-shell/src/shell/DesktopScene.tsx delegates shell chrome, window staging, and overlays to focused desktop layer components. DesktopOverlayLayer.tsx delegates shortcut, menu, dialog, and system overlays to sublayers.
  • App-facing settings and keyboard shortcut contracts now live in packages/app-contract; generic shortcut hint UI and dialog escape handling live in packages/os-ui.
  • packages/os-ui is mostly leaf UI code consumed by the shell, which is the right direction; it should stay free of shell state and data fetching.
  • packages/os-apps is now the implementation home for most non-core apps. The shell imports package manifests into the registry and package components into the renderer bridge, while the package depends only on app-contract, os-ui, React peers, and package-local code.
  • packages/app-contract, packages/db, and packages/storage currently appear mostly as orphaned or lightly connected modules, which means they are not yet fully integrated into the runtime graph.

Refactor Rules

  • Do not create new files over 500 lines.
  • Files over 500 lines require a split or an explicit architecture note. Files with more than 12 direct local imports should be treated as dependency hubs and split by responsibility when touched.
  • Monitor AppRuntime.tsx, DesktopScene.tsx, and useDesktopShellController.ts closely; new app renderers belong in app registries/loaders, desktop JSX belongs in layer components, and controller-only logic should move into focused shell hooks.
  • AppRuntime.tsx should read registry/manifest data, build runtime context, and delegate local renderer lookup to a component map or loader map. Do not add a large app switch or direct app import list back into the runtime host.
  • DesktopScene.tsx should stay a page-level composition file. DesktopOverlayLayer.tsx should only aggregate menu, dialog, shortcut, and system overlay layers.
  • Do not place API requests directly inside React components; put them under src/api or an app-local api module.
  • Do not store remote server data in Zustand; use TanStack Query for remote data.
  • packages/os-ui must not depend on business state, i18n, react-query, or zustand.
  • Sub-apps must be registered through manifests; do not hardcode app UI inside the shell.
  • Experimental features that are useful to toggle should be exposed in Developer Tools, not only through console-only localStorage edits.
  • Large refactors must produce a migration plan before implementation.
  • Every refactor must update docs/architecture.

Performance Guardrails

The OS Shell is a long-running browser runtime. Refactors should avoid patterns that create cumulative memory, rendering, or iframe overhead.

  • Window state must stay normalized. Do not store large app data inside WindowInstance objects.
  • Heavy app content should move toward lazy loading. The current package-app bridge is static to preserve behavior during extraction, but future renderer maps should evolve toward loaders for larger surfaces.
  • Large lists and tables must use virtualization or a documented pagination/windowing strategy.
  • App data fetching must use TanStack Query or a documented cache boundary. Zustand is for local OS UI state, not remote server data.
  • OS apps must not deep-import OS Shell internals. Use manifests, runtime context, app contract types, or documented adapters.
  • Iframe apps must be sandboxed where practical and loaded on demand.
  • Global event listeners must have cleanup, and long-running timers/subscriptions must stop when their surface closes.
  • Avoid passing large mutable objects through React context. Prefer narrow props, selectors, or query/cache boundaries.
  • Features handling large datasets should consider Web Worker, IndexedDB, streaming, pagination, or server-side aggregation.

AI coding agents should ask before changing shell runtime behavior:

  • Does this create unnecessary re-renders?
  • Does this keep iframe, window, or app state alive after close?
  • Does this mix remote data with local UI state?
  • Does this load all apps upfront?
  • Does this introduce a large dependency into the shell?
  • Does this bypass the app contract?

On this page