Campus app packages
Every bundled Campus app uses the same schema-9 package. frontend, workload, persistent data, background execution, interfaces, public routes/ports, secrets, Agent behavior, and economic abilities are optional components. The manifest has no delivery class, native route, creation kind, or Agent-app discriminator.
The product model is Unified Campus application model. Hosted source, seller, build, registry, pricing, and release concerns are in Campus application packaging and Store.
Repository layout
Bundled packages are discovered under packages/campus-*/campus.yaml:
packages/campus-name/
├── campus.yaml
├── frontend/ # optional UI
│ ├── index.html
│ └── optional assets
├── Dockerfile # required only when a local workload image is built
├── backend/ # optional workload source
├── AGENTS.md # optional publisher instructions
└── agent/ # optional private Agent skills/contextThe manifest is the source of truth. Catalog metadata must not be duplicated in Clojure code. Package IDs, catalog order, workload image names, and explicit frontend origins are unique.
Minimal UI-only app
schemaVersion: 9
catalogOrder: 10
id: campus-home
name: Home
version: 0.1.0
publisher: Campus
summary: Launch apps without starting a Node workload.
category: System
icon: "◆"
systemSupplied: true
defaultInstall: true
frontend:
entrypoint: index.html
chrome: always
theme: dark
tint: campus
permissions:
- id: apps.catalog.read
reason: List the applications available to this account.
- id: apps.lifecycle
reason: Open applications selected by the user.Minimal UI-less workload app
schemaVersion: 9
catalogOrder: 900
id: campus-background-sync
name: Background Sync
version: 0.1.0
publisher: Example
summary: Synchronize data without an interactive UI.
category: Utilities
icon: "↻"
defaultInstall: false
workload:
type: firecracker
image: example/background-sync:0.1.0
port: 3000
dataPath: /data
persistentData: trueThis is still a Campus App. Store displays its declared components, Home and Store route management to Settings instead of opening an iframe, and its workload, schedules, endpoints, MCP tools, and economic abilities remain available through their normal permission boundaries.
Omitting workload is a complete steady state. Campus installs the app principal, serves its content-addressed frontend, and reports workload state absent; it does not create a fake container or installation error.
Hybrid app
schemaVersion: 9
catalogOrder: 100
id: campus-notes
name: Notes
version: 1.0.0
publisher: Example Studio
summary: Fast notes UI with private Node persistence.
category: Productivity
icon: "◇"
defaultInstall: false
frontend:
entrypoint: index.html
origin: http://campus-notes.localhost:8090
chrome: auto
theme: light
tint: campus
workload:
type: container
image: campus-notes:dev
port: 3000
dataPath: /data
permissions:
- id: search.index
resources: [self]
reason: Publish note titles into the owner's private Campus search index.Opening Notes loads the frontend before Campus starts or locates the workload. A workload request uses the SDK's progressive connection path and leaves the iframe mounted.
Declared UI and revisions
When frontend is present, frontend.entrypoint must be a safe package-relative file inside frontend/. frontend.chrome is auto, always, or never; the trusted shell decides the effective chrome. frontend.theme is light, dark, or both and controls the trusted mobile bars plus the status-bar and home-indicator safe areas. A both app receives the account's resolved Campus theme (light or dark) in its launch descriptor and through live CampusSDK shell-inset events; CSS can react to data-campus-shell-theme on the document root. Fixed-theme apps ignore the account preference. Older packages without a declaration inherit the Campus preference. Campus config supplies the per-app origin when a bundled manifest omits it.
frontend.tint selects the semantic accent recipe without replacing the Campus surfaces, typography, spacing, or component language. Supported recipes are campus, communication (green), finance (orange), intelligence (blue), and claw (the OpenClaw exception). It is optional for user packages and defaults to campus; Campus-supplied packages declare it explicitly. First-party documents mirror the value as data-campus-tint so shared components can consume the recipe in both light and dark themes.
At catalog seed time, Campus hashes every declared UI path and byte sequence into one SHA-256 revision. The active URL is /r/<digest>/<entrypoint> on the app's origin. Packaged files and Developer-published snapshots are immutable under that path and use long-lived immutable caching plus an ETag.
An installation with UI independently stores its active and previous frontend revision. Promotion changes one pointer; rollback swaps the pointers. It never mutates a revision or starts/restarts the workload. A system-supplied package is immutable through the Developer publication API and must be forked to a new account-owned app first.
Schema 9 does not declare browser-installable per-app identity, a PWA start URL, or root-scope service worker policy. Those remain part of the deferred per-app PWA proposal, not arbitrary authority granted by placing a web manifest in frontend/.
Optional workload
workload declares the execution component only:
type: supported runtime driver, currently localcontainerand target Firecracker paths;image: logical development image or immutable published digest;port: private backend port reached only through Gateway;dataPath: writable workload path, normally/data;persistentData: whetherdataPathhas an installation-owned durable volume. It defaults totrue; stateless workloads set it tofalseand receive only activation-local storage.
Frontend code never receives a backend loopback address. CampusSDK obtains an installation-scoped Iroh endpoint ticket and capability only after an admitted action asks to connect. Public HTTP/WS routes and direct UDP ports are separate manifest declarations and still require exact installation grants.
Workload lifecycle
Lifecycle is not package authority. Every workload installation defaults to the user's automatic mode; the user may instead select foreground or always-on and set the automatic idle timeout. Campus derives eligible wake paths from granted interfaces: admitted MCP tools, user schedules, and granted public HTTP/WebSocket routes. A manifest containing the retired background field or background.run permission is invalid. See application lifecycle.
Permissions and interfaces
A manifest permission is the maximum authority an installation may request. Runtime authority is the intersection of the request, the user's stored grant, the calling principal, the exact resource, and the receiving service's policy. Permission entries are mappings with a non-empty app-specific reason.
Optional interface declarations include:
mcp.toolsfor app-owned schema-validated synchronous capabilities;publicEndpointsfor exact HTTP or WebSocket ingress;publicPortsfor named direct UDP protocols;secretSlotsfor exact protected outbound credential injection.
Each mcp.tools contract has a positive contractVersion (default 1). Packages define the contract but cannot select a Campus executor; any recovery fallback is an exact trusted platform binding documented in Campus MCP.
secretSlots are workload-only. Schema validation rejects them when workload is absent because frontend-only apps have no Node-owned recipient key or autonomous secret consumer. At runtime each binding is encrypted to that installation and decrypted only by its local Gateway. See Installation-sealed secrets.
This does not prevent an interactive frontend from requesting intelligence.use. Browser intelligence is mediated by the trusted shell with a separate passkey-protected account recipient and, when necessary, a Campus-owned Gateway-only target; it does not give the package a general secret slot or autonomous credential consumer.
Interfaces belong to the installation principal, not the iframe and not the workload process. Campus performs source-grant, publication/audience, Contacts or selected-user, payment, schema, replay, capacity, and audit checks before waking the executor.
Agent packaging
agent may declare package-relative instructions, a private standard Agent skill package, contextual packs, and worker roles:
agent:
instructions: campus-assistant/AGENTS.md
agentPackage: agent-skills
contextPacks: campus-assistant/apps
workers:
- role: builder
trigger: apps.create
isolation: target-firecracker
- role: forker
trigger: apps.fork
isolation: target-firecracker
- role: devops
trigger: runtime.tune
isolation: target-firecrackerWorker roles are explicit and target-isolated. The trusted create, fork, or runtime-tuning flow starts the selected worker; it receives the target workspace and its own installation authority, not the account chat history or another app's credentials. This worker bootstrap is a control-plane operation. Callable work between installed Agents remains ordinary app-owned MCP. Instructions and context packs guide behavior but grant no capability.
Store submission
Seller uses one reviewed flow for Campus Apps, MCP listings, and services. App submission captures the complete schema-9 package rather than only its UI. Campus validates a bounded snapshot, recomputes its artifact digest, verifies a declared UI against the active promoted revision, and records UI, workload, Agent component, permissions, interfaces, public routes/ports, economic abilities, and secret-slot declarations in the immutable release.
Personal Agent routes a natural-language submission request through its app-submitter readiness workflow and opens Seller with the trusted owner-local app action. Seller still owns the review and confirmation, keeping Agent guidance and manual submission on the same backend contract.
An ordinary workload release either runs its declared image or declares a bounded build context and Dockerfile. Store sends build-source releases through Campus Build and pins the resulting image and provenance to the immutable release. Developer produces that build form. Developer releases that explicitly use the pinned campus-app-builder:dev layer use workspace-seed materialization. Buyer tokens, grants, private data, and lifecycle settings remain installation-owned.
Store has one Campus App section. Structured component declarations describe whether an app has UI, workload, Agent behavior, endpoints, or economic abilities; every installation remains a Campus App. MCP listing is independent: Seller may expose an already-public app-owned tool in Store discovery, but cannot widen its audience, grants, schema, executor, or admission policy.
System-supplied and default installation
systemSupplied: true means Campus publishes and can restore the stock revision. It does not imply frontend-only or trusted execution. defaultInstall: true creates the installation and manifest grant snapshot during account setup, including before Node/payment provisioning.
masterInstall: true is reserved for Campus-published packages in the Administration category. Those packages are not installed for ordinary accounts; platform assignment installs them for the durable master account, restores their complete packaged grants, and starts their workloads. Master authority still comes from the singleton platform-account assignment, never from the account name or category text alone.
visibility controls who can access a package: public packages are shared while assigned packages are private to their owning account. Discovery is an independent concern. Setting discoverable: false keeps an app in the trusted launcher catalog but omits it from Home, Store, and global search. The app remains ordinary, isolated, and launchable through an explicit shell control, such as the notification bell.
The current default set is Home, Wallet, Store, Personal Agent, Contacts, and Settings. Home, Store, Contacts, and Settings omit workloads. Wallet and Personal Agent declare optional workloads, but their interfaces still install and open before those workloads are funded or ready.
Validation and build checks
node scripts/verify-packages.mjs and catalog loading reject unsafe/missing frontend paths, duplicate identifiers, invalid origins, unknown permissions, inconsistent route/port/secret grants, malformed schemas, retired lifecycle fields, unsafe agent paths, and unknown worker role combinations.
Local build tasks derive OCI workload images only for packages that declare workloads. /data, local Runtime state, Iroh private keys, user credentials, and production secrets are never package content. Store artifact digests and append-only release records are implemented. Production immutable source commits, attestation/signing, SBOM and scan results, and external artifact retention remain required before accepting arbitrary hosted-source builds.