Skip to content

Latest commit

 

History

History
533 lines (438 loc) · 37.7 KB

plugins.md

File metadata and controls

533 lines (438 loc) · 37.7 KB

Plugin system

Status (intentional at this stage)

The plugin host infrastructure is implemented and tested: wasmtime sandbox, manifest parsing, capability gating, HostApi imports, fuel budget, and epoch timeout isolation (plugin-host + log-hello / busy-loop examples).

No product content plugins have been built yet (allemannsretten camping-spot spec, marine traffic, weather overlays, bathymetry, sonar, RTL-SDR/APRS-adjacent guests, UI translation packs, animated icon packs, etc.). That is expected and intentional, not a bug or an oversight — the host exists so future contributors can ship those plugins independently without changing the navigation core. Country/region-dependent packs (camping, future driving-hour families, horse access, …) follow the reusable pattern in jurisdiction-rules.md. Product requirements for the system (not optional): users can enable/disable each plugin, and hardware-facing plugins can talk over USB and Bluetooth via the host — see Enable / disable and External device I/O. See Ideas for beneficial plugins below as an open invitation / roadmap, not as incomplete core features.

Navi runs untrusted extension code in a wasmtime sandbox (plugin-host), not in the routing / sensor / UI process address space as native code.

Guest plugins compile to wasm32-unknown-unknown and call a narrow HostApi via WASM imports. WASI filesystem and network are not linked — only the capabilities declared in the plugin manifest are wired. Host-owned code (Android service, native accessory) may open USB/serial/network and feed sanitized snapshots into the core; WASM guests must not get raw sockets.

Gate: wasmtime Android product link (Phase 5a)

Source of truth for this gate. docs/status.md only points here.

Current state (2026-09 Phase 5a)

  • plugin-host pins wasmtime major 48 (lockfile 48.0.3), with features cranelift + runtime only (default-features = false; no Winch, WASI, component-model, wat, cache, profiling, coredump, addr2line/demangle, parallel-compilation, or GC collectors — guests do not use Wasm GC).
  • navi-ffi (Android libnavi.so) links navi-plugin-host. The right-to-roam camping guest runs under Cranelift JIT on shipped ABIs (arm64-v8a, x86_64). navi-desktop / navi-linux still must not depend on navi-plugin-host (guarded by scripts/check-plugin-host-gate.sh).
  • Per-call isolation: fuel + epoch wall-clock + linear-memory ceiling (StoreLimits, default 16 MiB; camping guest 32 MiB). Trap / timeout / fuel / memory → plugin disabled for the session with a visible message; app never crashes.
  • Enable/disable: host-owned PluginEnableStore (default OFF). Disabling camping deletes filesDir/plugin_kv/camping_night.json. Weather / DATEX toggles remain on MapHudPrefs (untouched).
  • Guest .wasm is built from source via scripts/build-plugin-wasm.sh into app/src/main/assets/plugins/ (gitignored). No committed binaries; F-Droid recipe adds wasm32-unknown-unknown and runs the same script before assemble.
  • Runtime choice: Cranelift JIT from .wasm at load (Module::from_file). No AOT .cwasm in the APK (F-Droid simplicity; avoids ABI-specific precompile blobs). Pulley is not required for shipped ABIs; any future unsupported ABI fails closed (PluginError::UnsupportedAbi / plugin unavailable — never crash).
  • The wasmtime 29-era RustSec ignores remain cleared from deny.toml. Example-guest wee_alloc ignore remains for fixtures.
  • Feature / backend confirmation: cargo tree -p navi-plugin-host -e features -i wasmtime shows only cranelift and runtime (plus transitive std / unwinder / icache-coherence those enable). Only plugin-host declares wasmtime in the workspace.
  • Android aarch64 verification (kept green): CI plugin-host-android-aarch64 / scripts/plugin-host-android-aarch64-smoke.sh (NDK link + QEMU aarch64 Cranelift). Bionic on-device smoke was verified 2026-08-29 on SM-P613; re-run --adb after fuel/epoch/memory embedder changes.

Required before linking other product hosts

  1. Keep the aarch64 smoke green on the wasmtime pin you ship.
  2. Re-run scripts/check-plugin-host-gate.sh after any wasmtime or workspace dependency change.
  3. Before linking navi-desktop / navi-linux, wire the same HostApi + enable-store path and remove those crates from the premature-link guard in the gate script.

Crates

Crate Role
plugin-host Load manifest + .wasm, capability gate, fuel + epoch + memory, HostApi
plugin-sdk no_std guest helpers (host_log, host_position, …)
plugins/log-hello Reference plugin: one log line
plugins/busy-loop Reference plugin: infinite loop (isolation tests)
plugins/trap-guest Reference plugin: deliberate trap
plugins/memory-bomb Reference plugin: grow memory until limit
plugins/right-to-roam-camping Product camping guest (Phase 5a on Android); shared rule engine in plugins/right-to-roam-camping/engine (navi-right-to-roam-camping)
plugins/CATS-plugin/ CAT / CATS WASM guest — repeater select / auto-tune / network follow (CAT.md); host is navi-cat + navi-hamlib-sys
plugins/weather/ Weather plugin — Meteocons assets + guest scaffold; product HUD/map use host UniFFI (plugins/weather-plugin.md)
plugins/imu/ IMU guest (pitch / tilt / compass, mount calibration, display) on sensors_read; engine in plugins/imu/engine; staged into the APK by scripts/build-plugin-wasm.sh and fed by the Android SensorManager backend via navi-ffi (imu_plugin_*), default OFF (plugins/imu-plugin.md)
plugins/datex/ DATEX guest scaffold; host client in driver-break-core::datex (plugins/datex-plugin.md)

Manifest (plugin.json)

{
  "name": "log_hello",
  "version": "0.1.0",
  "entry": "plugin_main",
  "capabilities": ["log"],
  "fuel_limit": 5000000,
  "timeout_ms": 500,
  "wasm": "plugin.wasm"
}

Capabilities are validated before the module is instantiated. Unknown capability names reject the load. Requested capabilities must be a subset of the host policy set passed to PluginHost::load_dir.

Enable / disable (required)

Every installed plugin must be individually enableable and disableable by the user. This is a product requirement for the plugin system, not an optional per-plugin nicety.

Rule Detail
Per-plugin toggle Host UI (Tools / Settings) shows one on/off control per installed plugin (manifest name).
Persisted Enabled/disabled state is stored on device (e.g. plugin_kv / host preferences). Survives app restart.
Default Newly installed plugins start disabled until the user turns them on (opt-in), unless a ship checklist documents an exception.
Disabled = not called A disabled plugin is not invoked on route plan, tick, or event hooks. Its HostApi imports must not run. Capability grants alone do not keep it live.
Core without plugins Routing, map, GPS, and HUD must keep working with all plugins disabled (Design rules).
Load vs enable The host may still discover / validate a .wasm + plugin.json while disabled; enable only gates execution and side effects (audio, overlays, accessory I/O).

Future host API sketch (not in ABI yet): plugin_list / plugin_set_enabled(name, bool) owned by the Android/desktop host, not by guest WASM.

External device I/O — USB and Bluetooth (required)

Plugins that talk to hardware must be able to use USB and/or Bluetooth (including BLE where the device requires it). Guests never open raw sockets or raw HID/serial themselves — the host owns the transport and feeds sanitized data (or accepts sanitized commands) through capability-gated HostApi imports.

Rule Detail
Transports USB (USB-serial, USB accessory / AOA, wired UART over USB) and Bluetooth (Classic SPP and/or BLE GATT) are first-class plugin I/O paths.
Host-mediated WASM guests request open/read/write/close via HostApi. Host opens the OS device, enforces permissions, rate-limits, and may disconnect on disable / app background policy.
User consent Pairing, USB permission dialogs, and “allow this plugin to use accessory X” stay in the host UI. Disabling a plugin closes its sessions.
No silent TX Radio CAT, OBD write, or any transmit path stays gated (read/query free where safe; TX only with explicit arm — see CAT / ECU ideas below).
Offline routing Accessory I/O must not block T2 UI or A*. Dropped links degrade the plugin feature, not core nav.

Proposed capabilities (not in ABI yet)

Proposed Purpose
accessory_list List paired / attached USB and Bluetooth devices the host is willing to expose
accessory_open Open a session (plugin id + device id + mode: usb-serial / bt-spp / ble)
accessory_read / accessory_write Exchange bytes or framed messages; host may impose max length / rate
accessory_close Release the session (also implied when the plugin is disabled)
accessory_events Optional push of connect/disconnect / permission-denied

Until those land, host-native services (as already sketched for ECU Bluetooth / USB, CAT via Hamlib — see CAT.md — and DIY e-bike USB-serial) may open the link and push snapshots into core; a future WASM guest then only calls ecu_read / cat_vfo_set / ebike_telemetry_read-class imports.

Specs that need a cable or radio (ECU, CAT, ebike_telemetry, lora_convoy, APRS TNC, future instruments) must document which transport(s) they use and that they honour enable/disable (sessions closed when off).

Debug files (USB/MTP)

On-device diagnostic and debug artifacts must be USB/MTP-retrievable without adb, under the same shared tree as the core diagnostic session log (debugging.md):

Writer Path
Core (Tools → Diagnostic logging) Documents/debug/navi_session_YYYY-MM-DD_HH-mm-ss.log
Plugin Documents/debug/<plugin-name>/…

Examples:

Documents/debug/navi_session_2026-07-31_12-52-13.log
Documents/debug/right-to-roam-camping/session_….log
Documents/debug/safety-resupply/last_run.json

In a file browser / MTP mount:

Internal storage → Documents → debug → <plugin-name> → …

Rules for plugin authors:

  1. Use a stable folder name matching the plugin manifest name (lowercase, hyphen or underscore — same string users will see on USB).
  2. Prefer Documents/debug/<plugin-name>/. If the host falls back to Download/debug for the core log, plugins must use that same root’s debug/<plugin-name>/ tree.
  3. Do not write plugin debug files into app-private storage only, into the core navi_session_*.log file, or into a top-level /debug folder (not creatable without MANAGE_EXTERNAL_STORAGE).
  4. The current log HostApi import goes to the host logger (logcat / host process); durable USB-visible files need a future host capability (or host-owned code writing into Documents/debug/<plugin-name>/ on the guest’s behalf). Specs that mention “diagnostics” should target this layout.

Capabilities (HostApi) — implemented today

Capability Import Purpose
log navi.log(ptr, len) UTF-8 log line to the host
position_read navi.get_position(out_ptr) -> i32 Write lat,lon as two little-endian f64
poi_query navi.poi_query(...) JSON POI list into guest buffer
poi_write navi.poi_write(ptr, len) Upsert POI from guest JSON

Isolation limits

  • Fuel: instruction budget (DEFAULT_FUEL = 5_000_000 unless overridden).
  • Wall-clock: epoch interruption (DEFAULT_TIMEOUT_MS = 250 unless overridden).

A plugin that busy-loops is terminated with CallOutcome::FuelExhausted or CallOutcome::Timeout. Isolation is covered by plugin-host/tests/isolation.rs (load→call→return for log-hello; kill + host-thread heartbeat for busy-loop).

Building a reference plugin

cargo build --release --target wasm32-unknown-unknown \
  --manifest-path plugins/log-hello/Cargo.toml

Copy the produced .wasm next to plugin.json as plugin.wasm, then:

cargo test -p navi-plugin-host --test isolation -- --nocapture

Ideas for beneficial plugins

None of the plugins below are shipped yet. They are the intended extension surface: each should stay sandboxed (or host-side with a thin capability), push normalized data into core stores, and never starve T2 UI/audio. Protocol and DSP docs already exist where noted.

1. APRS (aprs / aprs_sdr)

Benefit Live tactical positions, weather beacons, short messages on map
Docs to implement APRS.md (fields, TrackStore range), APRS-SDR.md (AFSK/AX.25 stages, IF offset), crate rtl-sdr-rs for IQ
Host duties Own RTL-SDR / TNC; decode frames; upsert TrackStation
Guest duties Optional: filter/annotate beacons, map symbol keys, messaging UI helpers
Proposed caps position_read, track_upsert (new), log; network/USB stay host-side
Related work SDRoxide issue #150 — Navi asked about an APRS plugin; upstream is considering APRS as built-in with the decoder in its own crate, which this plugin could reuse rather than duplicating AFSK/AX.25

Range display already clamps to 50–150 km in core — plugins must respect that (no global dump onto the map).

2. Weather (weather)

Benefit Current conditions / alerts along route (wind, precip, temp, pressure)
Docs plugins/weather-plugin.md — asset layout, provider mapping. Icon purposes: plugins/weather-icons-reference.md
Assets (vendored) plugins/weather/icons/ (static) and plugins/weather/animated-icons/ (SMIL); refresh via scripts/vendor-meteocons.sh
Providers MET Norway Locationforecast (primary) → Open-Meteo failover. Attribution without the “Yr” brand.
Host duties HTTPS fetch (opt-in), SQLite cache, rate-limit / Expires+IMS; resolve fill/{slug}.svg; HUD chip + optional city map symbols
Guest duties Scaffolded WASM guest (plugin.json); product APK does not load plugin-host yet
Caps position_read, weather_read, log (in ABI; unused by product until wasmtime gate lifts)
Offline Last-known cache only; no silent background refresh without user opt-in
Shipped UI Map settings → Plugins and Tools → Plugins: Weather overlay (default OFF); nested Show weather symbols on map (default OFF; place:city, zoom ≤ 8, cap 10, 56 px, nearest-to-center); Nearby attractions (default OFF; nested Hide when hours unknown); DATEX roadworks (default OFF)
Not shipped SMIL / other icon styles; town/village tiers; viewport-batching; corridor overlay; safety-resupply WBGT hookup; product plugin-host link

APRS WX beacons (b/t/h keys) remain a radio-side path; this plugin is the internet weather overlay.

2b. DATEX road situations (datex)

Benefit Roadworks / closures / incidents along the planned corridor from NPRA DATEX II
Coverage Norway only today (NPRA). Other national DATEX feeds are not integrated
Docs plugins/datex-plugin.md — client contract, how to add DATEX services / cadence, active vs inactive
Server navi-server optional DATEX redistributor (--apply-datex); caches XML; clients GET /datex/ only
Host duties Plain HTTP GET (pack_server); parse; classify DatexImpact; CorridorBand filter; overlay active; planner via planner_impacts
Guest duties Scaffolded WASM guest (plugins/datex/); product APK does not load plugin-host yet
Caps log, position_read (scaffold); future incident_* when ABI lands
Default OFF (DATEX_PLUGIN_DEFAULT_ENABLED = false)
Offline / failure Warn + disable overlay for the session; never block routing

3. Road info (road_info)

Benefit Closed roads, mountain convoy schedules, accidents / temporary hazards
Sources National road authorities, DATEX-II style feeds, OSM notes/highway=* diffs, user reports — always opt-in network
Research plugins/traffic-information.md — why a free / global / ~1-minute source does not exist today; RTL-SDR RDS-TMC / DAB-TPEG alternative under consideration
NPRA DATEX (via navi-server) plugins/datex-plugin.md — host GET of cached /datex/npra/GetSituation.xml (default OFF; no NPRA credentials on device)
Legacy direct-NPRA sketch plugins/datex-npra-client.md — do not use for product; credentials stay server-side
Host duties Fetch + validate; store incidents with bbox + expiry; DATEX uses pack_server read-only GET
Core effect DATEX: DatexImpact::{Ignore,Penalize,Block} on active situations → RouteOptions.datex_impacts (see datex-plugin.md)
Proposed caps position_read, incident_query / incident_write (new), log
UI Map banners + route recalc prompt; never rewrite the .pbf silently

4. CAT radio control (cat)

Benefit Set VFO frequency / offset / CTCSS from nearby NFM repeaters while driving
Path plugins/CATS-plugin/ — all guest logic here; wasmtime only
Docs CAT.md — RigBackend (TCP + FFI), latest-stable Hamlib lock, Android transports, read-back verification, auto-tune, network follow, onboard DB (OSM / AnyTone CSV / OpenRepeater / RadioID; RepeaterBook disabled). Test report / CSV path: cat-test.md
Host duties navi-cat + navi-hamlib-sys + USB/BT loopback / remote rigctld; never auto-TX (rig_get_ptt interlock; never rig_set_ptt / T); enforce gating + read-back even if the guest misbehaves; close sessions on plugin disable
Caps position_read, log, cat_status, repeater_query, cat_vfo_set, cat_network_follow
Safety Read/query free; TX inhibited; program only when PTT clear and read-back matches

Auto-tune summary (full detail in CAT.md): if a NFM amateur repeater is within 150 km, resolve output frequency, shift/offset, and CTCSS/DCS, then program VFO 1 only.

Same client/display split as the planned LoRa convoy plugin (Navi does not implement the RF/mesh layer): plugins/lora-convoy-spec.md.

5. ECU / EV telemetry (ecu)

Benefit Live fuel rate / SoC / power for eco reweight and range UI
Docs ECU.md — OBD-II, J1939, MegaSquirt examples → LiveEnergySnapshot
ICE fuel_rate_l_h from PID 5E / J1939 LFE / MS pulse-width
EV / hybrid state_of_charge_pct, power_kw (traction / HV), optional remaining range
Host duties Bluetooth SPP / USB / SocketCAN; read-only diagnostics; honour plugin enable/disable
Core effect refine_energy_cost / LiveEnergyProvider on T1
Proposed caps ecu_read (new), accessory_* (USB / Bluetooth), log — no DTC clear / programming

5b. DIY wired e-bike telemetry (ebike_telemetry)

Benefit Live assist power, pack SoC, regen, and DIY-computed remaining time/distance for Electric Cycle — supplements physics-based EbikeConfig estimates when a custom display/BMS is cabled in
Docs ebike-telemetry-diy.md — open $NAVIPWR ASCII over USB-serial (CAN optional); no open cross-vendor standard exists
Transport Wired USB-serial primary; CAN secondary; Bluetooth/BLE allowed when the DIY display/BMS exposes it — same host-mediated accessory_* path as ECU
Host duties Open UART/CAN/BT; parse checksummed $NAVIPWR; expose latest snapshot (WASM cannot open serial); close on plugin disable
Core effect Feed LiveEnergySnapshot-class SoC/power (+ optional remaining); physics climb/range stays default offline
Proposed caps ebike_telemetry_read (new) / host read_ebike_serial_telemetry(), log
Notes Spec only — not implemented. Distinct from reverse-engineering commercial Bosch/Bafang/STEPS buses (deferred, high maintenance).

6. Voice guidance (voice / voice_guidance)

Benefit Turn-by-turn spoken directions (pre-recorded clip packs only — no on-device TTS)
Docs voice-guidance.md — clip layout, fragment keys, storage estimates, localization open questions, rodio/cpal clip-playback spike
Host duties Audio output (rodio/cpal or Android-native fallback); load /sounds/<lang>/<gender>/; mute/volume + language/gender settings
Guest duties Optional: phrase assembly / pack selection; triggers from nav maneuver state
Proposed caps position_read, voice_speak / voice_pack_query (new), log
Notes Recorded clips are the only audio path (authored offline; English fallback if a language pack is missing). Spoken guidance is a legitimate foreground audio interruption (unlike silent background routing). Per-language concat vs whole-phrase clips is an open design question.

7. Right-to-roam overnight camping (right_to_roam_camping)

Benefit Suggest legal wild-camping positions along a route where a broad right-to-roam exists (Norway allemannsretten and country-aware packs)
Docs plugins/right-to-roam-camping-spec.md — intersection/track candidates, shared 150 m SafetyConfig, two-night plugin state, fire/foraging/leave-no-trace guidance, multi-country rules
Host duties Expose route/junction hints, POI/area queries, safety config, admin region, clock; render suggestion cards + disclaimer
Guest duties Rank road∩track seeds, walk short distance along track, filter by country rules, persist two-night keys, assemble guidance text
Proposed caps position_read, poi_query, route_read, safety_config_read, admin_region_read, clock_read, plugin_kv / storage, log
Notes Spec only — not implemented. Informational guidance, not legal advice. No Nordic wild-camp logic for England/Wales or Denmark. Country packs and “decline rather than guess” are the reference example in jurisdiction-rules.md.

8. Safety / resupply lookahead (safety / resupply_safety)

Benefit Before departure, warn when the largest gap between reliable fuel or water stops exceeds usable range (tank/load minus conservative buffer), with stricter buffers in remote/arid terrain
Docs plugins/safety-resupply.md — confidence scoring, Köppen/remote mode, buffer selection, lookahead, heat/water for foot travel, confirmation cache
Host duties Corridor POI scan, tank/water capacity, HUD chips / spoken summary, optional weather WBGT; persist confirmations
Guest duties Score POIs, decide remote mode, pick buffer, run lookahead gap detection, optional heat water estimate
Proposed caps position_read, poi_query, route_read, fuel_config_read, plugin_kv / storage, weather_read (optional), log
Notes Spec only — not implemented. Distinct from core SafetyConfig (POI radii / overnight distances). Conservative guidance, not a supply guarantee.

9. Instrument cluster / AGL signal export (instrument_cluster)

Benefit Export Navi nav state (speed, limit, overspeed chrome, next maneuver, ETA, break timing, eco, polyline, and merged approach warnings — road signs, children-zone proximity, speed cameras, seasonal closures) to open-source clusters and AGL via VSS/Kuksa.val, with a simple JSON fallback
Docs plugins/instrument-cluster-agl-spec.md — VSS mapping + Vehicle.Private.Navi.* (including Warning.*), navi.cluster.v1 JSON, host-mediated publish, AGL scope boundary
Host duties Assemble guidance + merged warning snapshot (same UniFFI / merge order as map chrome); implement Kuksa.val / loopback JSON / log sinks; user opt-in; never grant raw sockets to WASM
Guest duties Decide what/when to publish; call vehicle_signal_publish; enforce no-route clear for rest fields and clear warning leaves when chrome is hidden
Proposed caps nav_guidance_read (new), vehicle_signal_publish (new), position_read, log
Notes Spec only — not implemented. Export only (not ECU in; not alert audio). Not an AGL afm / Wayland packaging effort.

10. UI language / translation (i18n / ui_translation)

Benefit Offline UI string packs (BCP 47 locales) so the Compose host is not English-only forever
Docs plugins/i18n-translation-spec.md — catalog layout, fallback to English, host-owned lookup, when to show a language control
Host duties Load packs from {dataDir}/i18n/; resolve message ids in Compose; persist ui_locale; install packs via Tools (no WASM sockets)
Guest duties Optional: validate packs, suggest locale; must not fetch translations itself
Proposed caps i18n_catalog_query, i18n_string_resolve, i18n_locale_get / i18n_locale_set, plugin_kv / storage, log
Notes Spec only — not implemented. Today the app UI is English only and has no language toggle. Do not infer UI language from GPS/SIM. Parallel markdown (docs/Norwegian.md, etc.) is documentation, not in-app i18n.

11. Animated icons (animated_icons / icon_anim)

Benefit Synfig-authored motion for HUD / selected markers without putting a Synfig runtime in the routing core
Docs plugins/animated-icons-spec.md — Synfig → SVG frames / packs, host player, reduce motion; static Inkscape flow stays in icons.md
Host duties Load {dataDir}/icon_anim/{key}/ packs; advance frames; call existing SVG rasterize; respect reduce motion
Guest duties Optional: validate packs / choose keys; must not download packs or play .sif
Proposed caps icon_anim_query, icon_anim_frame, plugin_kv / storage, log
Notes Spec only — not implemented. Core still renders one SVG per rasterize_key call. Road-sign catalogue (no_sign_*) remains static NLOD art unless an optional anim overlay is added later.

12. Custom alert sounds (custom_alert_sounds / alert_sounds)

Benefit User-customizable short audio alerts for overspeed, road-sign approach warnings (including children-zone proximity fallback), speed cameras, seasonal closures, and future hazard categories
Docs plugins/custom-alert-sounds-spec.md — category mapping, sound pack layout, urgency-phase timing, host alert_sound_play capability
Host duties Shared rodio/Symphonia playback (same stack as voice guidance); phase-transition events; resolve {dataDir}/sounds/alerts/ files; audio focus / mute
Guest duties Map warning events → category → clip; per-category enable flags; debounce overspeed repeats
Proposed caps warning_event_subscribe (new), alert_sound_play (new), alert_sound_catalog (new), plugin_kv / storage, log
Notes Spec only — not implemented. One short tone at urgency phase entry (750/150/25 m model), not continuous audio through the approach window.

13. Horse trekking (horse_trekking / horse_trek)

Benefit Horse-scale water and support-service lookahead, per-protected-area access guidance, and field notes for equestrian trekking — while core Horse routing preference stays a soft cost model (prefer unpaved / bridleway / route=horse, town-bypass penalty)
Docs plugins/horse-trekking-spec.md — BRouter-informed cost preference (reuse network-pref shape), horse daily water volumes, Norwegian verneforskrift per-area rules, vet/farrier/stable POIs, Tysbast informational note; core profile walkthrough horse-profile.md
Host duties Corridor POI scan, protected-area queries, jurisdiction packs; render advisory cards + disclaimer; optional soft-pref weights when Horse profile exists
Guest duties Water-gap / support-service lookahead, protected-area pack lookup (decline if unknown), static toxic-plant content
Proposed caps position_read, poi_query, route_read, admin_region_read, protected_area_query (new), plugin_kv / storage, log
Notes Spec only — not implemented. Hiking remains the accepted interim stopgap and does not apply horse-specific access, pace, water, or park rules.

14. Adaptive speed warning (adaptive_speed_warning / speed_warning)

Benefit Escalating spoken overspeed alerts by percentage over the HUD’s applicable limit, with a long arm delay so routine overtakes do not nag, and faster disarm when the driver corrects
Docs plugins/adaptive-speed-warning-spec.md — overPct tiers, arm/disarm timers, GNSS/HUD floor, road-class modulation, split from custom-alert-sounds tones
Host duties Authoritative speed/limit/highway snapshot (road_near_info / OverspeedHud); voice_speak + optional overspeed earcon; audio focus / mute; USB debug under Documents/debug/adaptive-speed-warning/
Guest duties Tier state machine, arm/disarm, phrase-key selection; configurable constants in plugin_kv
Proposed caps road_speed_state_read (new), voice_speak / voice_pack_query, alert_sound_play, plugin_kv / storage, admin_region_read (optional), log
Notes Spec only — not implemented. Motor profiles only. Not a ticket predictor. HUD chrome stays display-only.

15. LoRa convoy status (lora_convoy / convoy)

Benefit Share location, speed, fuel, and vehicle battery charge across a convoy over a LoRa mesh so low fuel is visible to the rest of the group without requiring direct radio range
Docs plugins/lora-convoy-spec.md — Meshtastic client/display split (same shape as CAT), private-portnum VehicleStatus, two independent BLE sessions (radio vs Android companion), seq/stale table
Host duties BLE central to a Meshtastic-flashed node (meshtastic crate, bluetooth-le + tokio); separate BLE session for passenger Android GATT writes; encode/decode; convoy_store; overlay + warn thresholds; close both sessions on disable
Guest duties Optional: chip formatting / list sort after wasmtime gate; must not open BLE
Proposed caps accessory_* (two BLE sessions), convoy_status_read (new), position_read, ecu_read / ebike_telemetry_read (optional onboard), plugin_kv / storage, log
Safety Driver does not enter fuel/battery on the Navi device while moving — companion is passenger-operable. Mesh TX only while the plugin is enabled. Informational overlay, not collision avoidance.
Notes Spec only — not implemented. Navi never talks to raw LoRa modules. Recommended radio: Meshstick USB SX1262 TCXO stick (USB head units; unique identity, traceability, flat mount face) or BLE Meshtastic boards (tablets). Text messaging is a later arm on the same PortNum dispatch.

16. POI look-ahead cone (poi_lookahead / poi_cone)

Benefit Quiet "worth a look" discovery of attractions, fishing spots, craft breweries, and cider makers in a heading-driven cone ahead of the vehicle (with or without a route) — not a hazard warning
Docs plugins/poi-lookahead-cone-spec.md — 850 m / ±30° cone, General + Fishing + CraftBrewery filter, open-now opening_hours gate, separate from the 300 m hazard cone
Host duties Cone or radius+bearing POI query; evaluate or expose open-now; render quiet chips/markers; enable/disable
Guest duties Category filter, cone membership if host returns a radius set, hours policy, nearest-first list — no audio
Proposed caps position_read, poi_query, clock_read, plugin_kv / storage, log
Notes Host-native UniFFI + quiet HUD chip; WASM guest scaffold. Must suppress known-closed venues. Does not modify live_hazard.rs. brewery=cider is classified as CraftBrewery in core. Master toggle default OFF.

Capability sketch (not in ABI yet)

Proposed Purpose
track_upsert Push APRS / track stations into host TrackStore
weather_read Read cached weather samples near lat/lon
incident_query / incident_write Road closures / convoy / accident overlays
repeater_query Nearest NFM repeaters from onboard DB (+ optional RepeaterBook sync)
cat_vfo_set Ask host to program VFO 1 (frequency, offset, tone)
ecu_read Latest LiveEnergySnapshot
ebike_telemetry_read Latest DIY $NAVIPWR / wired e-bike snapshot (host owns serial)
voice_speak / voice_pack_query Queue guidance utterance or list installed voice packs
route_read Active corridor samples / junction hints for camping or resupply plugins
safety_config_read SafetyConfig (e.g. min_building_distance_m) for shared overnight distance
fuel_config_read Tank / energy capacity for resupply usable-range math
admin_region_read Country / county for lat/lon (right-to-roam rule pack)
clock_read Current date for seasonal fire-ban guidance
plugin_kv / storage Small per-plugin persist (e.g. two-night camping memory, POI confirmations)
nav_guidance_read Active route / maneuver / ETA / break / eco / polyline / merged approach warning / overspeed snapshot for cluster export
vehicle_signal_publish Ask host to publish VSS path/values or navi.cluster.v1 JSON (host owns Kuksa/UDP/WS)
i18n_catalog_query List installed UI translation packs
i18n_string_resolve Resolve message id (+ args) for the active locale
i18n_locale_get / i18n_locale_set Read/write persisted UI locale preference
icon_anim_query List installed animated-icon packs (key, fps, frames)
icon_anim_frame Resolve SVG bytes/path for key + frame index
protected_area_query Protected-area polygons / ids crossed by corridor (horse verneforskrift packs)
warning_event_subscribe Push approach-phase transitions for road signs, cameras, overspeed, closures
alert_sound_play Queue short alert clip by category (host owns audio device)
alert_sound_catalog List bundled + user override alert sound files
road_speed_state_read Speed, applicable limit, HUD overspeed flag, highway class, profile (adaptive speed warning)
accessory_list / accessory_open / accessory_read / accessory_write / accessory_close Host-mediated USB and Bluetooth (SPP/BLE) I/O for hardware plugins
convoy_status_read Last-known convoy table (position, speed, fuel/battery, seq, stale) for LoRa convoy UI
plugin_list / plugin_set_enabled Host-owned inventory and per-plugin enable/disable (UI + persistence)

Add a capability to plugin-host Capability enum + HostApi before shipping any guest that needs it. Until then, host-native services may write into core via UniFFI without WASM.

Design rules for all plugins

  1. Wasmtime ship gate: navi-ffi (Android) links plugin-host as of Phase 5a (Cranelift JIT, fuel+epoch+memory). Keep aarch64 smoke green and re-run scripts/check-plugin-host-gate.sh after wasmtime changes. Do not link navi-desktop / navi-linux until those hosts wire the same path (gate section). The crate pin is 48.0.3 with Cranelift-only features confirmed.
  2. Offline-first: network is opt-in; core routing must work with plugins disabled.
  3. Enable / disable: every plugin has a user-facing on/off control; disabled plugins are not executed and must release USB/Bluetooth sessions (Enable / disable).
  4. USB / Bluetooth: hardware-facing plugins use host-mediated USB and/or Bluetooth — never raw guest sockets (External device I/O).
  5. No silent map-data mutation: OSM extracts and graph caches change only via explicit user actions (osm-updates.md).
  6. Tier priorities: plugins run at T0/T1 priority budgets — never block UI.
  7. Privacy: no VIN / callsign / location upload unless the user enables it.
  8. Range discipline: map overlays respect the same ~150 km class of filters used by tracks and CAT repeater search unless the user raises a documented clamp.