ados.sdk. The other agent-half language is Rust, with
the ados-sdk crate; both speak the same
length-prefixed msgpack wire and capability-token handshake to the
plugin host, so the choice is per plugin. Python is the right pick when
the plugin leans on the Python ecosystem (machine-learning inference,
scripting, fast hardware bring-up); Rust is the right pick for a tight,
low-overhead, long-running service.
A Python plugin’s agent half runs as a subprocess under
ados-supervisor. The public author surface is the ados.sdk
package: the typed driver base classes, the vision-engine client
types, and an in-process test harness. Import from ados.sdk, not
from internal agent modules.
Install
The standaloneados-sdk PyPI package is still in flight. Until it
publishes, plugin source vendors the contract types directly from the
agent tree at
altnautica/ADOSDroneAgent/src/ados,
or develops against a checked-out agent so import ados.sdk resolves.
What ados.sdk exports today
- Driver layer. The base classes hardware-driver plugins subclass, plus the dataclasses they exchange with the host. See driver layer and the per-kind pages.
- Vision.
VisionClientand the frame, detection, and model types a plugin uses to read frames from the vision engine and publish detections back. - Testing.
PluginTestHarness,FakeVisionEngine, andload_fixturelet you exercise a plugin in-process with no real agent.
The agent-half plugin shape
A plugin’s agent half is a plain Python class. There is no base class to import or subclass. The manifest’sagent.entrypoint points the
runner at it, in one of two forms:
module:Class, for code packaged as an importable module (follow_me:FollowMePlugin).- A path inside the archive (
agent/plugin.py), in which case the class must be namedPlugin.
ctx is duck-typed (see the warning above):
on_install, on_enable,
on_configure(ctx, config), on_start, then it waits for shutdown
(SIGTERM), then on_stop, on_disable. Most plugins implement
only on_start and on_stop.
ctx is the runtime-provided plugin context. It exposes the host
service helpers a plugin needs, including ctx.mavlink.subscribe(...)
and ctx.mavlink.send(...), ctx.events.subscribe(...) and
ctx.events.publish(...), ctx.vision.subscribe_detections(...) and
ctx.vision.designate_track(...),
ctx.peripheral_manager.register_*_driver(...), ctx.config, and
ctx.process.spawn. Each call is gated on a manifest permission;
calling a method whose capability was not granted is rejected. Because
the context type is not yet published in ados.sdk, the reference
extensions declare a local Protocol for the parts they use. Read the
thermal camera and
gimbal extensions for the current shape.
A real skeleton
This is the Follow-Me reference plugin, trimmed to its lifecycle shape. It is a plain class the runner instantiates with no arguments.on_start
opens the subscriptions the plugin needs (FC pose over MAVLink, the
operator’s designate clicks over the event bus, the detection stream
from the vision engine) and launches a control loop; on_stop and
on_disable tear it down. Each subscription matches a manifest
permission (mavlink.read, event.subscribe,
vision.detection.subscribe, vision.track.designate).
altnautica/ADOSExtensions
under extensions/follow-me/.
IPC
The supervisor passes a Unix domain socket path in theADOS_PLUGIN_SOCKET environment variable, the capability token in
ADOS_PLUGIN_TOKEN, and the bound drone id in ADOS_PLUGIN_AGENT_ID.
The runtime opens the socket and speaks msgpack RPC over it:
capability_denied error naming the
missing capability.
Resource limits
The supervisor enforces the resource block from the manifest:ados-plugins.slice). The plugin sees them as hard caps; an
out-of-memory kill is reported to the host as a crashed lifecycle
event and trips the circuit breaker.
Testing
ados.sdk ships an in-process harness. It wires a real plugin
context to fake host stubs so a single pytest run drives the
plugin’s lifecycle hooks with no agent and no hardware:
- exposes
harness.context, thePluginContextto pass to the plugin’s hooks; - injects events with
await harness.publish_event(topic, payload)and captures the plugin’s output withharness.published_events(); - replays recorded scenarios with
await harness.replay_fixture(name_or_path)(load files withload_fixture); - grants and revokes capabilities at runtime with
harness.grant(...)andharness.revoke(...).
FakeVisionEngine stands in for the real engine
and lets a test push synthetic frames into a VisionClient.
Where the rest of the contract lives
The agent host modules ataltnautica/ADOSDroneAgent/src/ados/plugins/
define the install and runtime machinery the SDK sits on:
manifest(the Pydantic manifest schema)signing(Ed25519 verification + revocation list)archive(pack and unpack with traversal protection)state(persistent install and permission state)supervisor(lifecycle: install / enable / disable / remove)runner(the process entrypoint that loads a plugin and calls its hooks)
ados-sdk PyPI publish, which will re-export the contracts above and
add the context helpers once they stabilise.