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

KeyRequiredMeaning
idyesLetters, digits, ., _ and -; at most 128 characters. No : — it separates plugin and name in a target.
nameyesDisplay name.
versionyesYour plugin's version. Free-form, only shown.
requiresyesThe oldest BeSwarm it works with, as major[.minor[.patch]]. add refuses it on an older BeSwarm.
aboutnoOne-line description.
osnoDefault 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 :).

KeyRequiredMeaning
runyesargv list, run without a shell from the plugin's directory. Non-empty, no empty arguments.
labelnoShown in the Plugins panel. A command without a label is hidden from the panel, but hooks and plugin run can still run it.
osnoOverrides [plugin].os. A command for another OS won't run.
timeoutnoHow long it may run: "30s", "5m", "1h". Default "30s", at most "24h".
menuno"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.

KeyRequiredMeaning
runyesargv list.
labelyesViews are always shown in the panel.
osnoOverrides [plugin].os.
menuno"workspace", as for commands.
placementno"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.
singlenotrue 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;
  • requires doesn't parse, or names a BeSwarm newer than the one you're running;
  • a run is 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.