Skip to main content
Hardware drivers sometimes need a closed-source shared library to talk to the device: a camera SDK, a LiDAR decompressor, a mount-control library. ADOS plugins can include these binaries, but the manifest must declare the inclusion so operators see the trust signal in the install dialog.

Declare the vendor binary

The agent half sets contains_vendor_binary: true and provides vendor_attribution. The two go together: the schema rejects one without the other (set the flag with no attribution and the manifest fails to load; set attribution with the flag false and it also fails). Both fields are schema version 2, so the manifest must set schema_version: 2. vendor_attribution is a list, so a plugin can attribute more than one upstream. The vision-nav extension ships two VIO backends and declares both:
There is no per-binary path or sha256 field in the manifest. The archive’s single SIGNATURE file covers every entry’s hash, so the vendor binary is protected by the same signature as the rest of the archive. license is the only required attribution field (it must be a non-empty string); the rest are optional provenance (name, source_url, source_offer_url, upstream_repo, upstream_version, commit_sha, notice). For a GPL-compatible upstream, set at least one of source_url or source_offer_url plus a version pin (upstream_version or commit_sha) so the install dialog can render a real source offer.

Trust signal in the install dialog

When contains_vendor_binary is true the install dialog shows the vendor attribution and labels the plugin as carrying a vendor binary rather than pure open source. The operator can still install, but the signal is loud.

Loading the binary at runtime

The agent unpacks the archive under the plugin’s install directory at /var/ados/plugins/<plugin-id>/. Resolve the binary relative to your plugin module and load it with ctypes:
The plugin runs inside its sandbox, so the binary cannot escape the plugin’s permission set. A vendor .so that opens a USB camera still requires the plugin to declare the matching capability (here hardware.usb.uvc).

Running the vendor code as a separate process

If the vendor code must run as its own process rather than load in-process, the plugin needs the process.spawn capability plus a subprocess_spawn allowlist. Entries are binary basenames, not paths. The plugin host rejects any ctx.process.spawn(...) whose basename is not on the list, and the manifest validator refuses to load if subprocess_spawn is set but process.spawn is missing from permissions.
Each basename resolves to <install_dir>/vendor/<basename>, so ship the binaries under agent/vendor/ in your archive and the extractor lays them out at /var/ados/plugins/<plugin-id>/vendor/<basename> after install. The host rejects shell metacharacters and any path-traversal attempt in a basename.

License note

Altnautica’s own open hardware files and developer docs are dedicated to the public domain under CC0 1.0; the agent and the GCS are GPL-3.0. A plugin that wraps a closed-source vendor .so is still under its own declared license in its own source files; the install dialog flags the vendor-binary inclusion separately so operators see it.

Architecture support

Nothing validates that the .so matches the target SBC architecture. Ship architecture-specific subfolders if your plugin runs on more than one:
And resolve at runtime:
Arch subfolders work for an in-process .so you load yourself with ctypes. A subprocess_spawn binary is different: the host resolves it at the flat path <install_dir>/vendor/<basename>, so per-arch spawned binaries need a wrapper script on the allowlist that picks the right arch, not a subfolder.

See also