Documentation
Plugins
A plugin is a directory of JavaScript that adds buttons, panels, tabs, modals and background services to the app.
Shape
Two files minimum: a JSON manifest and an ES module entry point.
my-plugin/ plugin.json index.js
{
"id": "acme.my-plugin",
"name": "My Plugin",
"version": "0.1.0",
"apiVersion": 1,
"entry": "index.js",
"permissions": ["storage"],
"contributes": {
"commands": [{ "id": "acme.my-plugin.hello", "title": "My Plugin: Hello" }]
}
}The entry exports an activate(ctx) function. ctx is the only handle you get — commands, storage, and the surfaces you declared.
Your id must look like publisher.plugin in lowercase. The bentomux publisher is reserved.
Surfaces
Nine places a plugin can appear:
| Key | Adds |
|---|---|
| commands | Palette entries and keybindable actions |
| topbar | A button in the top bar |
| sidebar | An entry in the left sidebar |
| dock | An item in the bottom dock |
| tabs | A custom tab type |
| modals | A modal dialog |
| widgets | A panel in the right sidebar |
| settings | A section in the Settings modal |
| services | A headless background task |
Permissions
Declare what you use. The manifest rejects any name it does not know.
storage app.read app.prefs.write app.window files.temp workspaces.write tabs.write terminal.read terminal.input git.read git.push agents.read agents.write remote.control backend.invoke
Be honest about the ceiling here: permissions are a declared contract, not a sandbox. Plugins run in the app's own web context, with the same reach the host has. Review what you install the way you would review a shell alias.
Validate before you ship
The validator runs from a terminal — no need to open the app. Exit 0 is clean, 1 means errors, 2 is a usage mistake.
bentomux --plugin-validate ./my-plugin bentomux --plugin-validate ./my-plugin --json
It checks, without running any of your code:
- the manifest exists, parses, and matches the schema
- the
idis well formed and not using the reserved publisher versionandminAppVersionare semver,apiVersionis known- the entry file exists, is inside the plugin root, and is not empty
- every contribution id is namespaced under your plugin id and unique
- every permission name is one the app knows
- every command referenced by a button, sidebar entry or dock item is declared
- icons resolve — a builtin name, or a file that exists
- every network origin is a bare https:// host with no path
- the whole plugin is under 5 MB
The CLI additionally runs node --check on the entry to catch syntax errors. The in-app validator skips that step, because Node is not guaranteed at runtime; a syntax error surfaces at activation instead.
Install
From a folder on disk, from a zip, or over HTTPS. Remote installs must be https:// and are checked against a pinned SHA-256 before anything is unpacked.
There is no hosted registry of our own. GitHub is the catalog: a public repository carrying the topic bentomux-plugin and a release with exactly one .zip asset is discoverable, and the app verifies the asset's published sha256 before anything is unpacked.
The plugin marketplace page lists what is currently published, most-starred first. It is a discovery surface, not an installer: the app is what downloads, verifies and installs a release.
Network access
A plugin that fetches an outside website declares it in plugin.json under network, as bare https://host[:port] origins with no path. The Studio install review shows the declared hosts next to the permissions, and a host outside the last build stays blocked until the next release.
Start from a template
Seven scaffolding templates ship with the app, one per surface. Each comes with a manifest, an entry, and the TypeScript definitions for ctx.
basic · topbar · sidebar · tab · modal · widget · service
Plugin Studio and the plugin creator are in the app, under Plugins. Studio lists what is installed, validates, and lets you remove or reinstall.