Skip to content

Contracts and capabilities

Every app hands the shell a contract on connect. It is a single declaration of how your app participates in the platform. It has four parts.

An app declares what it provides, what it consumes, the topics it subscribes to, and the permissions it holds.
  • provides — the intents and surfaces your app offers to others. Intent declarations carry a version and JSON schemas for their payload and result; surface declarations carry a name and the contexts they can be hosted in.
  • consumes — the intents your app intends to invoke on others, with a minimum version. This is how the platform knows your app depends on a capability before it ever calls it.
  • subscribes — the event topics you listen to, such as session.changed and theme.changed.
  • permissions — the platform capabilities you intend to use, such as notify.toast or surface.embed.

This is the load-bearing idea. The contract is delivered to the shell, and the shell sources app capabilities from it — discovery, wiring, the dashboard’s list of available surfaces, which app provides which intent. But the contract is not a security boundary:

  • A requiredPermission on a provided intent or surface is inert. It does not gate anything.
  • The contract describes intent; the provider’s backend authorizes every actual call.

So declare your contract honestly because the platform reasons about it, not because it protects you. The protection lives one layer down, at each app’s backend. For the authorization story an app author actually touches, see Advisory auth vs the backend gate.

Declaring consumes and subscribes looks redundant — you could just call invoke and subscribe at runtime. Declaring them up front lets the platform see the dependency graph between apps: who needs whom, and at which versions. That is what makes a capability removal or a version bump a reviewable change rather than a runtime surprise.