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-sizeUse this command when the dependency graph should be refreshed:
pnpm arch:updateESLint Boundaries
The root eslint.config.mjs is the canonical lint configuration.
apps/os-shell/eslint.config.mjsre-exports the root config.- File size, function size, nesting depth, and cyclomatic complexity are warnings in normal lint.
pnpm lint:strictturns warnings into a failing check with--max-warnings 0.- React Hooks rules are enabled for React source files.
packages/os-uiis blocked from importing shell app code, Zustand, TanStack Query, and app i18n modules.packages/app-contractis 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-uimust not importapps.packages/os-uimust not import Zustand, TanStack Query, or app i18n concerns.packages/app-contractmust not import React or UI implementation code.apps/os-shell/src/apps/**must not importapps/os-shell/src/shell/**internals; use@prox-os/app-contract,@prox-os/os-ui, app-local code, or explicit public adapters.packages/os-appsmust not importapps/os-shell/src/apps/*,apps/os-shell/src/shell/*, orapps/os-shell/src/window-manager/*.- Development-only diagnostics such as
@tanstack/react-query-devtoolsmay stay in devDependencies when guarded byimport.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/distandapps/api-worker/.wrangler; these make architecture review noisy and are now excluded. apps/os-shell/src/App.tsxis the thin root entry and delegates shell composition toapps/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.tsxa small root composition file. Shell state now lives in focused hooks underapps/os-shell/src/shell/stateandapps/os-shell/src/shell/settings. - Shell rendering is split across
apps/os-shell/src/shell/DesktopScene.tsx,topbar/TopBar.tsx,dock/Dock.tsx, andwindow-manager/WindowLayer.tsx. - The window layer now has shell-local
window-managerentry points forAppWindow,WindowTitlebar,windowStore, andwindowSelectors; the older root window store remains the underlying Zustand implementation for compatibility. packages/os-apps/src/apps/architectureis 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.tsxnow hosts runtime context and delegates bundled app imports toapps/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.tsxdelegates shell chrome, window staging, and overlays to focused desktop layer components.DesktopOverlayLayer.tsxdelegates 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 inpackages/os-ui. packages/os-uiis 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-appsis 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 onapp-contract,os-ui, React peers, and package-local code.packages/app-contract,packages/db, andpackages/storagecurrently 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, anduseDesktopShellController.tsclosely; 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.tsxshould 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.tsxshould stay a page-level composition file.DesktopOverlayLayer.tsxshould only aggregate menu, dialog, shortcut, and system overlay layers.- Do not place API requests directly inside React components; put them under
src/apior an app-localapimodule. - Do not store remote server data in Zustand; use TanStack Query for remote data.
packages/os-uimust 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
WindowInstanceobjects. - 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?