
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.

Overview
Kolibri's network discovery — mDNS broadcast plus peer listening — is welded to zeroconf inside KolibriBroadcast and only runs inside the server ProcessBus. Extract a transport-agnostic NetworkDiscoveryBackend and a NetworkDiscoveryHook transport interface, so a platform can supply an alternative transport (e.g. Android native NSD) and run discovery outside the process bus. Zeroconf becomes the default-registered transport. Server-platform behaviour is unchanged.
Complexity: Medium
Target branch: develop
Context
KolibriBroadcast (kolibri/core/discovery/utils/network/broadcast.py) implements the zeroconf transport directly (Zeroconf, ServiceBrowser, ServiceInfo, interface/address handling).
- It also owns the transport-agnostic machinery: broadcast-id lifecycle, the
KolibriBroadcastEvents bus, and listener dispatch.
NetworkLocationListener (.../network/search.py) turns those events into DynamicNetworkLocation rows via the add_dynamic_network_location / remove_dynamic_network_location tasks.
NetworkLocationListener is already transport-agnostic.
ZeroConfPlugin (kolibri/utils/server/__init__.py:295) runs inside the server ProcessBus.
- It instantiates
KolibriBroadcast, attaches the listeners, and monitors address changes every 5s.
- The existing
NetworkLocationDiscoveryHook / NetworkLocationBroadcastHook are notification-only.
- There is no interface for supplying discovery.
The Change
- Define
@define_hook(only_one_registered=True) class NetworkDiscoveryHook: register(instance), update(instance), unregister(), start_listening(on_add, on_update, on_remove), stop_listening().
- Split
KolibriBroadcast into a concrete NetworkDiscoveryBackend (transport-agnostic) and a zeroconf transport implementing NetworkDiscoveryHook.
- Register the zeroconf transport as the default.
- Resolve the backend's transport through the hook, so a registered override replaces zeroconf.
- Keep zeroconf-specific concerns (interface/address monitoring,
.local LocalHostnameListener) in the zeroconf transport.
- Make
NetworkDiscoveryBackend constructable and start/stoppable outside KolibriProcessBus.
Out of Scope
- The Android NSD transport and service.
- Changes to
NetworkLocationListener / DynamicNetworkLocation / discovery-task behaviour.
- The notification hooks (
NetworkLocationDiscoveryHook / NetworkLocationBroadcastHook) — unchanged.
Acceptance Criteria
General
Testing
References
KolibriBroadcast, build_broadcast_instance — kolibri/core/discovery/utils/network/broadcast.py.
NetworkLocationListener, discovery tasks — kolibri/core/discovery/utils/network/search.py, kolibri/core/discovery/tasks.py.
ZeroConfPlugin — kolibri/utils/server/__init__.py.
AI usage
Drafted with Claude Code in an interactive design session. The author made every design decision in dialogue and verified the code references.
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Kolibri's network discovery — mDNS broadcast plus peer listening — is welded to zeroconf inside
KolibriBroadcastand only runs inside the serverProcessBus. Extract a transport-agnosticNetworkDiscoveryBackendand aNetworkDiscoveryHooktransport interface, so a platform can supply an alternative transport (e.g. Android native NSD) and run discovery outside the process bus. Zeroconf becomes the default-registered transport. Server-platform behaviour is unchanged.Complexity: Medium
Target branch: develop
Context
KolibriBroadcast(kolibri/core/discovery/utils/network/broadcast.py) implements the zeroconf transport directly (Zeroconf,ServiceBrowser,ServiceInfo, interface/address handling).KolibriBroadcastEventsbus, and listener dispatch.NetworkLocationListener(.../network/search.py) turns those events intoDynamicNetworkLocationrows via theadd_dynamic_network_location/remove_dynamic_network_locationtasks.NetworkLocationListeneris already transport-agnostic.ZeroConfPlugin(kolibri/utils/server/__init__.py:295) runs inside the serverProcessBus.KolibriBroadcast, attaches the listeners, and monitors address changes every 5s.NetworkLocationDiscoveryHook/NetworkLocationBroadcastHookare notification-only.The Change
@define_hook(only_one_registered=True) class NetworkDiscoveryHook:register(instance),update(instance),unregister(),start_listening(on_add, on_update, on_remove),stop_listening().KolibriBroadcastinto a concreteNetworkDiscoveryBackend(transport-agnostic) and a zeroconf transport implementingNetworkDiscoveryHook..localLocalHostnameListener) in the zeroconf transport.NetworkDiscoveryBackendconstructable and start/stoppable outsideKolibriProcessBus.Out of Scope
NetworkLocationListener/DynamicNetworkLocation/ discovery-task behaviour.NetworkLocationDiscoveryHook/NetworkLocationBroadcastHook) — unchanged.Acceptance Criteria
General
NetworkDiscoveryHookis a single-registration hook definingregister,update,unregister,start_listening,stop_listening.NetworkDiscoveryHookand registered as the default.NetworkDiscoveryBackendresolves its transport through the hook, using a registered override instead of zeroconf.NetworkDiscoveryBackendcan be constructed and started/stopped without aKolibriProcessBus.DynamicNetworkLocationadd/update/remove regardless of transport.ZeroConfPluginare unchanged.Testing
NetworkLocationListenerwith a fake transport, and transport resolution (default vs override).References
KolibriBroadcast,build_broadcast_instance—kolibri/core/discovery/utils/network/broadcast.py.NetworkLocationListener, discovery tasks —kolibri/core/discovery/utils/network/search.py,kolibri/core/discovery/tasks.py.ZeroConfPlugin—kolibri/utils/server/__init__.py.AI usage
Drafted with Claude Code in an interactive design session. The author made every design decision in dialogue and verified the code references.