Capabilities
A capability is a runtime behaviour your Surface can opt into: fetching data, routing between Surfaces, persisting client state, running form validation, or wiring blocks into a per-World entity model. Capabilities ship as pwpacks and resolve per World at runtime — there is no global capability table.
Surface = Blocks + Capabilities. Blocks are the visual primitives; capabilities are the runtime behaviours that animate them.
The canonical 5
As of 2026-04-23 the registry contains exactly 5 canonical capabilities.
All other names you may see in older docs (auth, data, state, seo,
i18n, analytics, forms, behaviors) were retired in ADR-094 /
ADR-095 / ADR-110 / ADR-116.
| ID | Pack | Responsibility |
|---|---|---|
platform/persistence | @pwpack/phiwebs/persistence | Data fetch + cache; owns dataSources and initialState in binding config (ADR-124). |
platform/entities | @pwpack/phiwebs/entities | Tenant data model, CRUD, lifecycle. |
platform/navigation | @pwpack/phiwebs/navigation | Client-side routing between Surfaces (ADR-096). |
platform/interaction | @pwpack/phiwebs/interaction | Event-driven rules — attach triggers/actions to Surface events. |
platform/input | @pwpack/phiwebs/input | Form field state, validation, submission. |
platform/appearanceis not a capability. Visual appearance ships as a dedicated atom kind (ui-appearance) through the same publish pipeline. Don’t list it in plan bundles — list the appearance pack (@pwpack/phiwebs/appearance) instead.
Pack bundle model
Capabilities are not toggled individually. They follow the World’s plan bundle — the set of pwpacks installed at plan activation.
Plan activation
→ resolve plan.pack_bundle
→ install each pack
→ record one capability entitlement per capability atom
→ entitlement check: capability marked active?Installed = entitled. Plan upgrade installs additional packs; downgrade soft-uninstalls; re-upgrade reactivates the existing rows.
Default plan bundles
| Plan | Bundle |
|---|---|
| Basic | core-ui · persistence · entities |
| Pro | + navigation · interaction · input |
| Team | Pro bundle + extended pwpacks |
| Enterprise | Pro + custom enterprise packs |
Bundles are versioned with the plan; activating or downgrading a plan syncs the World’s pack set automatically.
Runtime resolution
The kernel registry starts empty per World. The first time a Surface references a capability:
- The runtime resolves a per-World capability lookup function with the
signature
(capabilityId, worldId) => Capability | null. - The lookup reads the World’s active capability atoms.
- The bundle URL is dynamically imported on first use; the exported
defineCapabilitybuilder runs. - The resolved capability is cached per World (5-minute LRU).
This means installing a new pwpack reflects in the live World within five minutes without redeploying anything.
Authoring a capability
Capabilities use the same pwpack pipeline as blocks. The canonical
builder is defineCapability(...) in @pwfabric/sdk — see the
defineCapability() SDK reference
for the full API.
See also
defineCapability()SDK reference — author a custom capability- Composition — how blocks + capabilities combine into a Surface
- Architecture overview — where capabilities sit in the layer stack