Sovereign Wellbeing 3.0.0: Retiring Legacy Kinds, Hardening Micro-Relays, and Standardizing SNIP-10
- Sovereign Wellbeing 3.0.0: Retiring Legacy Kinds, Hardening Micro-Relays, and Standardizing SNIP-10
- Why Kind 30078 and Parameterized Replaceables Held Us Back
- Canonical Kinds Across All Six Applications
- 1. Holy Fit: Kind 1359 (Regular)
- 2. Nunlock: Kind 1342 (Regular)
- 3. Sister Charge: Kind 10343 (Replaceable) & Kind 1343 (Regular)
- 4. Cell-ibacy: Kind 1357 (Regular)
- 5. Saint Stream: Kind 36787, Kind 1073, & Kind 20344
- 6. The Habit: Kind 1345 (Regular)
- 7. Wellbeing Relay Discovery: Kind 10323 (Replaceable)
- End-of-Life (EOL) Roadmap: January 1, 2027
- Hardening the Go Micro-Relays
- Migrating Historical Telemetry: resign_historical_telemetry.py
- Ecosystem Metadata Alignment
- What Comes Next
Sovereign Wellbeing 3.0.0: Retiring Legacy Kinds, Hardening Micro-Relays, and Standardizing SNIP-10
Date: November 12, 2026
Period Covered: October 15, 2026 to November 12, 2026
Author: Stephen (with Antigravity)
Tags: nostr, wellbeing, android, snip10, go, release
Over the past four weeks, we overhauled the entire Sovereign Wellbeing stack. Today, we are tagging and releasing version 3.0.0 across all six native Android apps, their companion Go micro-relays, and the web dashboards.
The headline change in 3.0.0 is the formal transition to SNIP-10 v3.0.0 canonical event kinds. We are eliminating generic kind:30078 payloads and retiring messy 30k parameterized replaceable events in favor of dedicated regular and replaceable kinds. Alongside the schema migration, our Go micro-relays received major security and protocol upgrades, including NIP-62 (Request to Vanish) support, scoped Kind 5 deletion firewalls, anti-tamper ratchet checks, and historical event ingestion. We also wrote a standalone resigning utility to cleanly backfill years of legacy events, and aligned release metadata across F-Droid, Fastlane, Zapstore, and Gitea.
Here is the technical breakdown of what changed, why we made these decisions, and how the migration unfolds.
Why Kind 30078 and Parameterized Replaceables Held Us Back
When we started building the Wellbeing suite, Nostr lacked standardized event kinds for personal telemetry. Like many early projects, we leaned on NIP-78 kind:30078 (Arbitrary Custom App Data) and various arbitrary 30k parameterized replaceable kinds (30342, 30343, 30344, 34557, 30345). We stuffed application prefixes and ISO dates into the d tag (such as d="holyfit:2026-11-07") and placed telemetry numbers in the content string.
That design got us off the ground, but it created significant technical debt:
- Relay Query Bloat and Blind Filtering: Generic kind 30078 is an opaque bucket. A relay cannot index what is inside it beyond the raw
dtag. When our dashboards or analytical indexers wanted daily step counts, they had to query kind 30078 broadly and download unrelated records from other apps, filtering out unwanted payloads client-side. This wasted cellular bandwidth and slowed dashboard initialization. - The Parameterized Replaceable Trap: Parameterized replaceable events (kinds 30000 to 39999) exist to maintain mutable, addressable state where the newest event with a given
dtag replaces earlier versions. When tracking telemetry, shoehorning dates intodtags to simulate an immutable ledger is an anti-pattern. If an event timestamp ordtag format differs even slightly across versions, relays either wipe out the wrong day or fail to deduplicate properly. - No Schema or Ratchet Enforcement: Relays had no way to know whether an incoming kind 30078 event was a step count, battery level, or random text string. They could not enforce validation rules. A user could post garbage or accidentally lower their daily step tally, and a standard relay could not tell the difference.
- Namespace Collisions: Multiple third-party Nostr clients use kind 30078 for bookmarks, drafts, and preferences. Co-mingling high-frequency device telemetry with application settings on shared relays caused unnecessary noise.
SNIP-10 v3.0.0 solves this cleanly. By allocating canonical regular kinds for immutable records and dedicated replaceable kinds for live device states, queries become precise, indexers stay fast, and relays can enforce strict per-kind validation.
Canonical Kinds Across All Six Applications
Under SNIP-10 v3.0.0, every Wellbeing app maps to dedicated canonical event kinds:
1. Holy Fit: Kind 1359 (Regular)
Holy Fit records daily step counts following the NIP-101h.9 specification.
- Kind:
1359(Regular event) - Required Tags:
["unit", "steps"]["t", "health"]["t", "step_count"]["period", "daily"]["timestamp", "YYYY-MM-DD"]["source", "Holy Fit"]
- Content: Unencrypted integer step count (e.g.,
"9420") or NIP-44 encrypted payload. - Replaced: Kind 30078 with
d="holyfit:YYYY-MM-DD".
2. Nunlock: Kind 1342 (Regular)
Nunlock tracks screen unlock frequency to measure focus and screen time interruptions.
- Kind:
1342(Regular event) - Required Tags:
["timestamp", "YYYY-MM-DD"]
- Content: String integer of total device unlocks since midnight (e.g.,
"42"). - Replaced: Kind 30342 and Kind 30078.
3. Sister Charge: Kind 10343 (Replaceable) & Kind 1343 (Regular)
Sister Charge monitors hardware power states, thermals, and battery longevity. We split this into live status and long-term logs:
- Live Battery State (Kind 10343): Dedicated replaceable event broadcasting current hardware state.
- Tags:
["level", "92"],["voltage", "4.21"],["temp_c", "29.4"],["charging", "false"]. - Content: JSON object, for example
{"level": 92, "temp_c": 29.4, "voltage_v": 4.21, "is_charging": false}.
- Tags:
- Battery Telemetry Log (Kind 1343): Regular, immutable log event generated every 15 minutes to track discharge curves over weeks and months.
- Tags:
["timestamp", "YYYY-MM-DD"],["level", "..."],["voltage", "..."],["temp_c", "..."].
- Tags:
- Replaced: Kind 30343 and Kind 30078.
4. Cell-ibacy: Kind 1357 (Regular)
Cell-ibacy monitors network telemetry, recording mobile cellular data and Wi-Fi consumption separately.
- Kind:
1357(Regular event) - Required Tags:
["timestamp", "YYYY-MM-DD"]["alt", "Daily Network Usage Telemetry"]
- Content: JSON payload containing byte metrics:
{ "mobile_bytes_rx": 412850000, "mobile_bytes_tx": 35210000, "wifi_bytes_rx": 3120400000, "wifi_bytes_tx": 240500000 } - Replaced: Kind 34557 and Kind 30078.
5. Saint Stream: Kind 36787, Kind 1073, & Kind 20344
Saint Stream scrobbles music playback, synchronizes live listening progress, and supports open music protocols:
- Now Playing Status (Kind 36787): Status event with
d="music"and NIP-40 auto-expiration matching the remaining track duration. Contains track metadata (title,artist,duration,position). - Trackstr Scrobble History (Kind 1073): Regular, permanent scrobble event adhering to the Trackstr open music specification. Tags include
title,artist,album, andduration. - Live Playhead Heartbeat (Kind 20344): Ephemeral 15-second heartbeat broadcasting active playhead offset, allowing web dashboards and desktop players to reflect live progress without database writes.
- Replaced: Kind 30344 and Kind 30078.
6. The Habit: Kind 1345 (Regular)
The Habit monitors application usage duration and screen time. Because individual app package names leak sensitive user habits, The Habit enforces NIP-44 encryption by default.
- Kind:
1345(Regular event) - Required Tags:
["timestamp", "YYYY-MM-DD"]["alt", "Daily App Usage Summary"]
- Content: Strictly NIP-44 encrypted JSON string of package durations (e.g.,
{"com.brave.browser": 3600, "org.thoughtcrime.securesms": 1200}). Plaintext app usage payloads are rejected. - Replaced: Kind 30345 and Kind 30078.
7. Wellbeing Relay Discovery: Kind 10323 (Replaceable)
Instead of hardcoding relay URLs in every application configuration, users publish an outbox relay list event for discovery.
- Kind:
10323(Replaceable event) - Tags: Multiple
["relay", "wss://...", "<app_target>"]entries mapping specific apps to their dedicated micro-relays.
End-of-Life (EOL) Roadmap: January 1, 2027
We recognize that users have existing telemetry published under legacy kinds. To prevent broken dashboards and sudden data loss, release 3.0.0 implements dual-query backward compatibility:
- Current Dual-Query Behavior (Nov 2026 - Dec 2026):
All Android apps and web dashboards query both the new canonical kinds (1359,1342,10343,1343,1357,1345,1073) and their legacy counterparts (30078,30342,30343,30344,34557,30345). The clients deduplicate records in memory, favoring canonical events when duplicates exist for a given date. - Formal EOL Date: January 1, 2027 (2027-01-01):
On January 1, 2027, dual-query fallbacks will be removed from all Wellbeing clients. The Go micro-relays will drop legacy kind numbers from their allowlists, rejecting future writes and filter subscriptions for kind 30078 and legacy 30k events. Users are encouraged to run the resigning migration script before that date.
Hardening the Go Micro-Relays
Each app in the suite operates with a dedicated Go micro-relay powered by Khatru and SQLite (holyfit-relay, sistercharge-relay, nunlock-relay, cellibacy-relay, saintstream-relay, thehabit-relay). In 3.0.0, we hardened these relays with several core features:
1. NIP-62 (Request to Vanish)
Sovereign health data requires complete deletion guarantees. We implemented NIP-62 handling directly inside the relay firewall. When a user publishes a Kind 62 event:
- The relay verifies that the event contains a
relaytag matching eitherall_relaysor the specific relay domain (e.g.holyfit). - It executes an atomic database transaction purging all events published by that
pubkeyup to the event’screated_attimestamp. - It wipes auxiliary tables, such as the
max_scoresstep ratchet table.
2. Scoped Kind 5 Deletion Firewalls
Standard Nostr relays often process Kind 5 deletion requests without validating whether the referenced events actually belong to the relay’s scope. We introduced isManagedKind5 verification:
- A Kind 5 event is only accepted if it explicitly references an event ID that exists in this relay’s SQLite database with a matching author pubkey, or references an
aorktag belonging to the kinds managed by that specific relay. - Blanket or unrelated Kind 5 requests are rejected outright, protecting the database from unnecessary deletion tombstones.
3. Schema Collision Protection & Step Ratchets
Each relay now enforces strict tag requirements and content validation inside RejectEvent:
- In
holyfit-relay, Kind 1359 must haveunit=steps,t=health,t=step_count,period=daily, and a validtimestamp=YYYY-MM-DD. Content must parse as an integer between 1 and 1,000,000, or match a valid NIP-44 Base64 payload. - We added a permanent
max_scoresSQLite table that acts as a step ratchet. Step counts for a given date cannot be lowered. If a client attempts to push a count lower than an existing verified record, the relay rejects the event with an informative error string.
4. Historical Event Ingestion
To allow users to migrate historical data, the relays accept past timestamps. Query limits were raised to 100,000 (QueryLimit: 100000 with default filter query limits of 50,000), ensuring that long-term historical charts load without truncated pagination.
Migrating Historical Telemetry: resign_historical_telemetry.py
To bridge the gap between legacy events and SNIP-10 v3.0.0, we wrote a standalone Python utility distributed directly via Blossom:
- Blossom URL:
https://blossom.vanderwarker.family/f56184fd9607f1c8e2acd5b287c06f77727ef7666c9423b06e502161c94a49f8 - Mirror:
https://nostr.download/f56184fd9607f1c8e2acd5b287c06f77727ef7666c9423b06e502161c94a49f8 - SHA-256 Checksum:
f56184fd9607f1c8e2acd5b287c06f77727ef7666c9423b06e502161c94a49f8
You can download it with curl or nak blossom download:
curl -sSL https://blossom.vanderwarker.family/f56184fd9607f1c8e2acd5b287c06f77727ef7666c9423b06e502161c94a49f8 -o resign_historical_telemetry.py
chmod +x resign_historical_telemetry.py
Because Nostr events are cryptographically signed over their kind, content, tags, and timestamp, you cannot simply edit the kind number in a database without invalidating the Schnorr signature. The events must be converted, resigned using the owner’s private key, and republished.
The script performs this migration cleanly:
- Reads Legacy JSONL: Scans an exported line-delimited JSON file of historical events.
- Normalizes Date Tags: Extracts the original date from the
timestamptag, the legacydtag (stripping prefixes likeholyfit:orcell-ibacy:), or thecreated_attimestamp. - Applies Canonical Schemas: Maps each legacy event kind into its canonical counterpart:
- Kind 30078 (steps) maps to Kind 1359 with full NIP-101h.9 tags.
- Kind 30342 / 30078 (unlocks) maps to Kind 1342.
- Kind 30343 / 30078 (battery) maps to Kind 1343 regular log events.
- Kind 34557 / 30078 (network) maps to Kind 1357.
- Kind 30345 / 30078 (app usage) maps to Kind 1345.
- Kind 30344 / 30078 (music) maps to Kind 1073 Trackstr scrobbles.
- Preserves Original Created-At: Retains the exact Unix timestamp of the original event so historical records do not clump together on the migration date.
- Signs via
nak event: Uses thenakCLI tool to compute valid Nostr signatures using the user’s secret key (--sec). - Dry-Run and Direct Publishing: Supports
--dry-runto preview tag mappings,--outputto save signed events to a new.jsonlfile, and--publish-relayto broadcast migrated events directly to the target micro-relays.
Example usage:
# Dry run to verify mappings
python3 scripts/resign_historical_telemetry.py \
--input legacy_telemetry.jsonl \
--dry-run -v
# Resign and publish directly to the Holy Fit micro-relay
python3 scripts/resign_historical_telemetry.py \
--input legacy_holyfit.jsonl \
--sec "$NOSTR_SECRET_KEY" \
--output canonical_holyfit.jsonl \
--publish-relay wss://holyfit.scuba323.com/relay/
Ecosystem Metadata Alignment
A protocol upgrade is only complete when the distribution channels agree on versioning, permissions, and release notes. In 3.0.0, we synchronized all metadata across the ecosystem:
- Build Systems: All six Android apps were bumped to
versionName "3.0.0"andversionCode 26in their respectivebuild.gradlefiles. Build targets were verified against Android SDK 35 with v1 and v2 release signing configurations. - F-Droid Metadata: Updated
metadata/com.scuba323.*.ymlacross all app repositories. Added explicit descriptions of canonical SNIP-10 kinds, Amber (NIP-55) external signer integration, Health Connect permissions, and the 2027-01-01 EOL notice. - Fastlane & Zapstore: Updated store listings, permissions summaries, and release notes for decentralized Nostr app distribution via Zapstore.
- Gitea Releases: Relays were tagged at
v3.0.0on our sovereign Gitea instance (https://git.vanderwarker.family/wellbeing), with pre-compiled 64-bit Linux binaries attached to each release. Relays can also be built directly viago install:GOPRIVATE=git.vanderwarker.family/* go install git.vanderwarker.family/wellbeing/holyfit-relay@v3.0.0
What Comes Next
With the protocol stabilized and canonical kinds in production, our immediate focus turns to polish:
- Expanding NIP-58 badges and activity achievements in Holy Fit and Nunlock.
- Adding deeper thermal throttling correlation charts in Sister Charge.
- Improving offline caching and zero-latency relay synchronization via Citrine.
The 3.0.0 release is available now across all repos, the F-Droid repository (https://apk.scuba323.com), and our web gateways. Test it out, run the migration script if you have legacy data, and let us know your feedback on Nostr.
Write a comment