Plugin API Reference
The field-by-field reference for aoe-plugin.toml, the manifest every Agent of
Empires plugin ships. The schema lives in the aoe-plugin-api crate
(PluginManifest) and is the source of truth; this page documents it for plugin
authors. The host parses the manifest strictly (unknown keys are rejected), so
every key here maps to a schema field.
For a guided introduction see Writing Plugins. To scaffold a working plugin, use the starter template:
cookiecutter gh:agent-of-empires/plugin-template
Versioning
A manifest carries two independent version axes.
| Key | Meaning |
|---|---|
api_version | The manifest schema version. The current schema is 6. The host rejects a manifest whose api_version is newer than it supports. Bump it as you adopt newer sections (see below). |
aoe_version | A semver requirement on the host app version, e.g. ">=1.11.0, <2.0.0". The host refuses to install, and skips loading, a plugin whose requirement excludes the running version. Optional; requires api_version >= 4. |
Schema additions by api_version: 2 added contributions (commands, keybinds, settings, ui), 3 added the pane UI slot, 4 added status and aoe_version, 5 added screenshots, 6 added a command action.
Top-level fields
id = "dev.example.my-plugin"
name = "My Plugin"
version = "0.1.0"
api_version = 6
aoe_version = ">=1.11.0, <2.0.0"
description = "What the plugin does."
capabilities = ["runtime.worker"]
| Key | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Plugin id (see Plugin id). Namespaces config, events, and action names. |
name | string | yes | Human-readable display name. |
version | string | yes | Semantic version of the plugin. |
api_version | integer | yes | Manifest schema version, 1 to 6. |
description | string | no | Shown in plugin listings. Defaults to empty. |
aoe_version | string | no | Host-app semver requirement. Requires api_version >= 4. |
capabilities | array of string | no | Runtime grants the worker needs (see Capabilities). Static contributions need none. |
screenshots | array | no | Up to 8. Requires api_version >= 5. See Screenshots. |
setting_defaults | table | no | Overrides for core host settings, keyed by canonical path (e.g. "theme.idle_decay_minutes"). Resolution is user value, then plugin override, then core default. |
Plugin id
A dotted, lowercase ASCII identifier such as dev.example.review-helper. Each
dot-separated segment starts with a lowercase letter and may contain digits and
hyphens; the whole id is at most 64 bytes. The aoe.* and agent-of-empires.*
namespaces are reserved for bundled and officially featured plugins; a community
install cannot claim them.
Capabilities
Capabilities gate runtime resource access. They are prompted once at install and pinned to the manifest hash; an update that widens them must be re-approved. Declare only what the worker uses. Static contributions (commands, keybinds, themes, ui, status) need no capability.
| Capability | Grants |
|---|---|
runtime.worker | Running any plugin code at all (host RPCs the worker initiates). Any worker needs this. |
session.read | Reading the attached session. |
session.write | Mutating the attached session. |
config.read | Reading host or other-plugin configuration (not the plugin’s own settings). |
config.write | Writing host or other-plugin configuration. |
process.spawn | Spawning processes beyond the plugin’s own worker. |
net | Outbound network access. |
fs.read | Filesystem reads outside the plugin directory. |
fs.write | Filesystem writes outside the plugin directory. |
clipboard.read | Reading the clipboard. |
clipboard.write | Writing the clipboard. |
notifications | Posting desktop / TUI notifications. |
browser_open | Opening a URL in the user’s browser from a command action. |
A capability this host version does not recognize is rejected, not granted.
Commands
Palette and CLI entries, namespaced by the host as plugin.<id>.<command-id>.
[[commands]]
id = "status"
title = "My Plugin: status"
description = "Show the status summary."
| Key | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Command id. Empty is unaddressable. |
title | string | no | Display name. |
description | string | no | Help text. |
action | table | no | A client-executed action. Requires api_version >= 6 and the browser_open capability. |
Command action
[commands.action]
kind = "open-ui-link"
slot = "row-badge"
id = "my_badge"
The only kind is open-ui-link: it opens the href from the plugin’s own
(slot, id) UI-state entry in the browser, with no worker round-trip. The
(slot, id) pair must match a declared [[ui]] entry on a per-session slot.
Keybinds
[[keybinds]]
command = "status"
key = "Ctrl+Shift+G"
| Key | Type | Required | Notes |
|---|---|---|---|
command | string | yes | Target command id (a plugin or core command). |
key | string | yes | Key chord, e.g. Ctrl+Shift+G. Core bindings win a collision. |
Settings
Plugin-declared settings, rendered on the TUI and web settings surfaces and
stored under [plugins."<id>".settings]. The worker reads them via the
config.get host RPC.
[[settings]]
key = "refresh_secs"
label = "Refresh interval (seconds)"
description = "How often the worker polls."
type = "integer"
default = 120
min = 0
max = 86400
advanced = true
| Key | Type | Required | Notes |
|---|---|---|---|
key | string | yes | Setting key, stored under the plugin’s settings table. |
label | string | no | Display label. |
description | string | no | Help text. |
type | string | no | Value type (see below). Defaults to string. |
options | array of string | no | Allowed values for select; ignored otherwise. |
min / max | integer | no | Inclusive bounds for integer; ignored otherwise. |
default | any | no | Declared default. Must match type. Absent means the type’s zero value. |
advanced | bool | no | Group under the Advanced fold. Defaults to false. |
Setting types:
type | Widget |
|---|---|
string | Text input (default). |
bool (or boolean) | Toggle. |
integer | Number input, bounded by min / max. |
select | Dropdown over a non-empty options array. |
UI slots
Declares the host-rendered slots the worker pushes state into via the
ui.state.set host RPC.
[[ui]]
slot = "pane"
id = "my_pane"
| Key | Type | Required | Notes |
|---|---|---|---|
slot | string | yes | One of the slot names below. Unknown slots are rejected. |
id | string | no | Addressing id for (slot, id) state pushes. Required to be non-empty when a command action targets it. |
| Slot | Scope | Renders |
|---|---|---|
status-bar | global | A segment in the dashboard status bar. |
card | global | A card on the dashboard overview. |
sort-key | global | A named sort option over a row-column value. |
filter-facet | global | A named filter over a row-column value. |
row-badge | per-session | A badge on the session row. |
row-column | per-session | A text column on the session row. |
detail-badge | per-session | A badge in the session detail view. |
pane | per-session | A dockable tool-window pane (requires api_version >= 3). |
notification | n/a | A transient notification pushed via ui.notify; gated by the notifications capability, not a slot declaration. |
Status
Status segments the plugin contributes, consumed by the status surface. Requires
api_version >= 4.
[[status]]
id = "pr_state"
label = "PR state"
| Key | Type | Required | Notes |
|---|---|---|---|
id | string | yes | Stable segment id. |
label | string | no | Human-readable text. |
Themes
[[themes]]
name = "My Theme"
path = "themes/my-theme.toml"
| Key | Type | Required | Notes |
|---|---|---|---|
name | string | yes | Theme name in the picker. Must not collide with a builtin. |
path | string | yes | Theme TOML path, relative to the plugin directory. |
Screenshots
Up to 8 marketplace screenshots, shown in the plugin detail view. Requires
api_version >= 5.
[[screenshots]]
path = "assets/screenshots/overview.png"
alt = "The plugin's pane showing live status."
caption = "Live status in the pane."
| Key | Type | Required | Notes |
|---|---|---|---|
path | string | yes | Repository-relative image path. No URL scheme, no leading separator, no ..; must be PNG, JPEG, GIF, or WebP. |
alt | string | yes | Accessible description; non-empty. |
caption | string | no | Caption shown beneath the image. |
Runtime
The worker the host spawns and supervises. Omit it for a static, metadata-only plugin. Two kinds.
Command
The host runs the build steps at install or update, then launches command.
[runtime]
kind = "command"
command = [".aoe-build/venv/bin/my-plugin-worker"]
[[runtime.build]]
command = ["python3", "-m", "venv", ".aoe-build/venv"]
platforms = ["linux", "macos"]
| Key | Type | Required | Notes |
|---|---|---|---|
command | array of string | yes | argv. Plugin-relative by default (must contain a path separator, never absolute) so the daemon’s PATH never decides whether the worker launches. With system = true it must instead be a bare program name resolved on PATH. |
system | bool | no | Resolve command[0] on the host PATH (for genuine system tools only). Defaults to false. |
build | array | no | Ordered build steps, run once at install or update inside the plugin directory, in the user’s interactive shell. |
Build into .aoe-build/ (the host’s build-output directory); the host excludes
it from the plugin tree hash, so a venv, node_modules, or target/ there does
not break integrity verification.
Build step
| Key | Type | Required | Notes |
|---|---|---|---|
command | array of string | yes | argv, same resolution policy as the launch command. |
platforms | array of string | no | Restrict to OS names: linux, macos, windows. Empty runs on all. |
Release binary
The host downloads a release asset instead of building from source.
[runtime]
kind = "release-binary"
asset = "my-plugin-${target}.tar.gz"
bin = "my-plugin-worker"
| Key | Type | Required | Notes |
|---|---|---|---|
asset | string | yes | Asset-name template; ${os}, ${arch}, ${target} are substituted before matching the release. |
bin | string | no | Executable path inside the extracted archive. Omit to run the downloaded asset directly (a raw, non-archive binary). |