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
Amanifest.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:- 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. - 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 separateSIGNATUREfile into the archive. TheSIGNATUREfile has two lines: the signer key id, then the base64 signature.
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: rustin the manifest) runs its own compiled binary directly. Either way the subprocess sits in the sharedados-plugins.slicecgroup, 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, andRestrictSUIDSGID=yes. The plugin reaches the host only through a Unix domain socket; it cannot open arbitrary network sockets unless it declarednetwork.outbound. - GCS half: an
<iframe sandbox="allow-scripts">with noallow-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 throughpostMessage, and the host validates every envelope.