Skip to main content
A plugin has up to two halves: an agent half that runs on the drone or ground node, and a GCS half that runs in the Mission Control browser. The agent half is written in Python (the ados.sdk package) or Rust (the ados-sdk crate); the GCS half is written in TypeScript (the @altnautica/plugin-sdk package). One signed archive carries both halves and one manifest.yaml describes them. Four primitives describe every plugin in ADOS: a manifest, a signature, a sandbox, and a set of capability tokens. If you understand those four, the rest of the system follows.

Manifest

A manifest.yaml at the root of the archive declares everything the host needs to install the plugin: the id, the version, which halves (agent, gcs, or both), the permissions each half requests, and the slots the GCS panels mount into. The manifest carries no per-asset hash list. Asset integrity is bound by the canonical payload hash that the signing step writes into the separate SIGNATURE file (see below). The host validates the manifest against schemas/plugin-manifest.schema.json before unpacking anything. A malformed manifest is rejected before any file is written to disk. See manifest reference for the full field list.

Signature

The archive is an Ed25519-signed zip. Two steps produce it:
  1. Pack. Zip the plugin tree (manifest plus the agent and GCS halves) into a .adosplug. No hashes are written into the manifest at this step.
  2. Sign. Compute the canonical payload hash (a SHA-256 over the path-sorted <path>\n<sha256-hex> of every archive entry except the signature file itself), sign that 32-byte digest with an Ed25519 private key, and write a separate SIGNATURE file into the archive. The SIGNATURE file has two lines: the signer key id, then the base64 signature.
On install the agent recomputes the payload hash and verifies the signature against its trust list. First-party publishers (e.g. altnautica-2026-A) are pre-trusted. Third-party keys must be added explicitly. Unsigned archives install only when the agent is in developer mode (red banner, manual toggle).

Sandbox

Each half runs in a separate sandbox.
  • Agent half: a subprocess under ados-supervisor. A Python plugin runs through the plugin runner; a Rust plugin (runtime: rust in the manifest) runs its own compiled binary directly. Either way the subprocess sits in the shared ados-plugins.slice cgroup, which caps CPU percent, memory, and PIDs. The generated systemd unit adds privilege hardening: NoNewPrivileges=yes, ProtectSystem=strict, ProtectHome=yes, PrivateTmp=yes, LockPersonality=yes, RestrictRealtime=yes, and RestrictSUIDSGID=yes. The plugin reaches the host only through a Unix domain socket; it cannot open arbitrary network sockets unless it declared network.outbound.
  • GCS half: an <iframe sandbox="allow-scripts"> with no allow-same-origin. Null origin means no shared cookies, no shared storage, no DOM access to the host. The host serves the plugin bundle with a Content-Security-Policy that constrains what the frame can load. The plugin reaches the host only through postMessage, and the host validates every envelope.
The sandbox is the boundary that turns a manifest’s permissions into real authority. The plugin cannot lie about what it can do.

Capability tokens

Permissions in the manifest become capabilities at runtime. When the operator approves a permission, the host mints a capability token: a short string bound to the plugin id, the granted capability set, the plugin’s session, and an expiry, signed with HMAC-SHA256 under a per-session secret. The token carries a TTL (10 minutes by default). The plugin presents the token (or an automatically attached one) on every privileged call, and the host re-checks the HMAC and the expiry on the critical path before the call runs. Why tokens and not just a permission flag? Because they expire. Because they bind to a session, so a stolen token does not work in a later session. Because they let the host audit which call exercised which permission. For the wire shape and the validation pipeline, see event hooks and the permissions reference.