LibreNostr
com.librenostr.android
LWB lwb89@cosanostr.com Sats Received
Underlying data available via MCP: app_zaps, app_releases.
Zap Count
Underlying data available via MCP: app_zaps, app_releases.
Releases
- Sep 28, 2026 0.7.0### Changed - The note feed, notifications and DM conversations now show content noticeably faster: opening a reply's parent note, refreshing the feed, and loading notifications no longer wait on profile pictures/names or on interaction counts before showing anything — the note or notification itself appears first, names and counters fill in moments later. - Opening a DM conversation no longer re-decrypts the whole inbox every time; it also runs off the main thread now, instead of occasionally freezing the app while it worked. - Relay queries no longer wait far longer than intended when a relay is slow or unreachable: a single stuck query could previously hold up the screen for well over ten seconds; it's now capped
More…
consistently across the app. ### Fixed - Some notes crashed the feed outright when their content matched more than one highlighted piece at the same spot (a hashtag inside a link, for instance). --- APK is signed and `arm64-v8a` only. Verify the signature before installing: \`\`\`bash apksigner verify --print-certs librenostr-0.7.0-arm64-v8a.apk \`\`\` - Sep 28, 2026 0.6.2### Added - A local web of trust filter for the following feed (Settings > Web of Trust): hides notes and reposts from accounts you don't follow and that aren't followed by enough of the people you do follow. Entirely on-device — it reads only public follow lists already published to relays, no server involved. - Relay addresses can now be plain `ws://` when they point at your own network: `localhost`, `127.0.0.1`, `::1`, or a `.local` name, for a self-hosted relay with no certificate. - `#bitcoin` renders as ₿ in Bitcoin's own orange; `#nostr`, `#grownostr` and `#asknostr` get a purple circle.
More…
### Changed - The relays LibreNostr adds on top of your own, to reach people you follow who don't publish to any of your configured relays, are now chosen by how many additional people they actually reach, not by how often a relay shows up overall — the same fixed number of relays now covers more of your follow list. ### Fixed - Removed an unused CameraX manifest placeholder service that had no function but showed up as an unexplained entry to anyone inspecting the app's manifest. - Sep 25, 2026 0.6.1### Changed - Redesigned onboarding: a new welcome screen, a relay-selection step that asks for at least three relays and shows your NIP-65 list when available, a privacy step that describes the built-in Tor engine and Orbot, and a step indicator across the flow. The gestures screen is gone. - Redesigned bottom navigation: every destination now has a label, the selected one is highlighted with an animated pill, the compose button is labelled "Post", and Reads and Explore keep Home highlighted. - Home now has Algorithms, Long reads and Bookmarks buttons under the top bar. They replace the swipe from the edges of Home and the long-reads overlay; the algorithm drawer opens from its button. - Note actions animate when tapped. A like also gives a haptic tick and a short, quiet chime (skipped
More…
when the system's touch sounds are off). - The zap sheets were restyled and give haptic feedback when you pick an amount and when you confirm. ### Removed - The edge-swipe gestures on Home (right for algorithms, left for long reads); use the new buttons. - Sep 24, 2026 0.6.0## [0.6.0] - 2026-09-24 ### Added - Built-in Tor powered by Arti, bundled for `arm64-v8a`, so Tor can run inside LibreNostr without installing another app. - Tor settings now show the built-in engine state and bootstrap progress, alongside the existing Orbot engine. ### Changed
More…
- Network routing now offers Direct, Tor for everything, and Only `.onion` addresses modes. - Relay WebSockets, HTTP requests, media, uploads, and web pages follow the selected network mode; switching modes reconnects relay sockets through the new route. - `.onion` relay addresses are accepted as cleartext WebSockets only when they are routed through Tor. ### Fixed - Traffic that cannot be routed through the selected Tor mode is no longer silently fetched directly. - Strict Tor mode fails closed when Tor is unavailable instead of falling back to a direct connection. - Sep 15, 2026 0.5.17### Changed - Feed queries now also reach the relays that the people you follow actually publish to (NIP-65 write relays), not only the relays configured in Settings — less time spent waiting on a relay that never had a given author's notes in the first place. - Like/reply/repost/zap counts for notes further down the feed are now fetched only once a note actually scrolls into view, instead of eagerly for the entire page. Combined with the relay routing above, pull-to-refresh and scrolling through the feed and notifications are both noticeably faster.
More…
### Fixed - A single relay hiccup while scrolling deep into the feed could permanently stop further notes from loading for the rest of that session. The feed now retries further back automatically before giving up, with a "Load more" button once it does — this is a partial fix, reaching the very end of the feed can still get stuck in some cases and needs further work. - Sep 15, 2026 0.5.16### Fixed - Pulling to refresh the feed or notifications could take much longer than it should: a single refresh fires off dozens of overlapping relay queries, and a couple of the public relays this app talks to (nostr.mom, offchain.pub) reject a connection's request outright once too many of its subscriptions are still open at the same time. Every relay's subscription used to stay "open" from that relay's point of view until the *entire* page's fetch had settled across every relay, even for the relay that had already answered in milliseconds — so a handful of slow relays kept otherwise-fast ones tied up long enough to trip that limit repeatedly on every
More…
refresh. Subscriptions now close the moment each relay actually answers, a rejected request now fails immediately instead of sitting through the full request timeout waiting for a reply that was never coming, and no more than 4 relay queries run at once app-wide. Confirmed via captured device logs and an isolated reproduction against the affected relays: rejections dropped to zero under identical traffic. A page still needs on the order of a hundred relay round trips in this fork's fully relay-only design, so refresh isn't instant, but it no longer wastes time on rejections it caused itself. - Sep 14, 2026 0.5.15### Removed - The in-app Primal wallet is gone: no more custodial balance, deposits/withdrawals, the self-custodial Spark wallet option, promo-code redemption, or the ability to let another app spend from either wallet over Nostr Wallet Connect (NWC). Safely operating a real wallet isn't something this fork can commit to, so it's better removed cleanly than left half-working. **Zapping is unaffected** — it still builds a standard NIP-57 zap request and hands the invoice to whichever Lightning wallet app is installed on your phone, exactly as before.
More…
### Fixed - The notifications tab did a full refresh from relays every time it was opened, even seconds after the previous visit with nothing new to show. It now only does a full refresh when little or nothing is cached locally yet. - The GIF picker in the note composer opened blank until you typed a search. Trending GIFs now load automatically as soon as it opens. - Every direct-message send or fetch left a background task running for the rest of the app session, never cleaned up — a slow memory leak on accounts that use DMs a lot. - An internal cache used to avoid re-checking Nostr address (NIP-05) verification kept growing for as long as the app ran, with nothing ever removed from it. It's now capped to a sane size. - Live stream chat kept the *entire* message history for a broadcast in memory and reprocessed all of it on every new message, so long or popular streams could accumulate this without bound. Chat now keeps a rolling window of the most recent messages instead. - Reconnecting to a remote signer app (e.g. Amber) more than once in the same app session could produce duplicate "new signer request" notifications; the underlying subscriptions now only ever start once per app session instead of stacking on every reconnect. ### Changed - Reply threads could visibly stutter while scrolling long conversations: any single change anywhere in the thread (a like, a zap, anything) was rebuilding *every* visible reply card from scratch instead of only the one that actually changed. Scrolling should now feel noticeably smoother, especially in longer threads. - Saving a page of fetched notes to the local cache ran one extra, unfiltered database query per note before saving it — a full feed page could mean dozens of redundant queries fired back to back. A page now saves with a single query regardless of how many notes it contains. - Raised the local image/media cache limits (feed avatars, attachments, video thumbnails), so scrolling back up through a session causes fewer unnecessary re-downloads than before. - Sep 12, 2026 0.5.14### Fixed - Opening "who liked this" briefly showed "no likes yet" before the real list appeared. Likes and reposts were fetched at the same time but shared one loading flag; reposts (usually the shorter list) finishing first flipped it off for both tabs while the likes fetch was still in flight, making the still-empty list render as a genuine empty state until the real fetch caught up. Likes and reposts now each track their own loading state. - The retry button on a "mentioned event not found" card looked like it did nothing: it did fetch and store the missing note, but the citing note's own feed row never got told to redraw (its
More…
live query deliberately does not watch that table, to avoid invalidating every open feed on every unrelated note fetch elsewhere in the app). The retry now updates the card directly once its target resolves, the same approach already used by the note editor's own retry. - Sep 12, 2026 0.5.13### Changed - Loading a page of the following feed used to make three relay round trips one after another: the notes themselves, then any quoted notes, then everyone's profile metadata. Quoted notes and profile metadata for the page's own authors now fetch at the same time instead of waiting on each other, and both skip anything already known from an earlier page in the same session (already-fetched profiles, already-stored quoted notes) instead of asking the relays again — the same request-avoiding pattern the notifications tab already used. Feed pages should now paint noticeably sooner, especially a following list with active posters who recur across pages.
More…
- Sep 12, 2026 0.5.12### Security - Direct messages and private-thread replies could end up stored unencrypted on debug builds installed on real devices. The caching database shared its encryption on/off switch with the wallet and account databases, and those two turn it off on debug builds purely for easier local inspection; because the switch was a single flag shared by all three databases instead of being scoped per database, that debug convenience silently carried over to DM/private-reply content too. The caching database now uses its own always-on encryption path that nothing else can disable, structurally, regardless of what any other database's debug build does.
More…
- The key that encrypts the local nsec/account store now requests hardware-backed StrongBox storage on devices that support it, matching the protection already used for the database encryption key. Falls back automatically on devices/algorithm combinations that advertise StrongBox but can't actually back it, as recommended by Android's own key-generation guidance. ### Fixed - Pull-to-refresh on the feed occasionally reloaded only your own notes instead of your full following list, when the follow list hadn't finished loading yet from relays at the moment of refresh. - Pull-to-refresh on notifications occasionally reloaded 15-day-old notifications instead of today's; tapping "mark all as read" then showed today's notifications again, but not fully updated. - Mentioning a user, quoting a note, or attaching an image initially rendered as a raw `@npub1...`/`nevent1...` reference instead of the chosen display name or a proper embed, until the note was reloaded. Newly-published notes now resolve and render these immediately. - A "failed to load more" banner on feeds and article lists existed in the code but was gated behind a developer flag that is permanently off in every real build, so pagination failures were silently invisible to every user. The banner (with its retry-relevant error message) now always shows when a page genuinely fails to load. ### Removed - The crash reporter was a non-functional stub: it built a full crash report on every uncaught exception but only ever logged "upload is disabled" and discarded it. Removed rather than left as dead code that looked functional but wasn't. - Sep 11, 2026 0.5.11### Fixed - The welcome screen no longer crashes on Android 8 and later while loading the app logo. It previously passed the API-specific adaptive launcher icon to Compose's `painterResource`, which only accepts raster images and VectorDrawables; the screen now uses the dedicated raster logo. - The launcher icon is restored to the original LibreNostr squircle used through 0.5.6. The adaptive-icon experiment is removed because launchers supplied a black circular backing behind its transparent background, producing a black circle with a smaller squircle inside it.
- Sep 11, 2026 0.5.10### Fixed - The adaptive launcher icon now keeps LibreNostr's own squircle artwork on launchers that apply their own icon masks. Its artwork is carried by the foreground layer with a transparent background, preventing the launcher mask from turning the icon into a circle while retaining the correct full-size rendering.
- Sep 11, 2026 0.5.9### Changed - The launcher icon's foreground layer now fills almost the entire adaptive-icon canvas instead of being shrunk into the conservative safe zone, so on a squircle-masked launcher (the common case on Pixel-family and Material You launchers) it renders as a proper edge-to-edge squircle — the icon's own artwork, not a smaller icon floating inside a larger padded background. Checked under a squircle, a circle and a rounded-square mask; the bird stays fully intact under all three.
- Sep 11, 2026 0.5.8### Fixed - The adaptive launcher icon shipped in 0.5.7 replaced the crisp, original bird artwork with a pixel-extracted reconstruction (no vector source was available) that showed a visible grayish edge along the wing layers and a jagged notch on the smallest wing tip at real launcher size — a regression on every device, not just the ones the previous fix targeted. The foreground layer is now the original flat icon itself, cropped with a genuinely clean, zero-antialiasing cut (verified pixel by pixel) and scaled into the adaptive-icon safe zone, so it is pixel-identical to the original artwork rather than a reconstruction of it.
More…
- The adaptive icon's background layer is now a vector drawable with explicit 108dp bounds instead of a plain gradient shape, which has no intrinsic size of its own; some launchers' icon caching and extraction paths size their render target from that value before drawing and could come out blank if it reports none. - The Android 13+ themed-icon (monochrome) layer is now built from the app's existing status-bar silhouette asset instead of the same pixel extraction, removing the same edge artifacts there. - Sep 11, 2026 0.5.7### Fixed - The launcher icon no longer gets shrunk onto a white background on launchers that enforce Material You-style adaptive icons (GrapheneOS's default launcher among them). The app shipped only legacy flat icon PNGs with no adaptive-icon declaration, so such a launcher synthesized its own padded, white-backed version rather than rendering the icon full-bleed. A proper adaptive icon is now declared: the bird glyph as its own layer on the icon's own purple gradient background, sized to the standard safe zone and verified against both circle and rounded-square masks, plus a monochrome layer for Android 13+ themed icons. `android:roundIcon` also pointed at
More…
the square icon instead of the round one; fixed alongside it. - A note that quotes another note no longer gets stuck showing "Mentioned event not found" forever once its target is actually available. The "not found" classification was a one-time snapshot taken when the quoting note was first saved, never re-checked afterward — so the retry button really did fetch the missing note, but nothing ever told the quoting note about it. Any note persisted anywhere in the app now heals every other stored citation of it, not only the ones in that same fetch, and does so without disturbing the citing note's other embeds. - The Italian "Report Content" action in note, article and live stream menus read as "Contenuto della relazione" (a mistranslation of "report" as a noun) instead of the intended action; corrected to "Segnala contenuto", matching "Segnala utente" right next to it. - Sep 10, 2026 0.5.6### Fixed - The recipient of a NIP-17 direct message or private reply now actually receives it. Relay resolution was asymmetric between the two sides of a send: a sender resolving a remote recipient with no kind-10050 fell back to the public bootstrap pool, while that recipient polling their own inbox stopped at their own configured relays and never checked the bootstrap pool at all — the two sides agreed on nothing, so the wrap was delivered exactly where nobody was listening. Inbox polling now reads the union of every relay a sender could plausibly have used, and an account's own kind-10050 is announced on first poll rather than only after a send.
More…
- The Messages badge unread count is no longer hardcoded to zero. It is now derived from what actually arrived past the last known message, and opening a conversation clears it locally. - A private reply notification now shows the lock indicator and opens the thread it answers when tapped, instead of missing both because the notification screen built its note preview by hand and dropped the fields that carry them. - Private-reply sender profiles are now cached the same way direct-message senders already were, so a private-reply notification shows the sender's name instead of a raw npub. - Sep 10, 2026 0.5.5### Fixed - Private replies sent over NIP-17 now appear in their own thread instead of being sorted above the conversation root: the thread's topological sort reads the gift-wrapped reply's normalized root/parent relationship directly, not only public NIP-10 tags, which a private reply never carries. - The recipient of a private reply now gets a local notification for it — nothing else can, since the reply exists only inside an encrypted Gift Wrap and no relay ever serves one. Tapping the notification opens the thread the reply belongs to.
More…
- The sent-reply lock indicator on a private reply's note card is now an icon and label together, matching Amethyst/Damus, instead of label text alone. - NIP-17 relay resolution for both direct messages and private replies now follows the recipient's kind-10050 inbox, then their NIP-65 read relays, then a bootstrap pool, mirroring Amethyst's own fallback policy. Previously a missing kind-10050 could make an otherwise deliverable message fail outright. - A legacy NIP-04 direct message (the fallback used when a contact has no kind-10050) is now also published to the recipient's own relays, not only the sender's write relays, so accounts with disjoint relay sets can actually reach each other. - A private reply naming only a thread root (a NIP-10-legal shape, and the one Amethyst produces most often) is no longer silently dropped; a duplicate or malformed marker no longer discards an otherwise valid reply either. - Announcing an account's own NIP-17 DM relay list no longer runs before every send and can no longer make an otherwise deliverable message fail; it is now a best-effort step after delivery. - Sep 9, 2026 0.5.4### Fixed - Private replies are now invoked directly from a thread's reply toolbar via a lock icon, instead of being hidden in a note overflow menu. The recipient picker accepts either a searched username or an `npub`; only that selected account can decrypt the resulting NIP-17 reply. - Normal thread replies remain public by default. Private delivery is enabled only after the lock action and recipient selection, and can be switched back off before publishing. - NIP-17 conversations now continue to refresh and send through the compatible legacy path when a contact has not yet published a kind-10050 DM relay list, rather than failing the whole inbox.
More…
- Sep 9, 2026 0.5.3### Added - Modern private messages now use the NIP-17 pipeline: NIP-44 encryption, NIP-59 seals and Gift Wraps, recipient kind-10050 DM relay discovery, a sender copy, and a central inbox subscription. Newly sent messages no longer create legacy NIP-04 events. - Public threads support private replies to either a public note or an already-private reply. The encrypted root and parent markers are normalized into the existing thread tree only after decryption, persisted in encrypted local storage, and shown to authorized users with a small private badge. Gift Wraps reveal neither the thread relationship nor the plaintext to relays.
More…
### Fixed - Scrolling the Home feed now moves the complete LibreNostr header off-screen and gives its full height back to the timeline; scrolling in the opposite direction restores it. - The center compose (`+`) action remains attached to the bottom navigation while the Home header is collapsed. - Zap notifications now display the amount for every supported zap-notification grouping. - Video attachments can decode and display an actual preview frame when no explicit thumbnail is supplied, instead of leaving a flat grey placeholder. - Setting descriptions use readable foreground colours across the Dark Pixel, Dark Green Pixel, Dark Fire, Light Pixel, Green Pixel, and Fire Light themes. - The expanded Tor settings section no longer leaves an oversized black area below its content. - Sep 8, 2026 0.5.2### Fixed - A thread with an unusually long chain of nested replies could crash the app outright — the code that lays out the reply tree walked one level at a time recursively, and a deep enough chain overflowed the call stack. Rewritten to walk iteratively instead, with no protocol-level depth limit. - Deeply nested replies no longer push the note itself further and further off the edge of the screen — indentation now caps out after a handful of levels while the actual nesting is still tracked correctly underneath.
More…
- A reply whose parent note this app doesn't have used to render at the same visual weight as a confirmed direct reply to what you opened, with nothing distinguishing the two. It now draws with a fainter connector instead, so it's still there — never hidden — but doesn't read as more certain than it actually is. - Reply ordering could be unstable when two replies shared the exact same timestamp (common when several relays hand back events for the same second); ties now resolve the same way every time. - Sep 7, 2026 0.5.0### Added - **Tor support via Orbot**: a new "Tor" entry in Settings routes relay connections, zap/lightning requests, media uploads, image loading, media downloads, video/audio playback, and embedded link previews through Orbot's SOCKS proxy instead of connecting directly. Off by default; the SOCKS port is configurable (defaults to Orbot's own default, 9050). If Orbot isn't detected as installed, the settings screen says so plainly. There is no fallback to a direct connection if the proxy isn't reachable
More…
— connections fail instead of silently leaking outside Tor. The setting takes effect on the next full restart, not immediately, since every network client in the app is a long-lived singleton built once at startup; the app is explicit about this rather than pretending otherwise. A new onboarding step (shown once, for both new and existing accounts) explains the feature and links to Orbot on Zapstore. ### Fixed - Tapping the zap button could crash the app outright. The zap sheet's amount-preset grid was a `LazyVerticalGrid` sitting inside a `Column` that scrolls to make room for the keyboard — a lazy grid inside a scrollable container with no bounded height is disallowed and threw immediately. Replaced with a plain, non-lazy grid; the preset count is small and fixed, so there was never anything to virtualize. - Sep 7, 2026 0.4.0### Added - A redesigned home header — LibreNostr wordmark and tagline, an integrated search bar, a swipeable avatar — and a floating, pill-shaped navigation dock, replacing the previous Primal-styled top bar and bottom navigation. The biggest visual departure from Primal yet. - Two more themes, Green Pixel and Dark Green Pixel, joining the existing six; the theme picker is now a 4×2 grid instead of 3×3 with a gap. - A second button next to the publish countdown's "Don't send" — "I've read
More…
it, send now" — for skipping the rest of the wait once you've actually reviewed the note, translated into every supported language. - Zap notifications now show the sat amount as its own bold, colored badge instead of leaving it buried inside the sentence text. ### Changed - The navigation dock no longer has a separate account button — tapping the avatar already in the home header does the same thing, so this was a redundant second way to reach it. The dock's five remaining buttons (Feeds, Messages, compose, Notifications, Settings) are now evenly spaced with compose in the middle, instead of six unevenly packed ones. - The home header no longer shows a hamburger icon or a feed-name chip under the search bar for opening the algorithm picker. Onboarding already explains that a swipe does this, so both buttons duplicated a gesture that was already the primary way in. ### Fixed - A handful of small regressions from the redesign above: an off-center theme swatch icon, a hardcoded English "Profile" label where every other string is translated, and a navigation-bar height constant that no longer matched the dock's real height, which could misalign layout sitting below it (e.g. the wallet dashboard footer). - A broad Italian mistranslation pass: "account" no longer shows as "conti" (bank accounts) anywhere, and dozens of other terms across feeds, mute/ follow, wallet, sats, Lightning, reporting, and search are now consistent with what is, at its core, a social app. - The same class of corruption that caused the Italian bugs above turned out to affect nearly every other language: `nsec`/`npub` replaced with unrelated words, login and logout both reading as "Sign", "backed up" mistranslated as "supported" in the wallet's fund-loss warning, and "share" mistranslated as a stock/equity term instead of the social action. Fixed across Bulgarian, Czech, Danish, German, Greek, Spanish, Estonian, French, Croatian, Hungarian, Lithuanian, Latvian, Maltese, Dutch, Polish, Romanian, Russian, Slovak, Slovenian, Swedish, and Chinese — around 140 strings in total. - Japanese was corrupted far beyond a few bad strings: dozens of unrelated buttons and labels throughout the app had all been collapsed onto the same handful of wrong phrases (every "Retry", "Close", and "Done" button in the app, among others, showed the same unrelated word). Fully retranslated — over 130 strings corrected. ### Removed - Irish (`ga`) is no longer a supported UI language. Its translation was corrupted beyond a reasonable patch — the app's own name, `nsec`/`npub`, and dozens of unrelated buttons were all random, unrelated phrases. It will come back once someone can redo it properly. - Sep 6, 2026 0.3.3### Added - **Four new themes**: Dark Pixel, Light Pixel, Fire, and Fire Light join Midnight and Ice — six in total, shown in a grid with each theme's own name and color swatch instead of a plain "Dark"/"Light" pair. The two Pixel themes also use a different typeface (Fira Mono) and sharper corners, the first themes here to vary anything beyond color. ### Fixed - The feed could show only your own notes after a cold start, sometimes needing the app force-closed and reopened to recover. A relay query racing ahead of the app's own relay connections on startup returned an empty follow list, and that empty result got cached for 5 minutes — turning a one-off timing issue into a long-lived one. A fresh feed load now retries instead of trusting a remembered "you follow nobody" answer. - Scrolling a feed to load more notes could still make it visibly jump — the 0.3.0 fix for this addressed one of two places that were forcing a reload on every page, not both. - The zap comment field could end up hidden behind the on-screen keyboard, with no way to see what you were typing. The zap sheet's amount-preset grid is also a bit more compact now. - Switching between Home, Messages, Notifications, and Settings used inconsistent, sometimes directionless animations — tabs now consistently slide toward whichever side they actually sit on. - Several Italian strings translated in 0.3.0 didn't make sense in context ("account" as "conto" — a bank account, "muted" as "morto" — dead, "note" as "biglietto" — a ticket, among others).
More…
Verify the APK signature before installing: ``` apksigner verify --print-certs librenostr-0.3.3-arm64-v8a.apk ``` - Sep 6, 2026 0.3.2Note translation is now fully on-device — no server, no configuration, nothing ever leaves your phone. ### Changed - **Note translation no longer uses a remote LibreTranslate server.** The "Translate" action introduced in 0.3.0 now runs entirely on-device via Bergamot Translator (Mozilla's own production NMT engine — the same one built into Firefox) with real neural translation models, covering every EU official language plus Chinese, Japanese, and Maltese in both directions (Irish has no published model anywhere, so it isn't supported). Models are small (mostly 14-18MB per language pair) and download on demand, with an explicit confirmation showing the real size and an on-device/offline disclosure before anything is fetched — never bundled into the app itself. "Translate notes" is on by default now that there's no server address or API key to configure; the now-pointless server URL and API key fields have been removed from Settings > Content Display. - Raised the minimum supported Android version from 9.0 to Pie (API 28, Android 9) — the on-device translation engine's `iconv` usage requires it. - Release APKs are now built for `arm64-v8a` only (previously also `armeabi-v7a` and `x86_64`). A real 32-bit-only phone isn't a realistic target any more, and native x86_64 Android phones are effectively nonexistent today — the rare x86 devices (Chromebooks) already run arm64 apps through their own translation layer. ### Fixed - Translating several notes in a scrolling session could grow the app's memory use without bound until it ran out of memory and crashed — language detection was loading its full offline model independently for every note instead of once, shared. - Scrolling a note out of view while it was translating (or downloading a language pack) silently abandoned the operation — the spinner just kept spinning forever, with no error and no result even if you scrolled back. Translation now runs independently of what's on screen, so it keeps going, and finishes, regardless.
More…
- Translation could take upwards of 15-20 seconds per note due to two compounding issues: the debug build of the native engine ran unoptimized, and the one-time language-detection setup was doing several times more work than it needed to. Both are fixed — a typical translation now takes about two seconds. Verify the APK signature before installing: ``` apksigner verify --print-certs librenostr-0.3.2-arm64-v8a.apk ``` - Sep 5, 2026 0.3.1## [0.3.1] - 2026-09-05 A privacy/security pass across the codebase, prompted by an audit looking specifically for data leaks and unnecessary attack surface. ### Fixed - **The media-upload HTTP client could write a signed auth header to disk.** Enabling the in-app diagnostic logging (off by default, Settings) and then uploading a photo or video wrote the request's `Authorization` header — a
More…
signed Nostr event carrying your pubkey — into the exportable app logs. Anyone using "Share Logs" to send diagnostics to support would have sent that along with it, unknowingly. Logging is now fully disabled for that client, matching every other network client in the app; an additional, separate line of code that printed the same headers unconditionally (independent of the logging setting) was removed outright. - **The note-translate server address wasn't required to be HTTPS.** The server URL you configure in Settings > Content Display > Translate notes is now checked before every request; a plain `http://` address is refused rather than relying on Android's network security config to catch it as a side effect. Note text should never leave the device other than encrypted, on purpose, not by accident of a different setting. - Removed an unused, unwired no-op logger class left over from an earlier logging setup — dead code, no behavior change. ## Verifying this release Every APK is signed with the same key across releases (`CN=Lwb89dev, O=LibreNostr`). Verify with: ``` apksigner verify --print-certs librenostr-0.3.1-<abi>.apk sha256sum -c SHA256SUMS.txt ``` Pick the APK matching your device's CPU architecture (arm64-v8a covers virtually all phones from the last several years). - Sep 4, 2026 0.2.8Four small polish fixes from a real-device pass: a slightly clipped splash logo, a jarring tab switch, a missing swipe gesture, and a dead Home button. ## Fixed - **The splash screen logo was clipped in a corner.** The icon's artwork extended past the safe zone the system's splash screen uses when masking and scaling it, clipping a sliver off one edge. Re-centered with proper margin. - **Switching from Messages to Notifications flashed and rebuilt the whole screen.** Messages lives in its own navigation destination rather than the app's in-place tab system, so switching tabs was popping back to a fully torn-down screen and replaying a "returning from a detail screen" scale animation. That transition is now instant, matching every other tab. - **The DM Follows/Other tabs only responded to taps, not swipes.** Rebuilt on a `HorizontalPager` (the same pattern already used elsewhere in the app), so swiping left/right now switches between them, with the tab indicator and underlying data following along either way. - **Tapping Home from the Profile screen did nothing.** The persistent bottom bar mislabeled Feeds as the active tab while viewing a profile, so tapping Home read as "you're already here" and silently no-opped. ## Verifying this release
More…
Every APK is signed with the same key across releases (`CN=Lwb89dev, O=LibreNostr`). Verify with: ``` apksigner verify --print-certs librenostr-0.2.8-<abi>.apk sha256sum -c SHA256SUMS.txt ``` Pick the APK matching your device's CPU architecture (arm64-v8a covers virtually all phones from the last several years). - Sep 3, 2026 0.2.6A quoted note that wasn't already cached for some other reason showed "Mentioned event not found", the new Accounts entry in Settings had nothing inside it, and a bunker connection could leak a socket if you backed out mid-login. ## Fixed - **Quoted notes often rendered as "Mentioned event not found."** A note quoting another note — via a `nostr:note1…`/`nevent1…` reference or a NIP-18 `q` tag — used to only render correctly by coincidence, if the quoted note happened to already be cached from something else. The field that used to carry it was Primal's centralized cache server's job, and was never replaced with a relay fetch after the fork. The thread screen and the main feed now ask relays for a quoted note (and its author's profile) whenever it's missing. - **The new "Accounts" entry in Settings showed nothing when tapped.** Settings rows render their content inline rather than navigating away, and this one had no inline content wired up, so it just expanded to an empty box. It now shows the "Add an existing account" action. - **A bunker (NIP-46) account could be asked to approve leftover event kinds it should never see**, the same "leftover cache/wallet kind" set Amber accounts were already shielded from — the filter only checked for Amber, not for a bunker connection. - **A cancelled bunker connection (backing out mid-login, or cancelling a pending publish) could leak an open socket.** The connection's cleanup ran as a normal step after the work, not in a `finally`, so a cancellation skipped it. ## Verifying this release
More…
Every APK is signed with the same key across releases (`CN=Lwb89dev, O=LibreNostr`). Verify with: ``` apksigner verify --print-certs librenostr-0.2.6-<abi>.apk sha256sum -c SHA256SUMS.txt ``` Pick the APK matching your device's CPU architecture (arm64-v8a covers virtually all phones from the last several years). - Sep 3, 2026 0.2.4Two accounts on the same device already shared their relay connections and local cache; the cleanup and search-feed code paths had not caught up with that. ## Fixed - **Logging out one account discarded shared cache other logged-in accounts were still using.** The coordinator's follow-list cache and hot event layer are one process-wide instance, shared by every account signed in on the device — logging out account A used to wipe both unconditionally, even with account B still logged in and relying on them. It is now reset only when the account being removed was the last one signed in. - **Advanced search's `myfollows` scope asked relays directly instead of going through the fetch coordinator.** This was the case named when the coordinator was introduced — the note feed, article feed and advanced search all want the same follow list, often within the same burst of tab loads — but this call site was never actually wired to it. It now shares the same coalesced, briefly-cached request as everything else. ## Verifying this release Every APK is signed with the same key across releases (`CN=Lwb89dev, O=LibreNostr`). Verify with:
More…
``` apksigner verify --print-certs librenostr-0.2.4-<abi>.apk sha256sum -c SHA256SUMS.txt ``` Pick the APK matching your device's CPU architecture (arm64-v8a covers virtually all phones from the last several years). - Sep 3, 2026 0.2.3Proofreading a note before it went out meant trusting the countdown alone, and tagging someone by name only worked if a relay happened to answer. ## Added - **The publish countdown now shows a preview of the note.** The last few seconds before a note goes out were a bare timer with no way to see what was actually about to be published. The countdown screen now renders the note's text and any attached image or GIF the same way a published note would look, so a mistake is caught by reading it, not by guessing. - **Mention search now checks profiles you already have before asking a relay.** Typing `@` followed by a name only searched relays — a NIP-50 `search` filter if the relay supported it, otherwise a scan of the last 500 arbitrary profile events, meaning a followed or previously-seen profile could still fail to show up. Profiles already cached locally now match instantly by name prefix, offline included; a relay is only asked to fill whatever the local cache didn't already cover. ## Verifying this release Every APK is signed with the same key across releases (`CN=Lwb89dev, O=LibreNostr`). Verify with:
More…
``` apksigner verify --print-certs app-<abi>-altRelease.apk sha256sum -c SHA256SUMS.txt ``` Pick the APK matching your device's CPU architecture (arm64-v8a covers virtually all phones from the last several years). - Sep 2, 2026 0.2.1Two follow-up fixes to the Follows/Requests split shipped in 0.2.0, found by using the app rather than by reading the code. ## Fixed **A reply landing in the same relay page as the stranger's first message was still filed as a request.** The classification read who you had written to from the local database, and the page that just discovered the conversation had not been saved yet — persisting happens after classification runs. A conversation whose reply and first-seen message arrive together got judged before its own evidence existed, and nothing would ever revisit it: a quiet conversation's events do not reappear in a later sync once they fall outside its window. Fixed by folding the page's own messages into the same check, so a reply counts the moment it is seen instead of waiting for a future sync to notice it already happened. **A conversation misclassified before the fix existed stayed that way forever**, even carrying a reply the database had held all along. A stored conversation's relation only changed when its events reappeared in a fresh relay fetch — which an old, quiet conversation never does, so its very first classification became permanent. Every sync now sweeps every stored conversation against current local data once, correcting rows like this without needing anything back from the relays. ## Install
More…
Pick the APK for your device's ABI — `arm64-v8a` for essentially every phone from the last several years. Signed with the same key as prior releases, so it upgrades in place. - Sep 2, 2026 0.2.0A request coordinator so the app stops asking relays the same question twice, and three bugs it turned up along the way: direct messages showing raw npubs, profile tabs that never loaded, and a Requests/Follows split that was not actually splitting anything. ## Added **A fetch coordinator sits between every repository and the relays.** Before this, each repository asked on its own and nothing knew what anything else had already requested. The active user's follow list was fetched independently by the note feed, the article feed, advanced search, explore and the profile screen — five requests for one kind-3 event, all at once on app start. Profile metadata was worse: two screens showing the same author each asked for kind 0 separately, and the profile screen bypassed the existing cache entirely. A concurrent request for something already in flight now attaches to it instead of opening a second one; two screens asking for overlapping sets of authors or notes now share whatever overlaps and only ask separately for what does not. The follow list additionally gets a short time-to-live, since the screens that want it open seconds apart rather than at the same instant. ## Fixed **Feeds, notifications and DMs lost events past about four relays.** The incoming socket flow was unbuffered, so one slow collector blocked the read loop for every relay behind it, and a query could finish on the first EOSE while other relays still had events in flight. Buffered now, and a query waits for a quorum instead of a winner.
More…
**Direct messages showed a raw npub instead of a name for many conversations.** A relay hands back kind-4 events and nothing else, so the conversation list never asked for the participants' profiles — a name appeared only when another screen happened to have fetched that profile first. **A profile's Notes and Replies tabs never loaded**, showing "unable to load content" every time. Somebody's own notes are a plain author filter a relay can answer directly, but the feed mediator only recognised following feeds and follow sets, so a profile tab fell through to a centralized API this build doesn't have. Dead since the relay migration. **The Requests and Follows message tabs showed the same conversations.** Every conversation was written under one relation regardless of which tab it was fetched for, and the list query ignored the column besides. A relation is now decided locally, the way Amethyst does it: a conversation counts as accepted if you follow the other person or you have written back to them, and everything else is a request. Answering somebody is what accepts them. **Follow/unfollow loops filled the notifications tab.** A follow list is republished in full on every change, so an account cycling follow and unfollow emits a new event id each time; one account produced seven identical "followed you" rows inside a minute. Follows are now keyed by who did it and what day, and are grouped per day in the notifications list itself rather than only until the tab is opened. One failed profile-metadata request used to leave an author rendered as a raw npub for the rest of the session, because the request was marked done before anything came back. It is released and asked again now. ## Changed **A live note arriving no longer re-fetches the whole feed.** The refresh triggered by the live subscription asked for a full page across the entire follow list on every burst; it now asks the relays only for what is newer than the newest note already held. **Note interaction counts and DM-referenced profiles are shared through the coordinator.** Likes, replies, reposts and zaps for a note were re-fetched by every feed that displayed it; profiles referenced inside a conversation sat outside every existing dedupe. Both now coalesce with whatever else is already asking. Settings > Notifications gained a "Show new followers" switch, for turning follow notifications off entirely. ## Install Pick the APK for your device's ABI — `arm64-v8a` for essentially every phone from the last several years. Signed with the same key as prior 0.1.x releases, so it upgrades in place. - Sep 1, 2026 0.1.5Reliability with more than a handful of relays, a session that fetches before you go looking, and a notifications tab that stops shouting. ## Fixed **Feeds, notifications and DMs lost events once the pool grew past about four relays.** The incoming socket flow was unbuffered, so a slow collector blocked the read loop for every relay queued behind it, and a query could finish on the first EOSE while other relays still had events in flight. The flow is buffered now, the read loop no longer sleeps before EOSE, and a query waits for a quorum rather than for whoever answers first. **Follow and unfollow loops filled the notifications tab.** A follow list is republished in full on every change, so accounts that follow and unfollow repeatedly emit a new event id each cycle. Keying notification rows by event id turned one such account into seven identical rows inside a minute. Follows are keyed by who did it and on what day now. **Follows were grouped per day only until the tab was opened.** The seen feed is paged and mapped rows one to one, so marking everything seen brought every follow back as its own row. The grouping happens in the query now, where a page boundary cannot split a day in two, and the count is of people rather than of events.
More…
**One failed profile request left an author as a raw npub for the rest of the session.** Metadata requests were marked done before knowing whether anything came back, and nothing would ever ask a second time. ## Added **A countdown before a note goes out.** Posting holds the note for a few seconds behind a countdown that can be tapped to call it off, because a note published to relays is effectively permanent. Settings > Content display has a switch and a slider from one to seven seconds. Replies go out immediately unless asked otherwise. **Notifications and direct messages are fetched at session start**, per account and cancelled on a switch. They used to be fetched only by their own paging mediators, which run when their tab is first shown — so the unread dot could not appear until you had already gone looking. **Older direct messages are pulled in on start.** The conversation request sent no limit and no `until`, so whatever a relay chose to return was the whole of local DM history, and nothing would ever go back for the rest. **A fourth onboarding screen** naming the two gestures that are otherwise undiscoverable: drag right from the middle of Home for the algorithm picker, drag left for the long-form reader. **Settings > Notifications > Show new followers**, to keep follows out of the notifications feed entirely. ## Changed **The default relay set was rebuilt by measurement.** Every candidate was asked for its NIP-11 document and then opened for a real REQ; the ones that answered with events and an EOSE on repeated attempts were kept. `relay.nostr.band` and `nostr.wine` are out of the defaults — the first answered nothing unauthenticated, the second requires payment and restricted writes and is still offered during onboarding, unticked. `purplepag.es` moved to metadata-only, where it is unusually good and where it stops costing a round trip in note queries. Nothing is ticked by default: a pre-ticked list reads like an endorsement. **The event cache gained an in-memory hot layer and is now shared.** A note recurring across feed pages, a thread and a notification preview was read from SQLite and re-parsed from its raw JSON every time — about 378µs per lookup of 40 ids, against about 15µs once hot. The cache was also built per repository and per paging mediator while being described as session-scoped, so every notifications tab started with an empty dedupe set and re-asked the relays for authors the feed had already resolved. The manual feed-refresh button is gone; the live subscription and the five-minute refresh underneath it make it redundant. ## Install Pick the APK for your device's ABI — `arm64-v8a` for essentially every phone from the last several years. Signed with the same key as 0.1.2 through 0.1.4, so it upgrades in place. - Sep 1, 2026 0.1.4Speed: fewer round trips, nothing re-downloaded, and a live subscription in place of polling. ### Changed - **New notes arrive over a live subscription instead of a 30-second poll.** The feed used to ask the relays for a fresh snapshot every thirty seconds whether or not anything had happened, so a new note appeared somewhere between instantly and half a minute late and the request went out either way. It now opens a live REQ scoped to the same authors as the feed, carrying only what is
More…
published from that moment on. The delay drops to about a second and nothing is sent while nothing happens. A five-minute refresh stays underneath, because a subscription can die quietly and a feed that silently stops updating is worse than one that updates late. - **Events and profiles already in the database are no longer re-requested.** A thread's ancestors and the notes a notification points at are usually already stored by the feed; Nostr events are immutable and content-addressed, so a locally held id is the same event. Profile metadata is deduplicated per session rather than permanently, so a changed display name still comes through. - **A full page no longer waits for the slowest relay.** Every query paid a grace period after the first EOSE and, when that EOSE carried no events, waited for the slowest relay up to the full timeout — even when the first relay had already delivered everything asked for. The early exit is gated on a *full* page, never a partial one, so a fast relay with a single event still cannot hide the rest of the network. - **The follow list is no longer refetched before every page**, and author chunks are wider with more in flight, which brings the common case down to one sequential wave instead of two. ### Fixed - Opening a reply from the notification list walked the ancestor chain one relay round trip at a time, up to five, then made three or four more in sequence. NIP-10 already names a reply's root and parent in its `e` tags, so the whole ancestor set fits in one filter: ten sequential round trips become three, and the first is the opened note together with its replies. - A tagged user rendered as an ellipsized npub instead of the name they chose. The feed and thread fetchers requested metadata only for the authors of the events they loaded, never for the profiles mentioned inside them. - Follow notifications were grouped under a single key that covered every follow the account had ever received. They are bucketed by day now. ### Downloads APKs are split per ABI; most phones need **arm64-v8a**. Same signing key as 0.1.2 and 0.1.3, so this upgrades in place. ```bash sha256sum -c SHA256SUMS.txt apksigner verify --print-certs librenostr-0.1.4-arm64-v8a.apk ``` - Aug 31, 2026 0.1.3Notifications, Reads scoping, highlights and external-signer permissions. ### Fixed - **Notifications were slow and returned a truncated page.** A Nostr filter takes a list of kinds, so one REQ is enough; the fetcher issued five — replies, reposts, reactions, zaps, follow lists — and each fanned out to both relay pools, so opening the tab cost ten pool queries with their own EOSE grace and timeouts. The split also truncated the result: every kind got the full `limit` independently and the union was cut back to `limit`, so a page was whichever
More…
kind happened to be busiest and the rest fell off the end. Each tab now requests only the kinds it can display, and referenced notes and actor metadata are fetched in parallel instead of chained. - **Notification paging stopped after one page** on sparse tabs, because the end of the list was decided by the group-filtered row count rather than by what the relays returned. - **Zaps were credited to the wrong person.** A NIP-57 receipt is signed by the recipient's LNURL server, not by the zapper; the sender is the author of the kind 9734 request embedded in the `description` tag. - **Long-form Reads pulled from the global firehose.** The author list was passed as "no constraint" when empty, which happened for topic feeds, search feeds and any unrecognised spec — and the public long-form firehose is mostly spam. Every query is now scoped to an explicit author set: the user's follows, widened once to the follows of those follows when follows alone cannot fill a page, capped at 1000 authors because relays reject very large filter arrays. When no scope can be resolved the feed returns empty instead of falling back to global. - **Topic Reads queried the wrong tag**, putting the hashtag in `#e` (event ids) instead of `#t`. - **NIP-84 highlights never loaded.** The article fetch and the highlights fetch ran sequentially inside one `try` that caught only `NetworkException`, so any failure of the first skipped the second. They now run in parallel and each handles its own failure. - **Highlights could not be signed by an external signer.** The notary gated signer requests on a kind allowlist that omitted 9802, so a highlight was rejected locally and Amber was never asked; polls, reports and stream mute lists were blocked the same way. Separately, the NIP-55 connect request asked for `sign_event` on kind 1 only, so every other kind prompted on each use. Both now derive from a single list, and the connect request also asks for nip44 encrypt/decrypt and decrypt_zap_event. ### Downloads APKs are split per ABI; most phones need **arm64-v8a**. This release is signed with the same key as 0.1.2, so it upgrades in place. ```bash sha256sum -c SHA256SUMS.txt apksigner verify --print-certs librenostr-0.1.3-arm64-v8a.apk ``` - Aug 31, 2026 0.1.1Localization, unread badges and feed ordering, plus the fixes from the [2026-08-31 audit](https://github.com/Lwb89dev/librenostr/blob/main/docs/SECURITY_AUDIT_2026-08-31.md). ### Added - In-app language selection with 26 translations (Bulgarian, Croatian, Czech, Danish, Dutch, Estonian, Finnish, French, German, Greek, Hungarian, Irish, Italian, Japanese, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Chinese) and an Android `localeConfig`. - Unread badges for messages and notifications, computed from the local database instead of a remote counter. - A "mark all as read" action in the notifications list, and local mark-all-as-read for direct message conversations. - A new-notes indicator on the home tab, and an optional automatic feed refresh when the app returns to the foreground. - `wss://nostr.wine` in the fallback relay set.
More…
### Changed - Feeds are ordered by event timestamp rather than insertion position, so a relay reconnect can no longer shuffle the timeline. Notification ordering gained a stable tie-break on notification id. - Interaction counters are resolved from relays for reposts and for the notes in an opened thread, and the feed is invalidated once they arrive so visible cards redraw without navigating away. - Notification previews now fetch the events their `e` tag references, so likes, zaps and reposts render an actual note body. - Paging loads 50 notes initially and 20 per subsequent page. - A relay query whose first EOSE carries no events now waits for the remaining relays instead of returning empty. - Added `avif`, `svg` and `ico` to the recognized media types. ### Security - **Direct-message and mute-list queries are no longer broadcast to the hardcoded public fallback relays** when the account has its own relays configured. Previously, opening the messages tab disclosed the user's pubkey and reading activity to seven third-party relay operators regardless of configuration. - **An empty relay snapshot no longer clears the cached feed.** Offline or slow relays used to wipe the local timeline on every foreground, leaving nothing to fall back on. - **Relay connection status is now cleared when a relay closes the socket.** The teardown path cancelled its own coroutine, so the closed callback never ran and dead relays kept reporting as connected. - Replaced two uses of `kotlin.runCatching` with the project's cancellation-safe `runCatching`, which no longer converts coroutine cancellation into a logged failure. ### Downloads APKs are split per ABI and signed with the LibreNostr alternative key (RSA 4096, `CN=Luigi Antona, OU=LibreNostr, O=Lwb89dev, C=IT`, SHA-256 `3ff954de6f70d64b59a15d38d0019f1f796462192a50c2a1d490c1fa6f691637`). Most phones need **arm64-v8a**. Verify before installing: ```bash sha256sum -c SHA256SUMS.txt apksigner verify --print-certs librenostr-0.1.1-arm64-v8a.apk ``` - Aug 30, 2026 0.1.0# Changelog All notable changes to LibreNostr are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). LibreNostr is a fork of [Primal](https://github.com/PrimalHQ/primal-android-app) (MIT, Copyright (c) 2023 PRIMAL SYSTEMS INC.); this log covers changes made in the LibreNostr fork on top of the imported `3.5.25` baseline. ## [0.1.0] - 2026-08-30
More…
Initial LibreNostr release. Every active Android data path now talks to Nostr relays directly instead of a Primal cache server. ### Added - Relay-only data layer: feeds (**Latest**, **Latest with replies**), profiles, follow lists (NIP-65), threads, notifications, direct messages (NIP-04), bookmarks (kind 10003), mute lists (kind 10000/10555/30000) and live-stream lookup (kind 30311) are all read and written directly against configured relays. - Relay-only Reads: article feed, article details/comments (NIP-22/NIP-23) and highlights (NIP-84), replacing the Primal Articles API. - Relay-only Explore: profile search, popular people, trending topics/zaps and note reaction/repost action lists, with NIP-50 search where available. - Relay-only polls (kind 1068/6969/1018) and NIP-57 zap receipts (kind 9735), including invoice-to-zap enrichment. - `RelayPool` REQ/EOSE/CLOSE subscription API with dedupe, timeouts and bounded concurrent subscriptions (capped at 64). - LibreNostr branding: app name, launcher icon, `nostrich.org` deep links (`/home`, `/reads`, `/notifications`, `/p/<npub>`) replacing `primal://` and `primal.net`. - Project documentation: `docs/UPSTREAM.md`, `docs/BASELINE.md`, `docs/ARCHITECTURE_UPSTREAM.md`, `docs/PRIMAL_SERVER_DEPENDENCIES.md`, `docs/LIBRENOSTR_ROADMAP.md`, `docs/LIBRENOSTR_BACKLOG.md`, `docs/RELAY_ONLY_MIGRATION_STATUS.md`, `docs/SECURITY_AUDIT.md`. - ABI-split release APK packaging (`armeabi-v7a`, `arm64-v8a`, `x86_64`) and an `alternative` signing config independent of Google Play signing. ### Changed - `SocketModule` injects a fail-closed `RelayOnlyApiClient`; the legacy shared `PrimalApiClientFactory` / `PrimalHttpApiClientFactory` throw instead of silently reconnecting to a centralized cache. - Wallet: NWC (NIP-47) is the only enabled in-app wallet transport. Legacy Primal-wallet payment/balance/invoice paths and centralized NWC provisioning are fail-closed; zaps and invoice links fall back to the Android `lightning:` intent when NWC isn't configured. - Local credential storage now uses Android Keystore AES-GCM (versioned format v2, 128-bit auth tag); legacy CBC files are readable only for migration, with no plaintext fallback. - Android backup is disabled (`allowBackup=false`) and backup/data-extraction rules exclude all app data; cleartext network traffic is disabled. - Note counters, event stats and zap totals are now aggregated locally from relay-observed events instead of Primal's synthetic stats payload. ### Removed - Firebase Cloud Messaging registration and `PrimalFirebaseMessagingService`; push token methods remain as local no-ops so no device token or signed authorization event reaches a central service. - Primal well-known profile resolution, follow-pack remote paging, DVM featured-feed discovery, advanced-search parsing endpoint, and the Primal Articles/EventStats/Settings remote APIs on the active path. - Primal deep links (`primal://`, `primal.net` app-link intents) and the `CONTRIBUTING.md` template inherited from upstream. ### Security - Full audit results and verification evidence (build/test/lint runs, APK manifest and string scans, log review) are in `docs/SECURITY_AUDIT.md`. - No `primal.net`, Firebase, `primal://`/`primalconnect://` or `nostrnwc+primal` references remain reachable from the active production code path; the compiled APK was scanned to confirm this. ### Known limitations - Wallet/premium/external-signer UI and compatibility modules — including the optional Breez/Spark native wallet library — remain compiled in; their centralized transports are fail-closed but the modules themselves are scheduled for removal. - The internal package namespace is still `net.primal.android`; renaming it is deferred until after the networking migration, per `docs/LIBRENOSTR_ROADMAP.md`. [0.1.0]: https://github.com/Lwb89dev/librenostr/releases/tag/v0.1.0