> ## Documentation Index
> Fetch the complete documentation index at: https://docs.altnautica.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Event hooks and bus

> Topic taxonomy, capability-token RBAC, delivery, and back-pressure handling.

The event bus is how the host pushes data to agent plugins and how
plugins publish to each other. This page is the topic-by-topic reference.
For the GCS-side envelope and RPC mechanics, see
[event hooks](/developers/event-hooks).

## Topic taxonomy

Every event has a dotted topic name. The first segment is the namespace.
The host owns every namespace except a plugin's own.

| Namespace       | Owner  | Purpose                                              |
| --------------- | ------ | ---------------------------------------------------- |
| `mavlink.*`     | Host   | MAVLink message stream.                              |
| `vehicle.*`     | Host   | Canonical vehicle events (mode change, arm, disarm). |
| `mission.*`     | Host   | Mission lifecycle.                                   |
| `safety.*`      | Host   | Safety events.                                       |
| `gps.*`         | Host   | GPS events.                                          |
| `sensor.<id>.*` | Host   | Per-sensor events.                                   |
| `vision.*`      | Host   | Vision engine events.                                |
| `video.*`       | Host   | Video pipeline state.                                |
| `swarm.*`       | Host   | Swarm coordination events.                           |
| `agent.*`       | Host   | Agent lifecycle (`agent.ready`, `agent.shutdown`).   |
| `gcs.*`         | Host   | GCS-originated events.                               |
| `plugin.<id>.*` | Plugin | The plugin's own published topics.                   |

A plugin cannot publish into the host namespaces. A plugin's own topics
live under `plugin.<id>.*`.

Wildcards apply a trailing `.*`: `mavlink.*` matches `mavlink.heartbeat`
but not the bare `mavlink`.

## Capability RBAC

Subscribing requires the `event.subscribe` capability, and the topic must
be allowed for this plugin. The allowlist is the union of:

* The plugin's own `plugin.<id>.*` namespace (always allowed).
* A fixed set of public topics any plugin may subscribe to:
  `vehicle.armed`, `vehicle.disarmed`, `vehicle.mode_changed`,
  `vehicle.battery_low`, `vehicle.geofence_breach`, `mission.started`,
  `mission.completed`, `mission.aborted`, `agent.ready`, `agent.shutdown`.
* Any extra topics the supervisor seeds from the plugin's manifest.

Publishing requires `event.publish` (the plugin's own `plugin.<id>.*`
topics are always publishable). These namespaces are reserved and a
plugin may never publish into them: `vehicle.`, `mavlink.`, `mission.`,
`safety.`, `agent.`, `swarm.`, `gps.`.

The host re-resolves the required capability from the topic, not from the
plugin's say-so.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# manifest grants: event.subscribe, event.publish
async def on_start(self, ctx) -> None:
    await ctx.events.subscribe("vehicle.armed", self._on_armed)
    # publish into your own namespace so other plugins can subscribe;
    # the topic is delivered verbatim, the host does not rewrite it
    await ctx.events.publish(
        f"plugin.{self.plugin_id}.alert", {"kind": "cell_low", "v": 3.4}
    )
```

## Telemetry

Subscribe to telemetry through the telemetry surface, gated by the
`telemetry.read` capability on the agent (or `telemetry.subscribe` on the
GCS half). Per-topic GCS grants use the `telemetry.subscribe.<topic>`
form, as in `telemetry.subscribe.battery`. Representative topics include
battery, gps, attitude, position, and system; treat the exact payload
fields as the live telemetry shape, not a frozen contract.

## Delivery and back-pressure

Each subscriber has its own bounded queue (256 messages deep). The bus
fans out without blocking the publisher: when a subscriber's queue is
full the event is dropped and the host logs a warning rather than stalling
the producer. Telemetry and raw streams are therefore best-effort. If
your plugin needs a complete record, persist from a recording rather than
trying to capture every live event.

To avoid dropping, do not block in the event handler. Hand work to a
background task and let the handler return quickly:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
async def on_start(self, ctx) -> None:
    queue: asyncio.Queue = asyncio.Queue(maxsize=64)
    asyncio.create_task(self._worker(queue))

    async def _ingest(sample: dict) -> None:
        try:
            queue.put_nowait(sample)
        except asyncio.QueueFull:
            pass  # drop locally; do not block the bus

    await ctx.events.subscribe("vehicle.battery_low", _ingest)
```

## Plugin-to-plugin

Plugins publish into their own `plugin.<id>.*` namespace. Another plugin
subscribes to that namespace only if it declares `event.subscribe` and
the operator approves, and the supervisor has the subscriber's allowlist
seeded for that topic. Plugin topics are derived data on a sandboxed bus;
they never command the vehicle.

## See also

* [Event hooks](/developers/event-hooks)
* [Permissions](/developers/permissions)
* [State and storage](/developers/state-and-storage)
