BB and Jido both have an event mechanism. BB has BB.PubSub — a
hierarchical-path message broker. Jido has signals — CloudEvents-flavoured
structs routed by an agent's signal router. bb_jido translates the
former into the latter. This page explains why, and what the design
choices buy you.
Two systems, two vocabularies
BB.PubSub delivers Erlang messages with a uniform shape:
{:bb, source_path, %BB.Message{payload: payload, robot: robot, ...}}- The source path is a list of atoms — the publisher's full path
(e.g.
[:sensor, :joint_state]). - The payload is a domain struct:
BB.StateMachine.Transition,BB.Safety.HardwareError, sensor-specific structs, etc.
Jido signals are CloudEvents: a :type string plus a payload in :data,
plus standard envelope fields (:source, :id, :specversion, :time).
The agent's router dispatches by type-string pattern.
These two vocabularies don't translate one-to-one. PubSub is a transport — it doesn't care what the payload means. Signals are a protocol — the type carries semantic meaning.
Why a bridge instead of a Jido Sensor?
Jido provides a Jido.Sensor abstraction for ingesting external events.
On paper that's the obvious place to hook PubSub in. In practice it adds
a layer of indirection that buys nothing:
- The sensor runtime expects events to be injected via
Jido.Sensor.Runtime.event/2. But BB already delivers events as Erlang messages. - We'd be writing a sensor that does nothing but receive a message and forward it. The bridge code is the same; the sensor wrapper is dead weight.
So BB.Jido.PubSubBridge is a plain GenServer that subscribes to
BB.PubSub and casts forward via Jido.AgentServer.cast/2. A future
sensor wrapper remains possible if a future Jido feature genuinely needs
one — it's not a one-way door.
Canonical signal types
The bridge produces three families of signal type:
| When | Type | Why |
|---|---|---|
%BB.StateMachine.Transition{} payload | bb.state.transition | Specialised — agents almost always want to react to transitions specifically. |
%BB.Safety.HardwareError{} payload | bb.safety.error | Specialised — safety errors deserve their own type. |
| Anything else | bb.pubsub.<dotted source path> | Generic — preserves the path information but no semantic claim. |
The specialised types are stable. Even if a future BB version changes
where state transitions are published, the signal type stays
bb.state.transition. The generic bb.pubsub.* type is necessarily
coupled to the path layout — it's a fallback, not a contract.
The signal :source is /bb/<robot module>, following CloudEvents'
URI-like source convention. Traceability stays sane when multiple robots'
events end up on the same downstream bus.
Filtering happens before the agent
Three places to filter, from cheapest to most expensive:
- Topic allowlist — only subscribe to paths the agent needs. Filters inside BB's registry; non-matching topics never trigger any work.
- Message-type filter — pass
:message_typesso the registry only delivers matching payloads. - Bridge-side throttle —
:throttle_msdrops repeat signals of the same type within the window. Signals are still constructed; they're just not cast forward.
Filtering at the agent's mailbox is the wrong place. By the time the agent receives the cast, it's already paid the signal-construction cost, and the mailbox queue may already be backed up. The bridge owns the discipline.
Filtering happens outside PubSub for content
The bridge can't peek inside a payload — that would couple it to every
payload type in BB. If you need content-based filtering ("only IMU
readings on link 3 with temperature > 60"), do it in your action:
def run(%{message: %BB.Message{payload: payload}} = params, _ctx) do
case payload do
%BB.Sensor.IMU{frame_id: :link3, temperature: t} when t > 60 ->
handle_overheat(params.robot)
_ ->
{:ok, %{ignored: true}}
end
endThis keeps the bridge a thin pipe and pushes domain knowledge into the agent's action code, where it belongs.
See also
- Bridge additional PubSub topics — the operational steps.
- Signal types reference — full table of what gets emitted.
- BB's PubSub documentation.