Skip to main content
A plugin’s contributes block is how it adds surfaces to Mission Control. The GCS half declares them under gcs.contributes; the agent half declares its own (services, shared_topics, drivers, vision and the MCP lists) under agent.contributes, described in the manifest reference. This page is the reference for the GCS-side keys. Every contribution is declarative. You name what you want in manifest.yaml, request the matching capability, and the host mounts it. There is no runtime “register this panel” call.
Each visual contribution needs the matching ui.slot.* capability under gcs.permissions. A contribution whose slot capability was not granted is not mounted: the slot skips it and shows the operator a notice naming the missing grant. See Permissions.

The shape of contributes

Keys are snake_case. Mission Control also reads missionTemplates, mapOverlays and targetActions, but the agent’s validator (and so ados plugin lint, sign and test) rejects the camelCase spelling. Omit the arrays you do not need. Mission Control parses each array independently and drops a malformed entry with a console warning rather than failing the whole plugin. The tools, resources and prompts lists are covered in the manifest reference.

Slot and capability map

The slot taxonomy

There are 13 slots. Each maps one-to-one to its capability by replacing dots with dashes: node.detail.tab needs ui.slot.node-detail-tab. A per-drone contribution is bound to the selected drone: its capability token names that drone, and it is torn down and re-mounted when the operator switches drone. The node-scoped slots are the six marked per drone; the other seven are fleet-level.

skills

A Skill is a flight behavior that surfaces in the cockpit Skill Bar. It can be bound to a hotkey or a gamepad button, toggled or fired once, and gated on arm state. Built-in commands and plugin behaviors such as Follow-Me are the same Skill shape. What it does. Registers an entry in the Skill Bar. Activation writes a key in the plugin’s per-drone config (activation.via: config); the plugin’s agent half reads that key and starts or stops the behavior. The Skill’s live state is read back from an event topic (state.via: event), so the bar shows what the plugin reports rather than an optimistic guess.
Where it renders. The cockpit Skill Bar. The operator rebinds it in Settings → Input Devices. Capability. ui.slot.flight-skill.
Mission Control honors only activation.via: config and state.via: event, and both config_key and topic must be set. A skill entry with any other transport is dropped. The Skill only triggers the plugin’s behavior: the agent half still needs its own flight capabilities (mavlink.write, flight.guided_setpoint) to act, and the cockpit’s arm and confirm gates still apply. See Safety.

target_actions

A target action is an action a plugin offers on a detection the operator clicks in the cockpit video. It appears in the same popup as the built-in actions, and can be fired on the selected target with a key. What it does. When the operator picks the action, Mission Control optionally designates the clicked box to the drone’s vision tracker, then writes one key of the plugin’s per-drone config so the agent half reacts.
An action that writes the same config_key as one of the plugin’s skills inherits that skill’s confirm and arm gates, so the two surfaces cannot bypass each other. An action that writes false is a stop and is not gated. A default_key that collides with a chord Mission Control owns is ignored. Where it renders. The cockpit target popup on a clicked detection. Capability. None on the GCS half: Mission Control performs the designation and the config write itself. The agent half needs the vision capabilities to see detections (vision.detection.subscribe) and its flight capabilities to act on them.

tabs

A node-detail tab mounts on a node’s detail panel. It works on any node profile. Use it for a configuration or status surface that belongs to one node. What it does. Adds a tab to the selected node’s detail panel, rendered as a sandboxed iframe scoped to that node. An optional profile list narrows which node profiles offer the tab.
Where it renders. The node detail panel, in the tab strip, when the node profile matches. With no profile the tab is offered on every profile. Capability. ui.slot.node-detail-tab.
The entry accepts id or key as its stable id. A tabs entry always resolves to the node.detail.tab slot; any slot field on it is ignored.

parameters

A parameter is a native, schema-driven form field Mission Control renders itself, with no iframe. The plugin declares the field’s type, bounds and widget; the host renders the control, validates and clamps the value, and writes it to the binding you name.
Where it renders. The plugin’s parameter panel on the node detail panel and in the cockpit quick-settings surface, grouped by ui.group and ordered by ui.order. Capability. No ui.slot.* for the native form itself. A parameter bound to engine.detector switches the shared vision detector. The schema, the widget set, visible_if and the bindings are on the parameter schema reference.

settings

A settings section groups native parameters under a heading. Use it when a plugin has more than a handful of parameters.
Where it renders. The Extensions section of the Settings page. Sections are ordered by order. Capability. ui.slot.settings-section.

panels

A panel mounts the plugin’s iframe bundle into the slot each entry names. Unlike tabs, which always resolve to node.detail.tab, a panel can target any iframe slot.
Where it renders. In the named slot; see the slot taxonomy. The common choices are fc.tab (a tab in a drone’s Setup tab), hardware.tab, settings.section (an iframe section; use settings for a native one), cockpit.panel and cockpit.widget (default zone bottom-left). Capability. The ui.slot.* capability of the slot you name, for example ui.slot.fc-tab or ui.slot.cockpit-widget.

overlays

A video overlay draws on top of the live video. Use it for detection boxes or a HUD. What it does. Mounts the plugin’s iframe above the video player, letterbox-corrected so plugin geometry lines up with the video pixels. For vector marks (boxes, reticles, labels) the bridge’s cockpit.marks method composites them into one shared layer instead.
An overlays entry implies the video.overlay slot. Where it renders. Above the live video in the cockpit. Capability. ui.slot.video-overlay.

notifications

A notification channel lets the plugin push alerts into Mission Control. What it does. Registers a named channel. The GCS half publishes into it with ctx.notifications.publish; messages appear as toasts.
A notifications entry implies the notification.channel slot. Mission Control reads only id, title, icon and order from the entry. Severity is set per message on the ctx.notifications.publish payload (info, warning, error, success or critical). Capability. ui.slot.notification-channel.

mission_templates

A mission template adds an entry to the planner’s pattern editor.
Where it renders. The planner’s pattern editor. Capability. ui.slot.mission-template.
A template only registers the entry. A mission built from it goes through the normal pre-upload validation and operator approval before it reaches the aircraft.

map_overlays

A map overlay draws on the map: polygons, markers or heatmaps.
Where it renders. The flight map and the planner map, as a layer above the base map. Capability. ui.slot.map-overlay.

models

A model registration adds a vision model to the catalog the agent’s vision engine selects from, with per-board variants. Use it when a plugin ships its own detector rather than relying on the built-in catalog. What it does. Registers a model id for a vision task with one or more per-board variants. The agent selects the variant whose board_match fits the running board, downloads it from source, and verifies it against sha256. A model parameter then lets the operator switch the active detector.
Where it renders. No slot of its own. The model shows up in the picker a model parameter renders, and feeds the agent’s vision engine. Capability. None on the GCS half. The agent half needs the vision capabilities that consume it (vision.frame.read, vision.detection.subscribe), and a model parameter must bind to engine.detector to switch the active detector.

agent_pages and node_surfaces

These two put a plugin’s pages where the built-in node pages live, rather than in a generic plugin tab. Both are rendered from the GCS bundle, so they need gcs.entrypoint.
agent_pages[]: node_surfaces[]:

Next steps

Parameter schema

Widgets, bindings and validation for native fields.

Scaffolder walkthrough

A plugin with a skill, a tab, parameters and a target action.

Permissions

The ui.slot.* capabilities and the rest of the catalog.

Manifest

Every manifest field in dependency order.
Last modified on October 11, 2026