Permissions Reference
StudioBrain plugins declare the capabilities they need in plugin.json. The host runtime enforces these declarations, granting access only to what the plugin has declared and the user has approved. This page is the complete reference for the capability system.
This page covers runtime capability/consent gating — what host functions a plugin can call once it’s installed. As of SBAI-4630/SBAI-4641 there is a separate, earlier gate: trust tiers, checked at install time before the capability system ever runs. See Trust Tiers below for how tiering and capability consent interact.
Trust Tiers (SBAI-4630)
Every plugin belongs to one of four trust tiers, declared as trust_tier in plugin.json and
verified against a code signature at install time — not just self-declared:
| Tier | Signed? | Who |
|---|---|---|
first_party | Yes, Biloxi Studios key | Plugins Biloxi Studios publishes itself |
trusted_vendor | Yes, vendor key | Large, vetted vendors (Adobe/Google-scale) |
partner | Yes, partner key | Verified studios and contributors |
community | No | Everyone else |
Verification is Ed25519 signature-based, not marketplace review or self-declaration alone.
Three values must agree before a plugin is trusted at a given tier: the manifest’s declared
trust_tier, the signature’s claimed tier, and the tier recorded against the matching public
key in the trusted-key registry (resources/plugin-trusted-keys.json on the host, overridable
via SB_PLUGIN_TRUSTED_KEYS_FILE). A community-tier plugin is, by definition, unsigned — it
is never marked is_verified, regardless of what its manifest claims.
Enforcement point: install-time manifest/signature validation in sb-server
(core/crates/sb-server/src/routes/plugins.rs, services/plugin_signature.rs), not the
wasmtime runtime. The runtime’s host-function gating (everything in the rest of this page) is
unchanged and unaware of trust tiers — tiering decides whether a plugin gets a verified badge
and whether consent is forced; the capability system still decides what host functions it can
call once running.
Interaction with consent (SBAI-4641): community-tier plugins always require an explicit
consent dialog on install, even if they declare zero non-auto-granted capabilities — the tier
itself is the thing the user is consenting to, not just the capability list. first_party,
trusted_vendor, and partner plugins still go through the same capability-based consent
dialog described below for anything beyond the auto-granted set; a higher trust tier does not
bypass capability consent, it only establishes the verified-signature badge users see before
they decide.
Capability Matrix
| Capability | Description | Auto-granted | Desktop | Core | Cloud |
|---|---|---|---|---|---|
entity_read | Read entity markdown and metadata | Yes | Yes | Yes | Yes |
asset_read | Read entity assets (images, files) | Yes | Yes | Yes | Yes |
ai_generate | Use the AI generation service | Yes | Yes | Yes | Yes |
entity_write | Create, modify, or delete entities | No | Consent | Consent | Consent |
asset_write | Upload, modify, or delete assets | No | Consent | Consent | Consent |
http_request | Make outbound HTTP requests | No | Consent (any domain) | Consent (any domain) | Not exposed (host callback has no HTTP action) |
file_read | Read files under the plugin’s own storage root (_PluginData/{plugin_id}/), relative paths only; host check is the native read_data permission | No | Consent | Consent | BLOCKED |
file_write | Write or delete files under the same plugin storage root; host check is the native write_data permission | No | Consent | Consent | BLOCKED |
Auto-granted capabilities
These capabilities are enabled automatically when a plugin is installed. They are considered safe because they are read-only or usage-tracked:
- entity_read — The plugin can read entity frontmatter and markdown content. It cannot modify anything.
- asset_read — The plugin can read files attached to entities (images, documents, audio). Read-only.
- ai_generate — The plugin can call the AI generation service. Usage is metered through your BrainBits balance, so the plugin cannot generate unbounded costs.
Consent-required capabilities
These capabilities require the user to approve a consent dialog before the plugin can use them:
- entity_write — The plugin can create new entities, modify existing entity fields and content, and delete entities. All changes appear in version history.
- asset_write — The plugin can upload new assets, replace existing assets, and delete assets from entities.
- http_request — The plugin can make outbound HTTP requests. See Domain Restrictions for Cloud-specific behavior.
Platform-restricted capabilities
These capabilities are blocked on certain platforms regardless of user consent:
- http_request — Make outbound HTTP requests from the plugin. Not exposed on Cloud: the official-plugin host callback (
packages/cloudflare-worker/sb-server-worker/src/plugin_host.rs) dispatches seven content, settings and log actions and has no HTTP action, so a Cloud plugin has no host path forhttp_request, andcapabilities.http_domainsis not read or enforced there. This describes the host-callback boundary only; it is not a statement about Cloudflare Workers’ own outboundfetchor about deployment egress policy. Available on Desktop and Core with consent. - file_read — Read files by path relative to the plugin’s storage root (
{content_base}/_PluginData/{plugin_id}/), never the host filesystem; the WASM host gates it on the nativeread_datapermission of thehost-storageinterface in core’spackages/plugin-sdk/wit/plugin.wit. Available on Desktop and Core with consent. Blocked on Cloud because Cloud runs in a server environment where plugin-scoped file storage is not meaningful. - file_write — Write or delete files under the same plugin storage root, gated on the native
write_datapermission. Same platform restrictions as file_read.
Plugins that require file_read or file_write cannot declare cloud in their platforms field. The marketplace CI validation will reject submissions that declare both Cloud support and filesystem capabilities.
Domain Restrictions
The http_request capability works differently across platforms:
Cloud (not exposed by the host callback)
On Cloud, the official-plugin host callback exposes no HTTP action: its seven actions are content, settings and log operations (packages/cloudflare-worker/sb-server-worker/src/plugin_host.rs), so http_request has no host path and the Cloud host neither reads nor enforces capabilities.http_domains. Declaring http_domains has no effect on Cloud. This is the boundary of the plugin host API, not a claim about Worker egress and not a service-binding workaround.
Desktop and Core (Informational)
On Desktop and Core, the declared domains are shown in the consent dialog for transparency, but they are not enforced. After the user approves the http_request capability, the plugin can reach any domain.
Even on Desktop and Core, declaring your actual domains in http_domains is good practice. It lets users make an informed decision during the consent dialog.
Capability Details
entity_read
What it grants: Read access to entity data through host functions.
Host functions enabled:
entity_read(entity_type, entity_id)— Read a single entityentity_list(query)— List entities with filters
What the plugin sees:
- Entity frontmatter (all YAML fields)
- Entity markdown body
- Entity metadata (created_at, updated_at, entity_type, entity_id)
What the plugin cannot do:
- Modify any entity data
- Access entities outside the current project scope (on StudioBrain Cloud, multi-tenant isolation is enforced by the host)
asset_read
What it grants: Read access to entity assets.
Host functions enabled:
asset_read(entity_type, entity_id, filename)— Read a single asset file
What the plugin sees:
- Binary content of the asset file
- Asset filename and content type
What the plugin cannot do:
- Modify or delete assets
- Access assets from entities it cannot read (respects entity_read scope)
ai_generate
What it grants: Access to the StudioBrain AI generation service.
Host functions enabled:
ai_generate(prompt, model, options)— Generate text content
Billing:
- Each generation call consumes BrainBits from the user’s account
- The plugin cannot exceed the user’s available balance
- Usage is attributed to the plugin in the billing dashboard
Rate limits:
- Same rate limits as the user’s direct AI usage
- Shared quota (plugin calls count toward the user’s limits)
entity_write
What it grants: Write access to entities.
Host functions enabled:
entity_create(entity_type, data)— Create a new entityentity_update(entity_type, entity_id, content)— Update an existing entityentity_delete(entity_type, entity_id)— Delete an entity
Audit trail:
- All write operations are logged in the entity’s version history
- The log entry shows the plugin ID as the author (e.g., “Modified by plugin: jira-sync”)
Scope:
- Write access applies to all entity types the plugin has access to
- On StudioBrain Cloud, tenant isolation is enforced (a plugin cannot write to another tenant’s entities)
asset_write
What it grants: Write access to entity assets.
Host functions enabled:
asset_write(entity_type, entity_id, filename, data)— Upload or replace an asset
Constraints:
- Same size limits as manual uploads (configurable per edition)
- Asset type restrictions apply (configured in entity templates)
http_request
What it grants: Ability to make outbound HTTP requests from the WASM sandbox.
Host functions enabled:
http_request(url, method, headers, body)— Make an HTTP request
Platform availability:
- Cloud: not exposed. The official-plugin host callback has no HTTP action (seven content/settings/log actions only), so there is no host path for
http_requestandhttp_domainsis not enforced. Host-callback boundary only; not a Worker egress statement. - Desktop and Core: governed by those hosts’ own gates, which this Cloud correction does not describe. On Core main the runtime requires the
net_httpcapability plusnetwork.allowed_domainsand caller consent, and builds a deny-all HTTP client unless hosts are granted (crates/sb-plugin-wasmtime/src/runtime.rs,host_state.rs); the Desktop/Core sections of this page are reconciled under SBAI-13559.
Request limits:
- 30 requests per minute per plugin instance
- 5 second timeout per request
- 1 MB maximum response body
file_read
What it grants: Read access to files under the plugin’s own storage root ({content_base}/_PluginData/{plugin_id}/), addressed by paths relative to that root. The WASM host enforces it through the read_data permission on the host-storage interface (read-file, list-files; core packages/plugin-sdk/wit/plugin.wit, host-storage section). file_read is this page’s capability name; it is not itself a host check or an installer permission.
Host functions enabled:
file_read(path)— Read the file atpath, relative to the plugin’s storage root (host-storageread-file;list-filesenumerates that root)
Platform availability:
| Platform | Available | Notes |
|---|---|---|
| Cloud | No | Blocked. Returns capability_blocked error. |
| Desktop | Yes | Consent required. WASM plugins operate within a plugin-scoped directory under the project content root ({base}/_PluginData/{plugin_id}/). |
| Core | Yes | Same as Desktop. Core’s wasmtime host has no native Python or Lua engine. |
Filesystem access is plugin-scoped storage, not general host filesystem access. The WASM host creates a dedicated directory for each plugin at {content_base}/_PluginData/{plugin_id}/ and enforces two restrictions: (1) absolute paths are rejected, and (2) path traversal (.. components) is blocked. Plugins can read/write any relative path within their own scoped directory — there is no manifest-based path allowlist. The contract is the host-storage interface in core’s packages/plugin-sdk/wit/plugin.wit: read-file and list-files require the native read_data permission, write-file and delete-file require write_data; the filesystem:read / filesystem:write spellings seen in older tickets are not host checks or installer permissions. Native Python is not loaded on Desktop, Core, Cloud, or mobile. Lua 5.4 runs only in the sandboxed mobile client host (sb-client-plugins), which removes dangerous builtins (io, os, debug, require, loadfile, dofile, load). Only install plugins from trusted authors.
file_write
What it grants: Write and delete access under the same plugin storage root, by relative path, enforced through the write_data permission on the host-storage interface (write-file, delete-file).
Host functions enabled:
file_write(path, data)— Writedatatopath, relative to the plugin’s storage root (host-storagewrite-file;delete-fileremoves a file there)
Platform availability: Same as file_read.
Safety:
- WASM plugins operate within a plugin-scoped directory (
{content_base}/_PluginData/{plugin_id}/), with absolute paths and path traversal (..) blocked at the sanitizer layer - Native Python is not executed, so it has no filesystem access
- Lua runs only in the sandboxed mobile client host and does not have unrestricted filesystem access
- No automatic backups are made before writes — plugins are responsible for safe writes
Consent Dialog Behavior
When a plugin is installed (or updated with new capabilities), StudioBrain shows a consent dialog for any non-auto-granted capabilities.
What the dialog shows
Plugin "My Plugin" requests the following permissions:
[auto] entity_read Read your entity data
[auto] asset_read Read your entity assets
[!] entity_write Create and modify your entities
[!] http_request Make network requests to:
api.example.com, cdn.example.org
[Enable] [Cancel]- [auto] items are informational. They are granted regardless of the user’s choice.
- [!] items require explicit approval. If the user clicks Cancel, the plugin is not installed.
- For
http_request, the declared domains are listed.
Partial approval
The current consent model is all-or-nothing for consent-required capabilities. If a plugin requests entity_write and http_request, you must approve both or cancel the installation entirely.
After installation, you can revoke individual capabilities in Settings > Plugins > [Plugin] > Permissions. The plugin may not function correctly without all its declared capabilities.
Re-consent on update
If a plugin update adds new consent-required capabilities, the consent dialog appears again showing only the new capabilities. Previously approved capabilities are not shown again.
Storage and Config Capabilities
The following host functions are always available to any plugin, regardless of declared capabilities:
| Function | Purpose |
|---|---|
storage_get(key) | Read plugin-scoped persistent data |
storage_set(key, value) | Write plugin-scoped persistent data |
storage_delete(key) | Delete plugin-scoped data |
storage_list(prefix) | List keys in plugin storage |
get_config(key) | Read a plugin setting value |
set_config(key, value) | Write a plugin setting value |
log(level, message) | Write to the plugin log |
ui_notify(title, message, level) | Show a toast notification |
These functions operate within the plugin’s own scope. A plugin cannot read another plugin’s storage or settings.
Security Considerations
WASM sandbox guarantees
- Plugins cannot access host memory outside their linear memory.
- Plugins cannot call host functions they have not declared.
- Plugins cannot bypass domain restrictions on Cloud.
- Plugins cannot access other plugins’ data or storage.
What the sandbox does NOT protect against
- A plugin with
entity_writecan modify any entity the user has access to. - A plugin with
http_requestcan exfiltrate entity data to declared domains. - A plugin with
ai_generatecan consume BrainBits. - Native Python is not executed, so it cannot bypass the sandbox.
- Lua does not bypass the sandbox. It runs only in the mobile client host, with
io,os,debug,require,loadfile,dofile, andloadremoved.
Recommendations
- Install only plugins from authors you trust.
- Review the declared capabilities before approving the consent dialog.
- Prefer a WIT Component. Native Python is not loaded. Lua is sandboxed and is not a Desktop or Core runtime.
- Revoke capabilities you do not need after installation.
- Monitor plugin activity in Settings > Plugins > [Plugin] > Activity Log.
Next Steps
- Plugin System Overview — How the plugin system works
- Using the Marketplace — Browse, install, and manage plugins
- Creating Plugins — Build your own plugin
- Host Functions API — Detailed function documentation