Manifest reference
Everything a plugin does is declared in beswarm.toml, at the root of its directory.
[plugin]
id = "example.notes"
name = "Notes"
version = "0.1.0"
requires = "0.1.0"
about = "Save and browse notes"
os = ["macos", "linux"]
[commands.save]
label = "Save notes"
run = ["sh", "save.sh"]
timeout = "2m"
[commands.log]
run = ["sh", "log.sh"]
[hooks]
"tui.started" = "log"
"agent.done" = ["save", "log"]
[views.board]
label = "Notes board"
run = ["less", "notes.md"]plugin
| Key | Required | Meaning |
|---|---|---|
id | yes | Letters, digits, ., _ and -; at most 128 characters. No : — it separates plugin and name in a target. |
name | yes | Display name. |
version | yes | Your plugin's version. Free-form, only shown. |
requires | yes | The oldest BeSwarm it works with, as major[.minor[.patch]]. add refuses it on an older BeSwarm. |
about | no | One-line description. |
os | no | Default OS list for every command and view: macos, linux. Missing means all. |
commands
[commands.<name>] declares a short-lived command. The table key is its name: letters, digits, _ and - (no . or :).
| Key | Required | Meaning |
|---|---|---|
run | yes | argv list, run without a shell from the plugin's directory. Non-empty, no empty arguments. |
label | no | Shown in the Plugins panel. A command without a label is hidden from the panel, but hooks and plugin run can still run it. |
os | no | Overrides [plugin].os. A command for another OS won't run. |
timeout | no | How long it may run: "30s", "5m", "1h". Default "30s", at most "24h". |
menu | no | "workspace" also lists a labelled command in a workspace's right-click menu in the sidebar, under Plugins ›. Run from there, its context gains workspace. |
Commands are meant to be short-lived. Anything long-running belongs in a view.
views
[views.<name>] declares an interactive command opened in a terminal tab. Same naming rules as commands.
| Key | Required | Meaning |
|---|---|---|
run | yes | argv list. |
label | yes | Views are always shown in the panel. |
os | no | Overrides [plugin].os. |
menu | no | "workspace", as for commands. |
placement | no | "tab" (default), "split-right" or "split-down". A split opens beside the focused pane, falling back to a tab when there is no visible pane to split. |
single | no | true allows one open single view per plugin. Opening another focuses the open one and fails with plugin_view_already_open. Its pane closes when the view exits. |
BeSwarm opens the tab in the plugin's directory and types env BESWARM_BIN=… <run> into its shell, with every word quoted. The tab stays a normal shell after your command exits, unless the view is single. Views have no timeout: use them for TUIs, live logs (tail -f), dashboards and prompts.
A command and a view may share a name; they live in separate namespaces.
hooks
[hooks] maps an event to the command, or list of commands, it runs:
[hooks]
"agent.blocked" = "notify"
"agent.done" = ["notify", "log"]
"workspace.*" = "log"A key ending in .* matches every event in that group, so "agent.*" matches agent.found, agent.working and the rest. A bare *, or a * anywhere else, is an error.
Targets
plugin run and plugin view take [plugin-id:]name. A bare name works when exactly one added plugin defines it; otherwise use the qualified form, such as example.notes:save. Commands and views are looked up separately.
Validation
add refuses the manifest when:
- a required key is missing, or an id or name uses characters it can't;
requiresdoesn't parse, or names a BeSwarm newer than the one you're running;- a
runis empty, or has an empty argument; - a hook names a command that isn't defined;
- a wildcard is malformed;
- a view has no
label.
It adds the plugin but records a warning — shown by plugin list and in the panel header — for unknown keys, an unknown os, menu or placement value (an unknown placement opens a tab), and a hook key that matches no event. Unknown keys only warn, so a manifest written for a newer BeSwarm keeps working on an older one.