Package Boundaries
Package boundaries are enforced through three signals:
Package boundaries are enforced through three signals:
- Directory taxonomy under
packages/<layer>/<package>. - Nx project tags stored in package manifests.
- dependency-cruiser rules in
.dependency-cruiser.js.
The goal is not paperwork. The goal is to keep browser bundles free of server implementation, keep contracts implementation-neutral, and make future AI agents choose the right package boundary before writing code.
Nx Tags
Each workspace package should carry tags in package.json:
{
"nx": {
"tags": ["layer:feature", "runtime:browser", "scope:os"]
},
"proxos": {
"layer": "feature",
"runtime": "browser",
"category": "features",
"importableBy": ["runtime", "app-package", "app"]
}
}Layer Tags
layer:uilayer:featurelayer:contractlayer:runtimelayer:studio-enginelayer:datalayer:backendlayer:devtoollayer:app-package
Runtime Tags
runtime:browserfor packages that may ship to the browser.runtime:serverfor Node/Workers/backend-only packages.runtime:sharedfor serializable contracts and safe shared helpers.runtime:toolingfor repo tools and generator packages.
Scope Tags
Scopes describe the product area, not the runtime:
scope:osscope:adminscope:founderscope:workspacescope:aiscope:data
dependency-cruiser Rules
The dependency-cruiser config owns hard import boundaries:
- Browser layers (
packages/ui,packages/features,packages/apps) must not depend onpackages/backend. - Runtime packages must not depend on
packages/backendunless an explicit architecture exception exists. - Contracts must not import implementation layers:
ui,features,runtime,backend, or app packages. - Browser packages must not import server data packages such as
packages/data/db. - UI packages must not depend on provider SDKs or server-only SDKs.
Existing package-specific rules remain in place for @prox-os/os-ui,
@prox-os/app-contract, @prox-os/app-registry, @prox-os/os-apps, and the
frontend primitives. The new layer rules make the default posture explicit as
more packages arrive.
@prox-os/connectors and @prox-os/embed-runtime are lightweight App Hub
aggregation packages. They are browser-safe shared runtime packages that may be
imported by app packages. They must stay limited to serializable types, mock
data, and safe policy helpers until real connector clients, sync engines,
permission enforcement, URL intelligence, or screenshot services are designed
behind stronger boundaries.
Browser / Server / Shared / Tooling
| Runtime | Allowed responsibilities | Examples |
|---|---|---|
| Browser | React UI, view models, action intents, mock adapters, Storybook examples. | @prox-os/files, @prox-os/os-ui, @prox-os/os-apps. |
| Server | Provider bindings, DB clients, auth, billing, storage presigners, audit persistence, AI adapters. | @prox-os/db, future @prox-os/auth. |
| Shared | Serializable contracts and manifest data with no environment binding. | @prox-os/app-contract, @prox-os/data-contract. |
| Tooling | Repo generators, static analysis, test helpers, build helpers. | future @prox-os/testing-utils. |
Platform Runtime Product Packages
These packages define the current platform frame. They split platform navigation, Alma, inspection, runtime chrome, and runtime contracts so future agents do not put every visible product surface back inside the app host.
| Package | Path | Layer | Importable by | Owns | Must not own |
|---|---|---|---|---|---|
@prox-os/platform-navigation | packages/features/platform-navigation | Feature | apps/os-shell, browser runtime hosts | Global Platform Navigation, platform frame, Left Panel host, Alma Rail host, platform-level layout state contracts. | Window manager, app lifecycle, backend data clients. |
@prox-os/alma | packages/features/alma | Feature | apps/os-shell, future platform hosts | Alma UI, prompts, command cards, context badges, quick actions, fullscreen mode. | Direct runtime store ownership, secret-bearing model clients, backend execution. |
@prox-os/inspector | packages/features/inspector | Feature | apps/os-shell, future platform hosts | Inspector UI, object/record/app/connector/permission/runtime placeholder sections. | Primary runtime hosting, app launch ownership. |
@prox-os/runtime-chrome | packages/runtime/runtime-chrome | Runtime | apps/os-shell, future runtime hosts | Runtime Command Strip, Runtime Canvas frame, mode surfaces, runtime-facing visible chrome. | Platform navigation entries, Alma command model, server-only permissions. |
@prox-os/os-runtime | packages/runtime/os-runtime | Runtime | Browser hosts, contracts, runtime chrome | Runtime modes, context snapshots, lifecycle/event contracts, singleton versus multi-window capability rules. | React presentation, platform navigation, backend enforcement. |
Studio Engine Packages
Studio Engine packages live under packages/studio-engines/*. They are
browser packages, but they are not generic UI primitives and not user Studio
instances. A package represents a renderer family such as Block, Board, or
Flow, while a Studio instance remains user data.
Extract a Studio Engine package when one of these is true:
- the engine owns a heavy dependency that should not sit in the Shell initial bundle;
- the engine has a stable renderer boundary shared by routes, demos, or future hosts;
- the engine can consume host callbacks instead of importing Shell stores.
Current extracted engines:
| Package | Owns | Dependency ownership |
|---|---|---|
@prox-os/block-studio-engine | Block Studio renderer | BlockNote and block-editor CSS. |
@prox-os/board-studio-engine | Board Studio renderer | Excalidraw and board CSS. |
@prox-os/flow-studio-engine | Flow Studio renderer | React Flow / xyflow and graph CSS. |
apps/os-shell must lazy-load these components. The Shell may pass callbacks
for opening apps, showing context menus, and supplying runtime context, but
engine packages must not import apps/os-shell, private app ids, window
manager state, or Zustand stores.
Desktop, Atlas, Grid, and Ops are not extracted yet. Desktop still depends on
Shell-specific runtime shape. Atlas, Grid, and Ops are lightweight v0 renderers
without enough package-level reuse or dependency weight to justify extraction.
IDE and App Studio are local-only development engines under /dev/studios/*.
Do not extract engines for symmetry alone.
App Category Packages
packages/apps/system-apps is no longer the container for every official app.
Apps are grouped by category package, not one package per app:
| Package | Responsibility |
|---|---|
@prox-os/os-apps | OS-level apps such as App Store, About, Support, System, and Trust. |
@prox-os/user-apps | Personal work, media, health, workspace, and user-owned surfaces. |
@prox-os/user-connector-apps | Mock connector shells and permission-aware source surfaces. |
@prox-os/dev-apps | Developer tools, route maps, and local development workbenches. |
@prox-os/admin-apps | Admin, backend, deploy, and operations control surfaces. |
@prox-os/game-apps | Browser-native games and game collection surfaces. |
@prox-os/founder-apps | Founder, pricing, waitlist, roadmap, and growth surfaces. |
@prox-os/community-apps | Community and community admin surfaces. |
@prox-os/hub-apps | Platform and productized hub cockpit surfaces. |
@prox-os/app-shared | Shared app primitives, manifest helpers, and proxied runtime UI. |
This keeps packages reviewable without creating a package per app. The Shell
registry composes manifests from these packages, while localAppComponents.tsx
maps app ids to components. Category packages should export app components and
manifests from their root barrel and avoid deep imports from Shell code.
Avoiding Provider Key Leaks
Provider SDKs, secret-bearing clients, token refresh logic, presigned upload generation, billing APIs, and DB clients belong in server packages or deployable apps with server runtimes. Browser packages should receive:
- redacted metadata,
- mock data,
- action intent,
- a typed contract,
- or a runtime callback supplied by the app host.
If a browser package needs to display a provider state, create a serializable view model in a contract or feature package. Do not import the provider client.
Keeping Contracts Pure
Contracts must stay safe to import from browser, server, tools, docs, and tests. They should contain:
- IDs and serializable object shapes,
- enums and discriminated unions,
- manifest and capability types,
- event payload contracts.
They should not import React, shell code, app packages, DB clients, provider SDKs, runtime adapters, or environment variables.
Exceptions
Exceptions are allowed only when the import is deliberate and documented. Use one of these paths:
- Add an ADR under
docs/platform/architecture/decisions. - Add a focused note to this document when the exception is broad and ongoing.
- Add a package-specific dependency-cruiser exception with a precise comment.
Do not add a wide ignore rule to make a build pass. The exception should explain why the boundary is safe, who owns it, and when it should be revisited.