Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
hana_rigging
A Bevy kernel for durable device identity, presence, availability, and recovery policy. Hardware providers perform I/O and report their full device set to this crate; the crate does not enumerate or operate hardware itself.
Work in progress. This crate is in active development (v0.1.0) and not subject to semver stability guarantees. APIs will change without notice between commits. Do not depend on this in production code yet.
Rigging — the ropes, pulleys, and counterweights above a stage that hold the lights, screens, and scenery, and let an operator move any of them on cue. The rigging does not produce the light or the image; it is what everything hangs from, and what makes a fixture addressable by name instead of by where it happens to be hanging tonight.
The problem
Devices are addressed by whatever the platform hands you: monitor index 1, camera 0, "the nearest display". Those handles move. Unplug a projector and plug in a different one, and index 1 now points at another physical unit — so the saved window layout, the camera feed, or the DMX patch quietly drives the wrong device. Every subsystem then grows its own hand-rolled reconnect logic, and each one guesses differently about what "the same device" means.
hana_rigging makes the answer exact and shared. Identity is match-or-nothing:
a saved key that matches no live unit yields nothing, never a fallback. Nothing
enters service without an explicit authorization the kernel issued for that one
physical unit.
What it does
- Durable identity —
DeviceKeysurvives restarts and replugs, and records in its own type how much the identity can be trusted - Presence and reachability — present, absent, or unreachable-for-a-duration, merged across every provider that reports the same unit
- Discovery scheduling — on-demand, event-driven, or periodic scans, with bounded concurrency, coalesced reruns, and startup readiness gating
- Roles and bindings — application-stable
RoleKeys bound to device endpoints, so "the presenter display" outlives the display it currently means - Recovery policy — per binding, decide whether a saved configuration is forgotten, retained, reapplied on request, or reapplied when the unit returns
- Authorized applies — drivers configure hardware only through kernel-issued permits, on attempts the kernel starts, polls, deadlines, and retires
- Identity adjudication — when a replacement unit occupies a departed one's slot, the kernel raises a question for a human instead of guessing
- Entity mirror — every kernel fact is projected onto Bevy entities as read-only components, so change detection and remote inspection just work
Trust is part of the identity
A DeviceKey carries where its value came from, and that determines what the
key is allowed to authorize:
| Source | Where it comes from | What it can do |
|---|---|---|
Reported |
The unit published it — an EDID serial, a CoreAudio UID | Drive output |
Authored |
A human assigned it, for units that report nothing | Drive output |
Synthesized |
Derived from descriptors as a location hint | Restore saved configuration only |
That distinction is the point. A webcam with no serial gets a synthesized key, so its saved window position can come back — but it can never silently become the camera a recording writes to, because a location hint is not proof of which unit is plugged in.
Reconciliation turns a key plus live evidence into an IdentityVerdict:
Proven, RestoreOnly, Authored, Displaced (a same-kind unit took the
slot — a human decides), WrongUnit, or Unverified.
Usage
Add the plugin, register the identity schemes your providers are allowed to report, and register the reporters and drivers that touch hardware:
use *;
use *;
let mut app = new;
app.add_plugins
.add_plugins
.register_device_scheme;
let driver = app.add_endpoint_driver;
let reporter = app.add_device_reporter;
A reporter hands back its whole current device set each scan, never a delta. That is what lets the kernel conclude a device is genuinely gone rather than merely unmentioned this frame:
discover receives no World on purpose — it is the boundary that keeps
enumeration out of the kernel's own state.
Bind an application-stable role to a device endpoint, and state every policy explicitly. There are no implicit recovery defaults hiding in the kernel:
app.world_mut..register?;
Then read state off the mirrored entities, or observe the derived events —
DeviceArrived, DeviceDeparted, PresenceChanged, IdentityChanged,
RoleAwaiting, RoleAvailable, AttemptFinished, and the rest.
The rigging_kernel example is a complete headless run: two reporters pushing
overlapping scans that agree on one panel and disagree about everything else, an
authored inventory entry, one apply attempt driven to a terminal outcome, and a
provoked departure. It ships with the crate — cargo run --example rigging_kernel.
A second example, identity_decision, walks the displaced-unit adjudication
path end to end. It lives in the source repository
rather than the published package, because it drives the kernel with a scripted
device harness that is not itself published.
Schedule
RiggingPlugin chains five ordered sets in Update, exposed as
RiggingSystems so integration crates can place their own systems precisely:
Collect → Reconcile → Prepare → SessionLoss → Apply
Prepare is deliberately empty — it is the one interval where identity is
settled but no apply has started, which is where consumer systems build the
configuration they want applied.
Design rules
These are enforced, not aspirational:
- The kernel performs no I/O and knows nothing about any specific device kind
- Exact match or nothing — no nearest-monitor, no first-camera, no tolerance
- Scans are whole sets; absence is always a named variant, never
Option - The kernel never silently puts a device in service; the default policy is
Forget - Resources are authoritative, entity components are read-only mirrors
start_applyreturns immediately and every poll re-validates that the attempt still targets the same physical unit
Version Compatibility
| Version | Bevy |
|---|---|
| hana_rigging 0.1.0 | 0.19 |
License
hana_rigging is free, open source and permissively licensed!
Except where noted (below and/or in individual files), all code in this repository is dual-licensed under either:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
Your contributions
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.