Add bounded client app metadata admin messages#907
Open
gotnull wants to merge 1 commit into
Open
Conversation
Add ClientAppData message and four AdminMessage oneof fields (104..107)
giving companion apps a small, bounded, local-node-only place to persist
opaque app-defined state. Pair with LocalClientAppData on-disk wrapper
in localonly.proto and matching nanopb sizing.
Wire surface (additive):
message ClientAppData { string app_id = 1; uint32 version = 2;
bytes payload = 3; fixed32 updated_at = 4; }
AdminMessage.payload_variant:
ClientAppData set_client_app_data = 104;
string get_client_app_data_request = 105;
ClientAppData get_client_app_data_response = 106;
string delete_client_app_data_request = 107;
Limits: app_id matches ^[a-z0-9._-]{1,32}$, payload <= 512 bytes, max 4
records per node. updated_at is firmware-set on write (0 if no valid time).
Important: namespaced, not owned. Firmware enforces shape and capacity
but does NOT authenticate which client is writing. Any admin-capable
client may overwrite or delete any app_id. Clients must treat payloads
as untrusted, optional, and recoverable. Do not store secrets, identity
keys, paid-entitlement state, or any data used for security/routing/
authentication/purchase decisions.
Records are local-only by construction: never broadcast over LoRa, never
included in NodeInfo, never relayed via MQTT. Cleared by factory reset
via the existing /prefs wipe path.
buf format / lint / breaking against master all pass.
TODO(maintainer): confirm field-number allocation 104..107, record cap,
and whether remote authenticated admin should be allowed to read.
This was referenced May 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a small new wire surface so Meshtastic companion applications can ask their locally-connected node to persist a few opaque, app-defined metadata records on their behalf. The intent is to give companion apps an explicit place for non-secret convenience metadata, instead of overloading user-visible fields like
long_nameor unrelated configuration surfaces.This is intentionally namespaced, not owned: the firmware enforces shape, payload size, and record-count limits, but it does NOT authenticate which client is writing. Any admin-capable client may overwrite or delete any
app_id. Clients must therefore treat stored payloads as untrusted, optional, and recoverable.Companion to the firmware implementation PR (meshtastic/firmware#10392) and the RFC (Meshtastic/rfcs#12).
Wire / API shape
New top-level message in
meshtastic/admin.proto:Four new
AdminMessage.payload_variantfields:New on-disk wrapper in
meshtastic/localonly.proto:nanopb sizing in the
.optionsfiles:Limits
app_idregex^[a-z0-9._-]{1,32}$payloadmaxupdated_atfixed32unix epoch seconds, 0 when RTC is invalidWorst-case on-disk footprint =
meshtastic_LocalClientAppData_size= 2258 bytes.Namespaced, not owned
The firmware does not authenticate which companion app is making a write request.
app_idprevents accidental name collisions between apps; it does NOT prove caller ownership. Any admin-capable client may be able to write or delete anyapp_id.Clients must treat stored metadata as untrusted, optional, and recoverable. The companion app's own local/cloud/export storage remains the source of truth. Do not store secrets, identity keys, session keys, paid-entitlement state, trust authority, blocklists, or any data used to make security, routing, authentication, or purchase decisions.
Records are local-only by construction:
payload/prefswipe pathCompatibility
Wire-additive only. Existing clients that don't know about the new tags are unaffected. Older firmware that doesn't yet implement the feature returns
Routing_Error_NOT_AUTHORIZEDor no reply for the new tags; companion apps must treat that as "feature unavailable, fall back to app-local storage."No version bump. No renumbering. No breaking changes to existing types.
Validation
All three buf checks pass clean against
master. The firmware-side implementation regenerates nanopb output (committed in the firmware PR) and passes bothbash bin/test-native-docker.sh -f test_defaultandbash bin/test-native-docker.sh -f test_client_app_data(27 store-level tests covering CRUD, slot accounting, payload bounds, persistence, factory-reset semantic, and storage-error injection).Linked
Maintainer questions
Specifically requesting confirmation on:
sensor_config = 103. Happy to move if you have a different range in mind.app_idget-miss sentinel. A read of an unknown key returns aget_client_app_data_responsewhoseapp_idis empty. This avoids introducing a one-off response-envelope pattern for this single feature, but it is a minor novelty. Acceptable, or do you want to wait for a broader admin-wide status model?MESHTASTIC_EXCLUDE_CLIENT_APP_DATAcompile-out flag?Other open questions are listed in the RFC.