What to run, in order — a list, because the useful actions are composites (research, then image) and a contributor should not have to model that as one operation.
An EMPTY list means the action does not apply to this subject and the host omits the item. One closure decides both applicability and behaviour, so the two cannot disagree.
A closure rather than value properties: holding an Operation.Definition on the capability value
makes the capability atom read recurse.
OptionalgroupConsecutive actions sharing a group are set apart from their neighbours by a separator.
OptionaliconPhosphor icon name.
Stable id; the menu item's key, and what the host dispatches on.
Menu item label, shown verbatim.
OptionalunavailableWhy the action cannot run right now; the host shows it disabled with this reason.
A menu item one plugin contributes to another plugin's object surface — "analyse this mailbox", "research this sender", "delegate this task to a chat".
The contributing plugin owns the behaviour and the host owns the surface, so neither has to import the other: the host defines a capability over this shape, and every plugin that wants a place on that surface contributes one.
Deprecated
Contribute an app-graph action on the subject's node instead, so every contributed action lives in the one graph the app's menus read. The host reads it with
graphActions(…, { filter }); a subject that is not an object gets a typed hidden node, as a prompt does (AppNode.makePrompt).