Skip to main content
A plugin can only do what its manifest declares and the operator grants. The capability catalog is generated from one source (capabilities.toml) into the agent (Python and Rust) and Mission Control (TypeScript), so the halves cannot drift. This page is the canonical list of capabilities, their counts and their risk levels. There are 53 agent capabilities and 26 GCS capabilities. The GCS set is 13 UI slot capabilities plus 13 data, command, cloud and bus capabilities. A plugin can also define capabilities of its own for the data it shares (see Plugin-declared capabilities).

Risk levels

Every capability carries a risk level. The install dialog badges each requested capability by its level. The manifest also declares a top-level risk for the whole plugin (low, medium, high or critical, default medium).

Declaring permissions

Permissions go in the agent.permissions and gcs.permissions lists. Each entry is an object with an id, an optional required flag and an optional degraded_behavior; a bare string means required.
Required permissions are pinned on in the install dialog. Optional permissions are shown with a toggle the operator sets. An id that is not in the catalog is a warning, not an error: the manifest loads, but the permission grants nothing.

How capabilities are enforced

44 of the 53 agent capabilities are enforced, by one of three mechanisms:
  • The dispatch gate re-resolves the required capability from the method on every request and rejects an ungranted call.
  • A handler-side check covers what a method alone cannot classify, such as an event topic or a MAVLink message id.
  • The generated unit’s sandbox covers the rest: the device policy, the socket address families and bind ports, and the mount namespace. See the security model.
The other nine are advisory metadata: mavlink.component.camera, mavlink.component.gimbal, mavlink.component.payload, mavlink.component.peripheral, sensor.camera.register, sensor.depth.register, sensor.lidar.register, sensor.imu.register and sensor.payload.register. GCS capabilities are enforced by the Mission Control bridge, which resolves the capability each call needs and checks it against the grant.

The catalog

The table covers both halves. Rows whose Enforced column reads n/a are GCS capabilities; an id listed twice (such as event.publish or mission.write) exists on both halves, one row for each.

Telemetry topics

On the GCS half, declare one telemetry.subscribe.<topic> per stream you read (for example telemetry.subscribe.battery). The bridge checks the topic-scoped id exactly; the bare telemetry.subscribe grants no stream.

Commands and designation

command.send lets a GCS half ask for takeoff, land or return-to-launch on its bound drone; the operator confirms each one and every other command is refused. Retargeting the drone’s follow tracker (command.send with vision.designate) needs the separate vision.track.designate capability.

Node-scoped UI slots

ui.slot.node-detail-tab, ui.slot.node-agent-page, ui.slot.node-surface, ui.slot.cockpit-panel, ui.slot.cockpit-widget and ui.slot.flight-skill are scoped to the selected drone; the other seven are fleet-level. Where each slot renders is on Contribution points.

Plugin-declared capabilities

A plugin that shares data on the event bus can define a capability for it under agent.declared_capabilities, with an id of the form plugin.<leaf>.<name> (the leaf is the last segment of the plugin id), a risk and a description. Its shared_topics name that capability as the one a subscriber needs. Another plugin requests it like any catalog capability, and the install dialog shows it with the declared risk and description. The World Engine, for example, declares plugin.world-engine.world.read for its point cloud, occupancy, splat and mesh topics. See Shared topics and declared capabilities.

Two-stage install

  1. The operator opens the drone’s Extensions tab and chooses Install from file, or picks an extension from the list.
  2. The agent parses the archive in memory: it validates the manifest, verifies the Ed25519 signature, checks compatibility, and returns a summary with the requested permissions, the signer and the risk. Nothing is written to disk.
  3. The review shows the summary, the board compatibility and the permission grid grouped by category, with required permissions pinned. The operator sets the optional toggles and chooses Install, a button that names how many permissions it grants.
  4. Only then does the agent unpack the archive and write the install record, and Mission Control grants the approved permissions.
A plugin that never gets past step 3 leaves no trace. From a shell, ados plugin install shows the same summary and asks for approval; see the Plugin CLI reference.

Permissions on update

Auto-update does not apply a version that asks for new permissions; the node reports update_available with the new permissions, and the operator reinstalls to approve them. Grants are recorded per permission, independent of enable and disable. An operator can grant or revoke a declared permission at any time from Mission Control or with ados plugin perms; the change takes effect at once, with no restart.

Capability tokens on the wire

Every plugin process runs with a capability token the host mints, bound to the plugin id, the granted capability set, a session id and an expiry. The host checks the token and the required capability before routing each request. A plugin cannot claim a capability by lying in the envelope: the host re-resolves the required capability from the method (and, for the event bus, from the topic) and rejects an ungranted call. The agent replies capability_denied: <cap>; the Mission Control bridge replies permission_denied.

Next steps

Manifest

Where permissions are declared, and every other field.

Security model

What each capability exposes if a plugin misbehaves.
Last modified on October 11, 2026