Skip to main content
A plugin moves through a small set of recorded states. The host is the state machine; the plugin reacts to lifecycle hooks the runner calls.

States

The supervisor records one status per installed plugin in /var/ados/state/plugin-state.json: Removal deletes the install entry rather than moving it to a state.

Parse before install

The install flow is deliberately two-stage:
  1. Parse: the host opens the archive in memory, validates the manifest, verifies the Ed25519 signature, and returns a summary. Nothing is written to disk.
  2. Install: only after the operator approves the requested permissions does the host commit the install. The agent unpacks the archive into /var/ados/plugins/<id>/; the GCS records the install in the operator’s profile.
A malicious archive cannot leave traces just by being previewed. The dialog runs parse; the Install button commits.

Enable and disable

Enable is the first time the plugin actually runs. For a subprocess plugin the agent generates a systemd unit (ados-plugin-<id>.service), writes it under /etc/systemd/system/, reloads the daemon, and starts the unit inside the shared ados-plugins.slice. The GCS host sets the status to enabled and mounts the iframe in every contributing slot. Disable stops the unit and unmounts the iframe. State on disk persists. Re-enable resumes from where it left off.

Failure and the start limit

The per-plugin unit restarts on failure (Restart=on-failure, RestartSec=2s). If it exceeds the start limit (5 starts within 60 seconds) systemd stops restarting it and the supervisor records the plugin as failed. The plugin does not auto-recover from that; the operator inspects the logs and decides whether to re-enable, remove, or investigate. Auto-recovery would mask the underlying bug.

Lifecycle hooks (agent half)

Every hook is optional. The runner looks each one up on your plugin instance at the right point in the process lifecycle and awaits it if it returns a coroutine; a hook you do not define is simply skipped. The runner is one process per plugin. Each time the unit starts, the runner calls the startup hooks in a fixed order, waits for the shutdown signal, then calls the teardown hooks. It does not persist a marker across restarts, so the full sequence runs on every process start. Most plugins only need on_start and on_stop. The runner keeps the process alive between on_start and on_stop until the supervisor stops the unit. A built-in agent plugin is a plain class (no base class to subclass) named by the module:Class entrypoint; a file-path entrypoint loads a class named Plugin. The ctx argument is the plugin context (see event hooks and bus).

Lifecycle hooks (GCS half)

The GCS half exposes mount and unmount through definePlugin:
unmount runs when the host disposes the iframe (operator disabled the plugin, navigated away, or removed it). Use it to flush in-flight state.

Remove

ados plugin remove <id> (or the GCS button) tears the plugin out:
  1. Stop the unit if running.
  2. Delete the unit file (and any declared extra-service units). Reload the daemon.
  3. Remove the install directory /var/ados/plugins/<id>/.
  4. Drop the install entry from the state file.
--keep-data additionally retains the plugin’s log file. The plugin’s data directory under /var/ados/plugin-data/<id>/ is not deleted by remove, so a reinstall can pick up where it left off.

Configuration changes

On the agent side, the config you receive is loaded once when the process starts. The runner reads it from disk and passes it to on_configure(ctx, config) during startup. To pick up a later edit without a restart, read live values through ctx.config at the point of use rather than caching the dict from on_configure. On the GCS side the host emits a config.changed event that your plugin subscribes to with ctx.config.onChange, so the iframe can react to an edit while it stays mounted.

State observability

Every transition is recorded. Operators see the plugin’s history through ados plugin info <id> and ados plugin logs <id> on the agent, and on the plugin detail page in Mission Control.