App Contract View
The app contract defines how apps are described, launched, permissioned, and hosted inside the OS Shell.
Purpose
The app contract defines how apps are described, launched, permissioned, and hosted inside the OS Shell.
This is the foundation for future local apps, route apps, isolated apps, and community apps.
Initial App Types
Local App
A React component bundled into apps/os-shell.
Use for first-party early apps.
OS Package App
A reusable official app exported from packages/os-apps and imported by apps/os-shell.
Use when an app no longer needs deep access to shell internals but should still run as part of the browser OS bundle.
Iframe App
A local developer tool or external surface hosted in an iframe.
Use for development-only tools such as docs, UI workshop, API explorer, or project graph surfaces before deeper integration exists.
Route App
An app represented by a route or external deployment under the same product domain.
Use for larger apps that deserve independent routing or deployment.
Isolated App Future
An app loaded with stronger isolation boundaries.
Use for community or third-party apps.
Initial Manifest Shape
export type OsAppManifest = {
id: string
title: string
shortTitle: string
icon: string
description: string
category: 'workspace' | 'data' | 'ops' | 'shell' | 'system' | 'developer'
routeGroup: 'app' | 'app-user' | 'app-shell' | 'app-dev' | 'app-iframe' | 'app-os'
routePath: string
runtime:
| { kind: 'local-module'; module: string }
| { kind: 'os-package'; packageName: '@prox-os/os-apps'; exportName: string }
| { kind: 'iframe'; iframeUrl: string; fallbackCommand: string; healthCheckUrl?: string }
| { kind: 'route-app'; routePath: string }
| { kind: 'isolated-app'; sourceUrl?: string }
window: DefaultWindow
permissions: AppPermission[]
}Responsibilities
packages/app-contract owns:
- Manifest types
- Window contract types
- Permission names
- Data scope names
- Runtime context shape for OS app exports, including narrow window actions and readonly window snapshots
- App-facing shell settings and keyboard shortcut contracts
apps/os-shell owns:
- Rendering windows
- Opening apps
- Managing active window state
- Shell-coupled apps that remain under
/app-shell - Adapting shell-local window store state into the app runtime context
- Adapting public settings and keyboard contracts to the shell's local state implementation
packages/os-apps owns:
- Reusable official OS apps that can be imported by the shell
- App folders shaped around
index.ts,manifest.ts,App.tsx,README.md, optionalroutes.tsx,components,hooks,api,store.ts, andtypes.ts
Current package app exports:
- Most non-core OS apps now export both component and manifest from
@prox-os/os-apps. - Each migrated manifest uses
runtime.kind: "os-package"andsourcePackage: "@prox-os/os-apps". - The shell adapts package apps through
apps/os-shell/src/apps/registry.tsandapps/os-shell/src/apps/localAppComponents.tsx. - Shell-coupled control apps such as
Display optionsandKeyboard shortcutsremain local modules until their contracts are stable enough to extract.
apps/api-worker may later validate:
- Permissions
- App installation state
- Data access scopes
Managed links and runtime affordances
AppRuntimeContext.links: optionalopenLinkChoiceAt(href, x, y)— opens the shell managed-link menu (Open in OS / new tab / copy). Use real<a href>in OS apps when possible; the desktop scene captures left-click on OS-resolvable targets.AppRuntimeContext.session: optionalrequestSignIn()— opens the existing sign-in overlay (placeholder auth). Used by the Hola welcome app.- Platform hosts (
packages/app-registry/src/platformHosts.ts):docs.prox-os.com→ docs iframe app,ui.prox-os.com→ UI workshop,api.prox-os.com→ Scalar API explorer. Dev shells use/app-dev/*routes instead. These hostnames are deployment origins, not app primary keys. For deployment and Access boundaries, see cloudflare-deploy-and-access.md and app-namespace-and-domain-strategy.md. - Iframe guests: today use
ProxOsIframeGuestLinkMessage(postMessage) to request the same menu; future work is to align guest links withresolveManagedLinkrules centrally.
Future identity vs launch targets (roadmap)
Current: shell id / appId in the composed registry is the stable in-OS key. routePath, iframeUrl, and platform hostnames are launch targets.
Candidate (not final): server-backed registry with namespace + slug, public paths such as /user/:handle/app/:appSlug, and optional runtime isolation subdomains separate from canonical URLs. Stable appId must survive slug renames (aliases + redirects). Do not use a new second-level subdomain per app by default.
Seed manifest shape and Moments / API / system-app notes: app-namespace-and-domain-strategy.md.
Routing Boundary
- Shell navigation: browser URL, route groups, website-mode variants,
/spaces/:spaceId, window open/focus/close. Implemented with TanStack Router inapps/os-shell; this is OS-level only. - App navigation: entirely inside the window body. The contract exposes only generic hints (
AppRuntimeContext.navigation), never aRoutertype from any library. First-partyos-appsusually mount their own TanStack Router (often memory-based). Third-party stacks keep their router behind an adapter; iframe apps are always isolated.
Design Rule
The OS Shell should not hardcode every app forever.
It should gradually move toward manifest-driven app registration.
App ids should use kebab-case without dots or other punctuation. For example, the Architecture app uses developer-architecture.