Unified Campus application model
Status: implemented application model, with production CDN/signing, bounded Wallet recovery, richer workload diagnostics, and hosted Store release infrastructure called out as remaining work.
Central decision
Campus has exactly one product and installation object: the Campus App.
A Campus App may declare a UI, workload, persistent data, background triggers, public endpoints, typed actions, MCP tools, Agent behavior, or economic abilities. Those are independent optional components of the same app, not app classes or Store sections. systemSupplied records publisher provenance and recovery policy; it does not select a different runtime or security model.
Creation, discovery, installation, and Store distribution all use the same Campus App contract. The structured agent declaration means the app contains an Agent component. Omitting frontend means the app has no UI. Both remain ordinary Campus Apps.
The old native versus node classification is absent from the product model and schema-9 manifest. The useful question is not “what kind of app is this?” but “which app component does this operation need right now?”
How the frontend is served
When an app declares a UI, the repository serves it from a dedicated app origin through CampusOS. The active revision URL is content addressed:
https://<app-origin>/r/<sha256>/<entrypoint>Packaged revisions resolve to validated package files. Developer revisions resolve to immutable snapshots stored by CampusOS. Responses use immutable caching and an ETag; a UI installation keeps only active and previous revision pointers. The iframe stays cross-origin from the trusted shell.
In production, the same URL contract should terminate at a CDN backed by immutable object storage. CampusOS remains the authority that selects an installation's revision and issues scoped launch and service capabilities; it should not stream static bytes on the hot path. A Store release should sign or attest the manifest-to-artifact digest. Content addressing is implemented now; release signing and the external CDN/object-store pipeline remain production work.
The app object
An installed app is one account-scoped security principal with one stable app identity and these independent components:
| Component | Required | Purpose |
|---|---|---|
| UI/frontend revision | No | Immutable HTML, CSS, JavaScript, WASM, and static assets served on the app's isolated origin |
| Manifest contract | Yes | Presentation, permissions, interfaces, compatibility, provenance, and optional components |
| Installation | Yes | Account ownership, grants, launch capabilities, audit identity, and selected active revisions |
| Workload | No | Container or Firecracker process for private state, Bark, background work, sockets, or server logic |
| Persistent volume | No | App-owned state attached only when the workload needs it |
| Agent component | No | App-scoped instructions, workers, tools, and autonomous behavior |
| Developer context | No | Target-scoped files, coding session, and Agent worker used to change the app |
| MCP or typed interfaces | No | Named schemas whose execution is bound to this app principal and an explicit executor |
A UI-only app declares frontend and omits workload. A hybrid app declares both. A UI-less app omits frontend and remains installable, manageable, callable, schedulable, and auditable through the same package, installation, permission, update, and economic model.
General durable secrets follow the same component rule: only a workload may declare secretSlots or hold a Node installation recipient key. Browser intelligence is the narrow exception, mediated by the trusted shell rather than app storage. The account has a separate P-256 recipient private key inside a passkey-PRF-encrypted user-secrets bundle, and a frontend-only installation may receive a Campus-owned Gateway-only Runtime target. BYOK can be sealed separately to browser and workload recipients under the same logical provider key. Campus-managed intelligence remains restricted to Campus-hosted placement and is never issued to BYOH. See Installation-sealed secrets.
Installation is deliberately independent of compute activation. Store installation creates the principal and records reviewed grants even when the account has no Node or hosted-compute funding. For apps with UI it also selects a frontend revision. Only a workload start/connect request is gated. This avoids treating Personal Agent, Wallet, headless services, or any future package as a special app class.
Fast UI open and progressive connection
Opening an app that declares UI must never wait for Node placement, container startup, Iroh discovery, or application health. A UI-less app has no open action; Home and Store route it to management while its workload and declared interfaces remain independently usable.
- Campus resolves the account installation and active UI revision.
- The shell immediately loads the content-addressed, immutable frontend on the app's separate origin.
- The frontend consumes a scoped launch descriptor and renders useful UI from cached or Campus-service state.
- CampusSDK reports whether the optional workload is absent, stopped, queued, starting, connecting, ready, or unavailable.
- Only an operation that needs the workload asks CampusSDK to connect. Campus starts or wakes the workload, discovers its Iroh endpoint, authenticates the app installation, and completes the request when ready.
- The frontend remains mounted throughout. It shows operation-specific progress and allows actions that do not depend on the workload.
For UI apps, the launch descriptor and catalog include workload.availability. CampusSDK exposes the same snapshot through campus.backend.availability():
| Field | Meaning |
|---|---|
required | The manifest declares a workload; it does not mean the frontend needs compute |
available | Campus can admit a workload start now |
code | not-required, ready, setup-required, node-unavailable, payment-required, paused, or unknown |
runtimeMode | campus, own-node, or null |
nodeConfigured, nodeOnline | Coarse Node readiness, without exposing its credential or ticket |
fundingRequired, fundingReady | Hosted-compute admission state, without exposing wallet balance |
Apps must branch on available/code, not infer runnability from a wallet balance. Funding is not required for an own Node, a funded hosted account may still be paused or offline, and a visible wallet balance is not itself a valid compute authorization. The snapshot is advisory and can become stale; the start/connect result remains authoritative and retryable after setup or payment changes.
The launch descriptor must be useful before a Node endpoint exists. For a UI app it includes the app ID, installation ID, active frontend revision, shell origin, frontend capability, and declared interfaces. Iroh tickets and workload capabilities arrive later through the SDK connection state machine; they are not on the first-paint critical path.
Campus logical storage is likewise independent of the optional workload. A frontend can create or read authorized account/app resources immediately after authentication, including before Node or payment setup. CampusOS owns metadata and authorization, then CampusSDK transfers bytes directly to the configured content-addressed provider. The local Rust provider and production Spaces provider use the same transfer-grant contract. Home uses this path for the shared wallpaper-family default while retaining an account-scoped browser override and a local first-paint cache. See Campus Drive and logical storage.
Campus Drive is the user-facing encrypted manager on top of that workload-independent primitive. Drive itself uses a workload because its AES-GCM-encrypted private index and revocable share records live on the installation's Firecracker volume. File bytes remain direct logical-storage transfers and are encrypted in the browser before upload. App-private /data remains outside Drive.
Recommended experience targets:
- shell transition feedback within 100 ms;
- cached frontend visible within 300 ms;
- no blank iframe while a workload starts;
- explicit progress after 400 ms for a workload-dependent action;
- retryable, idempotent connection and request behavior;
- the last active frontend remains usable when the Node is offline.
Settings-driven workload warm start
After the authenticated shell is visible, Campus asynchronously warms each installed workload whose App Settings has warmOnCampusOpen: true. The request never delays launcher first paint and does not open an app interface, establish its Iroh data connection, invoke a model, or execute tools. The catalog avoids known-ineligible requests, while the server authoritatively rechecks provisioning, account pause, Node availability, billing authority, and the installation's current lifecycle policy.
Package YAML supplies only install-time lifecycle defaults. Personal Agent opts in with automatic, a 120-second idle timeout, and open-time warming; other bundled workloads remain opt-out unless their operation requires a different mode. The copied installation setting is authoritative thereafter. Selecting foreground necessarily disables warming. Warm-start failure affects only workload readiness; the shell and all workload-independent application surfaces remain usable.
CampusSDK contract
CampusSDK is the common boundary for every app. It should expose three independent planes:
ui: launch context, revision, shell integration, navigation, and appearance;campus: granted Campus services that do not require the app workload;workload: connection state, wake, request, sockets, event streams, and cancellation.
The implemented workload state machine is:
absent | stopped -> queued -> starting -> connecting -> ready
\-> unavailableabsent is a normal terminal state for apps without a workload. SDK calls already distinguish “this app has no workload” from “the workload is unavailable.” Distinct funding, offline-Node, discovery, and health diagnostics are the next refinement; frontends must not permanently infer those conditions from generic network errors.
The app origin never receives the CampusOS session cookie. Launch and frontend-service capabilities are scoped to the exact account installation and app origin; the descriptor names the selected frontend revision and declared services. A frontend cannot widen its installation grants or substitute another app ID.
Common component combinations
These are examples of the one app model, not categories in Store or authorization code.
| App | Frontend behavior | Optional workload behavior |
|---|---|---|
| Launcher | Opens instantly; lists and launches apps through CampusSDK | None |
| Store | Opens instantly; browses manifests and requests trusted install review | None |
| Settings | Opens instantly; invokes step-up and account services through trusted SDK flows | None |
| Contacts | Opens instantly; edits Campus address and admission records | None |
| Notifications | Opens instantly; lists durable events, changes read state, and delegates activation through CampusSDK | None; CampusOS continues badge projection, device delivery, and trusted approval hosting |
| Wallet | Opens instantly; shows funding, policies, cached/public state, and recovery | Bark/Ark operations, private wallet state, address generation, signing, and typed receive actions |
| Personal Agent | Opens instantly, including before payment, with setup and history framing | Persistent account conversation and paid model/tool execution |
| Ordinary interactive app | Opens its last active frontend immediately | Private API, data, background work, sockets, or compute |
| Background integration | Optional; may be managed entirely through Settings and declared interfaces | Event-driven or scheduled workload |
Store may describe declared components and “some actions require compute,” but it must not split the catalog into UI apps, Node apps, or Agents.
Wallet as the reference hybrid app
Wallet proves why frontend and workload must be independent.
The Wallet frontend is system supplied and always opens. It may show setup status, public wallet binding, balances or policy observations safe to retain in Campus services, funding instructions, and exact progress while its workload connects. It is not itself the custody boundary.
The Wallet workload lives on the user's Node. Bark-dependent operations, private wallet material, signing, address generation, and the wallet.receive-address.request executor belong there. The implemented cutover durably claims the encrypted bootstrap and serves the typed receive-address executor. Initial funding activates the Node and permits the already-installed Wallet and Personal Agent workloads to start. Campus should retain only the minimum control-plane records needed for routing, billing proofs, policy enforcement, and recovery; it must not become the durable home for every user wallet merely because ciphertext is self-custodial. After the Node claim, Campus no longer advertises browser-held withdrawal or policy-write authority; finishing those operations inside the Wallet workload is remaining Bark integration work, not a reason to fall back to Campus custody.
A suspended hosted Node must not create a payment lockout. The remaining design work is a bounded Wallet recovery path: either a previously issued non-spending funding descriptor is enough to top up, or Campus grants a short, resource-capped recovery start to the Wallet workload only. The recovery path cannot start Personal Agent or arbitrary user code and cannot authorize spending.
Cross-user typed calls and MCP still resolve the Wallet installation principal. Admission, Contacts/payment policy, schema validation, replay protection, concurrency, and audit happen before Campus wakes its workload. If Bark is needed, the caller observes queued/waking/ready or a typed unavailable result rather than a fabricated native provider.
Campus Developer and instant UI changes
Campus creation opens a Developer Campus App workflow. The developer configures the app's optional UI, workload, Agent component, endpoints, tools, permissions, and economic abilities. The trusted creation or fork flow starts an explicit builder or forker worker in that target app's isolated development boundary. The worker receives target files and task context, not the Personal Agent's private chat history or another app's credentials. Once created, callable Agent-backed work is exposed through the app's ordinary named MCP tools rather than a separate delegation interface.
Frontend iteration must be independent of workload deployment:
- Agent edits a draft frontend workspace inside the target development boundary.
- A live preview updates as files change.
- Campus validates snapshot paths, file count, total size, required entrypoint, and provenance. Content policy and SDK-compatibility validation remain Store/build-pipeline work.
- Campus creates an immutable, content-addressed frontend revision with build provenance.
- A single atomic pointer promotes that revision for the account installation.
- The open app hot-reloads the promoted revision, or a normal reload selects it immediately.
Pure frontend changes do not rebuild or restart the workload. A backend or protocol change produces a separate workload revision and declares the frontend/workload compatibility range. Promotion must be atomic and rollbackable; serving partially written files is forbidden.
Campus-supplied apps are immutable recovery packages. Agent must fork one before changing it. The fork gets a new app identity, installation, grants, revision history, and data boundary. The stock Launcher, Store, Settings, Contacts, Wallet, and Personal Agent remain recoverable.
The last promoted frontend remains available while the development workload sleeps. Further edits may require waking paid target compute, but viewing and using frontend-only behavior does not.
MCP, typed actions, and cross-user calls
Interfaces attach to the app installation, not to the iframe and not to a container type. Each interface has an independent contract owner, policy authority, executor, and consumer surface as defined by the canonical MCP capability ownership model. Each interface names an executor:
- a workload endpoint for ordinary app logic;
- a Campus service executor only for reviewed, system-supplied functionality;
- no executor until an optional component is installed, which yields a typed unavailable result.
Discovery and cross-user invocation continue to intersect source grants, target publication, selected-user or Contacts policy, payment admission, and live account policy. The frontend's availability neither grants an MCP principal nor proves its workload is ready. Wake happens only after admission.
Packaging and revision rules
The manifest has one app shape. frontend, workload, and agent are independent optional components. An installable package and its manifest are required; there is no delivery: native|node or app-kind discriminator.
schemaVersion: 9
id: campus-wallet
name: Wallet
publisher: Campus
systemSupplied: true
frontend:
entrypoint: index.html
chrome: auto
workload:
type: container
image: campus-wallet:dev
port: 3000
dataPath: /data
mcp:
tools:
- name: receive-address
description: Return a fresh receive address.
inputSchema:
type: object
additionalProperties: false
outputSchema:
type: object
required: [ark_address]
properties:
ark_address: {type: string}
additionalProperties: falseEvery future hosted Store release must pin immutable source, any declared UI artifact, optional workload image, manifest, and provenance. The repository already versions UI snapshots independently; independent workload revisions and compatibility ranges remain release-model work. Rollback never mutates a published frontend revision.
Failure and recovery behavior
- The installation retains its previous verified frontend revision for explicit rollback; automatic delivery fallback remains production work.
- Workload start failure does not tear down the frontend.
- Iroh connect failure becomes
unavailableand a later operation can retry without tearing down the frontend; finer discovery states and cancellation remain SDK work. - Requests crossing a reconnect boundary need idempotency keys or explicit non-retry semantics.
- Frontend/workload compatibility enforcement remains release-model work.
- The stock system-supplied launcher is always a selectable recovery revision.
- Pausing an account stops workloads, not access to content-addressed frontends and trusted account controls.
- Uninstalling removes the installation and capabilities; revision retention follows the user's stated data-retention policy.
Implementation status
| Capability | Status |
|---|---|
| Schema-9 optional UI, workload, and Agent components | Implemented; all bundled packages currently declare UI |
| Default system installations before payment | Implemented |
| Store installation before Node/payment; start/connect-only gating | Implemented |
| Structured workload availability in catalog, launch descriptor, and CampusSDK | Implemented |
| Cross-origin iframe launch without compute start | Implemented |
| Lazy CampusSDK workload connection and UI progress states | Implemented |
| Frontend service capabilities while account compute is paused | Implemented |
| Logical storage before Node/payment, with local and Spaces direct-transfer providers | Implemented |
| Launcher wallpaper synchronization through user-owned logical storage | Implemented |
| Immutable Agent snapshots, atomic promotion, rollback, and open-frame refresh | Implemented |
| Wallet private workload and one-time encrypted bootstrap migration | Implemented |
| Wallet receive-address executor on the target workload | Implemented |
| Node-side manual payment and VAS policy signing after bootstrap claim | Remaining Wallet/Bark work; browser authority is disabled after claim |
| MCP and cross-user admission before workload wake | Preserved and covered by broker tests |
| Production CDN/object storage and signed Store release attestations | Remaining production work |
| Distinct discovery/degraded/retry diagnostics | Remaining SDK refinement |
| Frontend/workload compatibility ranges | Remaining release-model work |
| Bounded Wallet-only funding recovery while a hosted Node is suspended | Remaining security/product decision |
| Separately installable per-app PWA | Deferred proposal pending product validation; see Per-app installable web applications |
Acceptance criteria
- The catalog and APIs expose one app model; no user-visible Campus-app versus Node-app type remains.
- Every installed app can render its verified frontend without waiting for Node or Iroh.
- Any available package can be installed before Node/payment setup; installation alone never starts or places its workload.
- Apps without workloads reach a complete steady state without fake installation errors.
- Workload-dependent operations expose deterministic connection progress and typed failures.
- Wallet UI works before funding. After the Node claims Wallet state, private browser signing is disabled; receive-address execution is on the Node and the remaining payment/policy operations must be completed there before they are re-enabled.
- A suspended user can reach a narrowly bounded Wallet recovery path without enabling arbitrary compute. This criterion is not yet satisfied.
- Agent can preview, promote, hot-reload, roll back, and retain frontend revisions without restarting the app workload.
- Frontend promotion cannot change grants, app identity, backend image, or system-supplied recovery packages.
- MCP and cross-user calls preserve the same principal, admission, schema, payment, replay, capacity, and audit checks regardless of whether the executor is already running.