Developer

Permissions & Scopes

The capability model - every scope an applet can declare, how it is enforced, and how cross-applet calls work.

An applet declares every capability it uses in applet.json::scopes[]. Scopes are shown to the user at install time, validated when the bundle installs, and enforced on every call. There are no hidden capabilities.

A scope is a type:scope string, for example projectDb:write or http:fetch.

"scopes": [
  "projectDb:read",
  "projectDb:write",
  "http:fetch",
  "credentials:store",
  "events:emit",
  "system:sidecar"
]

Scope catalog

TypeScopesGrants
projectDbread, writeProject-tier per-resource SQLite
httpfetchOutbound HTTP via ctx.sdk.http
networkhttp, wsAuthenticated and paginated HTTP, WebSocket
credentialsread, storeCredential metadata read; secret storage
contentCacheread, writeBundle-writable shared cache
connectionmarkMark resource connection status
oauth(via credentials:store)OAuth 2.0 Authorization Code flow
eventsemit, listenTyped event bus
cronregisterScheduled task registration
storagekvKey-value storage
kvread, writeEncrypted key-value store for agent payloads
parsingrssUniversal feed parser (RSS, Atom, JSON Feed)
lifecycleresourcesResource create and delete events
clipboardread, writeClipboard access
notificationssendOS notifications
browseropenOpen URLs
projectsreadList projects, current project
resourcesreadDiscover other applets’ resources
placesreadList places
stagesreadList and get stages
gitreadGit status, log, branches, diff
relaychannelPeer-to-peer relay channel
mediaread, write, adminRemote media cache
fsread, writeApp-data filesystem (legacy)
dbread, writeApp-data SQLite (legacy)
systemread, sidecarApp and OS info; Node sidecar runtime
appletsread, writeMethod config and scope grants

Enforcement

A declared scope is checked at three points:

  1. Install - unknown scopes are rejected against the catalog.
  2. Pre-call - the SDK bridge checks the caller declared the scope.
  3. Native command - the host re-checks as defense in depth.

A method’s permission field names the scope required to call it. The method cannot run unless the applet declares that scope.

Cross-applet calls

To call another applet’s method, declare the target’s scope in your own applet.json. The call routes through the same registry as any other method.

// caller declares "rss:write" in its own scopes
await ctx.sdk.rp.rss.addFeed({ url });

Calls between applets in the same bundle skip the scope check, because a bundle is a single trust unit.

Legacy scopes

fs:* and db:* target the app-data sandbox and are de-promoted. Prefer projectDb:* (per-resource project-tier SQLite) and projectFs for new applets.