Creating a Plugin

This guide covers structure, plugin.json, and the two authoring paths. For the lock (repos, runtimes, Marketplace), see Architecture. For a first build, see Getting Started.

Where does it run?

KindDesktopMobileCloud
Official universalWIT Component (wasmtime Cranelift)Same Component (wasmtime Pulley)Official Worker, compiled at our deploy. Panels on all surfaces.
Official desktop-onlyComponent + network:local + environments: ["desktop"]
Community pluginComponentSame ComponentPanel iframe and/or author backend. Never a Worker on BiloxiStudios Cloudflare.
Any data kindFiles in the projectFiles in the projectFiles in the project. No Worker.

Two homes for code, one home for official data

You are shippingLand it in
Official or vendor code (Component + official Worker)studiobrain-plugins
Community plugin listingstudiobrain-community (today studiobrain-community-plugins), plugins/index.json
Community templates / rules / skills / layouts / packs / providers / abilities / flows / canvasSame community repo, catalog/index.jsonnot studiobrain-templates
Official datastudiobrain-templates only

studiobrain-templates is not a plugin home. Do not open plugin PRs there.

Plugin structure

my-plugin/
  plugin.json              # Manifest (required)
  plugin.wasm              # WIT Component (desktop / mobile)
  src/                     # Rust guest (cargo-component)
  frontend/                # or panels/ — iframe HTML
    panel.html
  widgets/                 # Field widget HTML (optional)
  assets/                  # Icons, screenshots (optional)
  README.md

Official universal plugins also have a Worker crate or package that our cloud deploy compiles. That Worker is not something community authors push into BiloxiStudios Cloudflare.

plugin.json

{
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "description": "A short description of what the plugin does",
  "author": "Your Name or Organization",
  "license": "Apache-2.0",
  "homepage": "https://github.com/you/my-plugin",
  "repository": "https://github.com/you/my-plugin",
  "icon": "Puzzle",
  "trust_tier": "community",
  "type": "full",
  "min_studiobrain_version": "2026.8",
 
  "capabilities": {
    "backend": {
      "entry": "plugin.wasm"
    },
    "frontend": {
      "panels": [
        {
          "id": "main-panel",
          "title": "My Panel",
          "location": "entity-sidebar",
          "entity_types": ["character", "location"],
          "default_collapsed": false
        }
      ],
      "tabs": [
        {
          "id": "analytics",
          "title": "Analytics",
          "url": "/panels/analytics.html",
          "entity_types": ["*"]
        }
      ],
      "pages": [
        {
          "id": "dashboard",
          "title": "Plugin Dashboard",
          "url": "/panels/dashboard.html",
          "nav_section": "tools"
        }
      ],
      "field_widgets": [
        {
          "id": "my-widget",
          "label": "My Widget",
          "category": "text",
          "value_type": "string",
          "accepts_options": false
        }
      ]
    },
    "settings": {
      "global": [
        {
          "key": "api_key",
          "label": "API Key",
          "type": "password",
          "required": true
        }
      ],
      "user": [
        {
          "key": "show_notifications",
          "label": "Show Notifications",
          "type": "boolean",
          "default": true
        }
      ]
    }
  },
  "permissions": ["read_entities"],
  "http_domains": ["api.example.com"]
}

Required fields

FieldTypeDescription
idstringUnique identifier. Lowercase, hyphens only.
namestringDisplay name.
versionstringSemver (1.0.0).
descriptionstringOne-line Marketplace blurb.
trust_tierstringcommunity, partner, trusted_vendor, or first_party.

Optional fields

FieldTypeDescription
authorstringName or organization.
licensestringSPDX id (Apache-2.0, MIT).
homepage / repositorystringDocs and source URLs.
iconstringLucide icon name.
typestringfull (Component + panels) or panel-only.
min_studiobrain_versionstringMinimum host version.

Backend entry

capabilities.backend.entry is the WIT Component path (plugin.wasm). Desktop and mobile load that Component. It is not compiled by Cloudflare from R2.

Official cloud execution is a separate Worker we bundle at deploy. Community listings must not assume a Worker on our account.

Permissions and HTTP

Declare host functions / permissions you actually call. See Permissions.

http_domains lists hosts for mediated http_request. On cloud official Workers, only those domains are reachable. Community cloud backends are the author’s problem and are not our Worker allowlist.

Request the minimum set. Users install a read_entities-only plugin faster than one that asks for writes plus arbitrary HTTP.

Frontend

  • panels — sidebar / footer
  • tabs — entity page tabs
  • pages — standalone navigation
  • field_widgets — custom form inputs (Field Widgets)

Settings

  • global — admin (API keys, service URLs)
  • user — preferences

Types: text, password, number, boolean, select, textarea.

Official vs community

Official universal

Rust Component in studiobrain-plugins plus an official Worker in our cloud deploy. Panels everywhere. Proofs today: entity-notes, entity-snapshots, content-stats.

Official desktop-only

Same Component, plus network:local and environments: ["desktop"] (LAN devices, local daemons). Marketplace hides these on cloud and mobile. Community listings may declare network:local only when environments is exactly ["desktop"].

Community

Component for desktop/mobile. Cloud = panel iframe and/or your backend. Submit to the community plugins index. See Submitting.

⚠️

Native Python / Lua guests are not Marketplace community plugins and are not a cloud runtime. New work is a WIT Component. Legacy backend/routes.py trees are archive, not a template.

Host functions

WASM guests call host imports. Summary — full list in Host Functions:

FunctionPurposeTypical permission
entity_read / entity_listRead entitiesread entities
entity_create / entity_update / entity_deleteMutate entitieswrite entities
asset_read / asset_writeEntity assetsread/write assets
http_requestMediated outbound HTTPhttp + declared domains
ai_generateStudioBrain generation (BrainBits on cloud)ai generate
storage_*Plugin-scoped dataplugin data
get_config / set_configSettingsalways (scoped)
log / ui_notifyDiagnostics and toastsalways
network:localDesktop LAN / localhostofficial desktop-only

Building the Component

Rust is the official proof language:

# From a first-party proof in studiobrain-plugins, e.g. entity-notes
cargo install cargo-component wasm-tools
cargo component build --release

Copy the wasm32-wasip1 release Component to plugin.wasm. The host WIT world lives with the plugin SDK; do not invent a parallel world.

WASI-on-Workers is experimental and is not this world. Do not transpile the Component to a Worker yourself and expect us to load it.

Testing locally

# Per-project: copy or symlink into the project plugin dir
cp -r my-plugin/ ~/StudioBrain/MyProject/_Plugins/my-plugin/

Enable it for that project. Tenant allowlist still applies on cloud.

  • Desktop: wasmtime Cranelift loads the Component.
  • Mobile: same Component, wasmtime Pulley.
  • Cloud community: open an entity and confirm the panel iframe. Do not expect your .wasm to become a Worker.

If the guest calls an undeclared permission, the host returns an error. Reset grants under Settings → Plugins → [Plugin] → Permissions to re-test consent.

Next steps