Writing a plugin

A folder, a plugin.json, and an HTML file. The manifest field by field, the two sandboxes, and what a plugin's page may ask the IDE for.

There is no build step and no SDK to install. A plugin is a folder with a plugin.json and the files it names. Write it anywhere you like, then load it from Settings → Plugins → Load unpacked…; edit, press Reload, look.

The quickest start#

Project Manager → Projects → the Plugin switch on a project (or Semantix plugin when you create one) marks it as a plugin. If the folder has no plugin.json yet, Semantix writes a starter one with a working background beside it. It doesn't install it — load it with Load unpacked… when you're ready.

While a project is marked as a plugin, the agent you chat with in it is told the plugin rules — the fields, the sandboxes, every permission — so you can ask it to build the plugin with you.

The smallest plugin: a background#

{
  "id": "my-wallpaper",
  "name": "My Wallpaper",
  "version": "0.1.0",
  "icon": "sparkles",
  "contributes": {
    "backgrounds": [
      {
        "id": "main",
        "name": "My Wallpaper",
        "entry": "background.html",
        "sections": ["main", "panel-left", "panel-right"]
      }
    ]
  }
}

background.html is just the body of a document — markup, <style> and <script>. Semantix wraps it. Draw on a canvas, and listen for three messages from the IDE:

  • host:init — the first message, carrying the live theme palette in payload.theme.
  • host:theme — the palette again, every time it changes. Its payload is the palette: accent, surface, text, textSecondary, border, elevated, and light (true on a light theme).
  • host:visibility — { visible }. Stop animating while it's false.

Every message is wrapped as { __semantix: true, v: 1, kind: 'event', type, payload }. The IDE sends nothing until your document says it's ready:

parent.postMessage({ __semantix: true, v: 1, kind: 'event', type: 'plugin:ready' }, '*');

What a background cannot do: fetch anything (no network at all), use localStorage, load files beside it, or receive clicks. Pictures and fonts must be inline data: URIs. Two libraries are on the shelf, imported by name from a <script type="module">: three (with three/addons/controls/OrbitControls.js) and gsap. Nothing else resolves.

Keep loops bounded and animate on requestAnimationFrame — a loop that never yields freezes the whole window, and the next run will hold your background back (When it misbehaves).

A page of its own#

Give the plugin an entry — an HTML page — and it becomes a panel. Add a surface and the panel opens as a tab, with its own button in the header:

{
  "id": "note-saver",
  "name": "Note saver",
  "version": "0.1.0",
  "entry": "index.html",
  "permissions": ["workspace:read", "workspace:write"],
  "contributes": { "surfaces": [{ "id": "main", "name": "Note saver" }] }
}

The page talks to the IDE by message. A request is { __semantix: true, v: 1, kind: 'rpc-req', id, method, params }, and the answer comes back as { kind: 'rpc-res', id, ok, result, error } with the same id. Wrap that in a small call helper that posts the request and waits for its answer, and writing a file into the open project is one line:

call('saveToWorkspace', { path: 'notes/hello.md', content: '# Hello\n' });

A page's sandbox is stricter than it might look. It has no network — not even its own folder over fetch — and no browser storage (no localStorage, no IndexedDB). It can load its own scripts, styles and images with ordinary tags. For anything it needs to keep, it asks the IDE (plugin:storage, below).

A hidden tab is kept alive, not reloaded: you get host:visibility with visible: false. Pause and keep your state.

Note

Settings → Plugins has a short in-app summary of this format under Writing one. This page is the full one.

What a page may ask for#

Each permission opens a small set of methods. A method the plugin didn't declare is refused with Unknown method — the same answer as a method that doesn't exist.

Permission What it allows
workspace:read The open project's path and name, and events when a file or the project changes
workspace:write Writing a file into the open project (missing folders are created)
images:generate Rendering images and video with the user's own providers — the plugin never sees a key
images:gallery Listing, saving and deleting kept renders
media:projects The media editor's projects
clipboard:read A pasted picture — only while focus is inside the plugin's own page
plugin:storage Its own small JSON values, up to 1 MB each, kept across updates and uninstall
plugin:chat Opening the plugin's chat and agent, and lending them tools
plugin:knowledge Adding and removing the plugin's knowledge notes at run time
speech:say Saying a line in the Studio's voice

A render with the vendor's content filter off asks the user to confirm they are 18 or older first.

The manifest, field by field#

Field Required Notes
id yes 1–64 letters, digits, -, _ or ., not starting with .. Don't reuse a built-in's id.
name yes Shown on the card.
version, description, author no Shown on the card.
icon no One of activity, blocks, flame, image, puzzle, sparkles, waves. Anything else shows the puzzle piece.
entry no The page, as a path inside the folder (or inside dist/, if there is one). No .., no leading /. Must exist.
permissions no From the table above. Meaningless without entry.
contributes.backgrounds no Each: id, name, entry (must exist), optional description and sections — any of header, panel-left, main, panel-right; main if left out.
contributes.surfaces no Tabs that open entry. Each: id, name, optional icon. Needs entry.
contributes.knowledge no A folder of .md notes for the plugin's mind.
contributes.chat no { "title": …, "instructions": "path.md" }
contributes.agent no { "name": …, "identity": "path.md", "instructions": "path.md" } — a name of up to 80 characters.

A plugin must contribute something — a page, a background or a mind — or it won't load.

Renaming is breaking. A saved theme remembers a background by its plugin and background ids, and an open tab remembers its surface id. Change one and the old reference stops matching: the tab explains the plugin no longer adds it, and the theme falls back to nothing.

Warning

Install checks that your pages and backgrounds exist, but not your mind's files. If a knowledge, chat or agent file is missing, the plugin installs and its mind fails later, all at once. Check every path you name.

Where it is now#

Note

activationEvents is read from the manifest and ignored; plugins load when listed. A plugin's mind can only be opened by its own page. Where something on these pages is marked coming, it means exactly that.