OUTKAST
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
- Nov 5, 2026 2.4.0### Added - **NIP-68 picture notes.** A kind 20 picture posted from another client now shows up as an ordinary note: home feed, profile, media grid, bookmarks, Network, the live subscription, notifications, threads, quotes and Explore (trending hashtags and zapped notes). The caption stays the text of the note, the pictures come from `imeta` (plus plain `url` and `image` tags), and the hashtags are kept. A picture that is a reply stays on the replies feed, the same way a kind 1 reply does. A content warning hides the body and the pictures until you tap Show; the header and the actions stay. Reposting a picture publishes a NIP-18 kind 16 generic repost, and that repost appears in the feed when the note inside it is a picture that can be shown. Kind 1111 comments count as replies,
More…
including a nested comment that names the thread root with an uppercase `E` tag. - Outkast still publishes its own notes as kind 1, so clients that only read kind 1 keep seeing them. Close-friends posts and pictures whose `imeta` carries an encryption key are left out. An expired picture is dropped. A story that has not expired yet shows as an ordinary picture. - Nov 2, 2026 2.3.0### Added - **NIP-20 command results.** Relay `OK` responses now expose the event id, acceptance status, machine-readable prefix and human-readable detail. The standard `duplicate`, `pow`, `blocked`, `rate-limited`, `invalid`, `restricted`, `mute` and `error` prefixes are supported, together with NIP-42's `auth-required` and forward-compatible unknown prefixes. Publishing still completes as soon as one relay accepts the event; when every relay refuses it, the error includes each relay's URL and the reason it returned. ### Fixed
More…
- Relay responses that arrive before the publish collector is attached are queued instead of being lost, so an immediate acceptance or rejection no longer turns into a ten-second timeout. - Direct-message and mute-list requests no longer fall back to public relays the user did not choose, including when the account has no configured relays. Private subscriptions behave the same way. - Changing the key on the login screen cancels the previous profile request, preventing a slower, older response from replacing the profile for the newly entered key. - Compressed WebSocket frames now use the correct gzip decoder and incremental bounded reads, instead of failing on ordinary payloads or attempting an exact 1 MiB + 1 byte read. - The system-language option now respects Android's per-app locale instead of forcing the device-wide language. - The Italian relay-deletion confirmation once again includes the relay URL. - Oct 26, 2026 2.2.1### Added - **Photo editor before upload.** A photo picked from the gallery or taken with the camera, for a note, a reply or a profile picture or banner, now opens in an editor before it is attached: crop (free, original, square, 4:3, 3:2, 16:9), rotate, flip, straighten, vertical and horizontal perspective, exposure, brightness, contrast, highlights, shadows, black point, saturation, vibrance, temperature, tint, sharpness, vignette, eight filters with an adjustable strength, and an Auto button that proposes the sliders from the picture. Hold the picture to see the original. Done with nothing changed attaches the photo exactly as it was, untouched; Done with edits draws them at full size (up to 12 megapixels) into a new JPEG with no metadata at all, so the location and camera details of the original do not
More…
travel with the edited copy. Videos, GIFs, SVGs and animated WebPs skip the editor. The engine is the one from the eikon gallery (MIT), with its tests. The editor is translated into all 25 languages the app ships in. - **Network, a new section of Discover.** Notes by people you do not follow that people you do follow liked or reposted in the last 48 hours, the most interacted-with first: the note's reactions plus its replies plus the number of zaps it received (the number, not the sats, so one large zap does not outweigh a hundred small ones), then the number of your friends behind it, then the newest. Everything is computed on the phone from your follow list and your friends' reactions, in a handful of relay requests and with no ranking server; a note needs two friends behind it when you follow 40 people or more. A ranking has no "older than" to page by, so the list loads whole (up to 100 notes) and then ends; pulling to refresh recomputes it. This is the nearest honest version of "popular among friends of friends": nostrich.org's Explore, which was the model, does not work that way, it shows global trending notes ranked by an external index. - **Create your algorithm.** In the Explore panel of Orbit, "Your algorithms" lists the lists you created or imported, and with none yet it explains what an algorithm is (a list of people whose notes make up a feed) and offers a Create your algorithm button. The creation screen takes a name and the people: pick them from your contacts (everyone you follow, with a search box that filters them) or find anyone, contacts or not, with the same box, which also accepts a pasted `npub` or `nprofile`. Above the people, your existing lists can be imported in one tap. The algorithm is published as a NIP-51 follow set, so other clients see it as a list too, and it is added to your feeds. - Explore's first page lists where it can take you (Network, Follow packs, Feed gallery, Zaps) instead of showing only recent people and searches. ### Fixed - **Mute did not stick, and did not reach everything.** Opening any profile or the muted accounts screen while the relays were slow replaced the stored mute list with an empty one (a relay answering nothing was taken for "you muted nobody"), so muted people came straight back into the feeds. A relay that returns no mute list now leaves the stored one alone, while a list that is really empty still empties it. A mute now shows at once and is taken back if it cannot be published, instead of looking unresponsive for the several seconds the relays need. Muted people are also left out of Notifications (replies, mentions, reactions, zaps) and Messages (the conversation and its unread badge), which the mute list never reached, and a muted account whose profile was never fetched is listed in the muted accounts screen so it can be unmuted. - **Unfollow did nothing visible.** Unfollowing changed the button only: the person kept feeding the home feed for up to five minutes because the follow list the feeds read is cached for that long, and their notes already in the feed were never removed. The newly published list now replaces the cache and the unfollowed person's notes leave the following feed. A relay that had not received the latest list could also hand back an older one, which silently undid the last follow or unfollow; the newest list wins now, both when reading it and when building the next change on it, and a list signed on this phone is always accepted. Following or unfollowing no longer deletes the hashtags you follow from your follow list either. - **A custom reaction came back as the red heart.** The orange heart, the thumbs up or any other emoji you react with now stays on the note you reacted to, for you, instead of the stock heart, drawn whole (it used to be cut off in the row of counters). It is remembered per note and also read back from the relays for reactions made on another device or client. - **Tagged people showed as an npub.** A mention was saved with the person's name only if that person's profile was part of the same relay response as the note; profiles fetched on an earlier page, which is most of them, left the shortened npub in the note for good. Mentions are now resolved against every profile already stored, mentions written only in the text (no `p` tag) get their profile fetched too, and notes saved earlier with an npub are rewritten as soon as the name arrives. - **"Rispondi" was cut to "Rispo".** The six tool icons under the reply field took the room of the button. The button is measured first now, the icons are 40dp wide instead of 48dp and scroll sideways if the screen is still too narrow. The label is one line in every language. - Taking a photo with the camera button left an empty temporary file in the cache on every redraw of the button. The file is created when the button is tapped, one per photo. - In Explore, choosing Network, Feed gallery or any other section left no way back to the list of sections: Back went to Home or closed the app. Back from a section now returns to the list, and Back from the list leaves Explore as before. Opening Explore from Orbit also lands on the list instead of on the section that was open when you left. - 80 strings that were still in English in every language (Tor settings, web of trust, onboarding, private replies, bookmarks, quotes, Orbit) are translated in all 25 languages. - The first page of Explore showed pulsing placeholders forever when you had not visited anyone yet, because the recent people it waits for are read from the phone and an empty list is the final answer. It shows a short note instead. - Removing an algorithm from the list does not touch the list on your relays; it can be imported again. ### Changed - The local database moves to version 7 (the user's own reaction is stored per note); the update is automatic and keeps everything. - The Discover entry in the Orbit panel is now a filled accent button with an icon and an arrow, so it reads as something to tap instead of as a label. - The Network section opens faster. It is resolved ahead of time when Explore opens (the ranking, the notes it quotes and everyone's profile), so tapping it finds the page ready; the counters used for the order are asked for together with the notes instead of after them, which saves a round of requests when nothing is ready yet; and a request that arrives while one is running waits for it instead of repeating it. A page built in the last ten minutes is now shown as it is when the section is opened again, and an older one stays on screen until the rebuilt page replaces it, where it used to be cleared first and leave an empty screen for as long as the rebuild took. - Create your algorithm opens faster: the contacts and your lists start loading while the Explore panel is still on screen, the lists stay visible while they refresh, and the contact list is sorted off the main thread and no longer filtered again on every keystroke in the name box. - The Orbit tile and its panel are called **Explore** (Esplora in Italian, translated in every language) instead of "Algorithm", and the button inside it that opens the Discover world keeps the name **Discover** (Scopri), so the two no longer repeat each other. The panel no longer lists Recent and Recent with replies, which are in the Home menu; Discover takes their place at the top. ### Removed - Explore's **Media** page. It ranked the media of the whole network, which only the Primal index could compute, so without it the page had nothing to show. - Oct 22, 2026 2.1.1### Added - Dragging sideways along the portal (the pill at the bottom of the screen that opens Orbit) runs through the worlds while the finger is still down, one world every 36dp, so a single stroke can cross all of them. The finger moving left goes to the next world, right to the previous one, like the swipe on the content. Dragging up still opens Orbit and a tap still opens it too; a short stroke that ends on the portal no longer opens Orbit by accident. ### Changed
More…
- Orbit is reorganized. The tiles now read Feed, Inbox, Long reads, Discover, Messages, Bookmarks, You, Settings. The Algorithms and Discover tiles, which both read as "the algorithm place", are merged into one: it opens a panel with an entry into the Discover world and, below it, your own feed list as before. - Messages has its own Orbit tile with its own unread badge. The Activity/Messages switch at the top of Inbox is gone, and the Inbox tile now counts notifications only. - Swiping between worlds follows the order of the Orbit menu: Feed, Inbox, Long reads, Discover. It used to be Feed, Discover, Long reads, Inbox. The slide towards Messages and Settings follows the same order, with Messages after every world (it used to sit between Feed and Inbox). - The swipe from the screen edge now belongs to the lower half of the screen, where the thumb is, and the upper half is left to the system back gesture. The band where the back gesture is turned off moved from the middle of each edge to the bottom. Android allows at most 200dp of it per edge, so on a tall phone it does not cover the whole lower half; above it, a swipe that starts a little inside the edge still changes world. ### Removed - The Create (+) button on the Settings screens, where there is nothing to post from. - Oct 16, 2026 2.1.0### Added - Swiping up on a photo or video in the full-screen viewer opens the note's thread, with its replies, rising from the bottom of the screen. The Reply button still opens the editor. The swipe is ignored while the photo is zoomed in, so moving around a magnified picture cannot leave the viewer. ### Fixed - Swiping between Feed, Discover, Long reads and Inbox failed on phones with gesture navigation:
More…
the edge strip lay inside the area Android reserves for the back gesture, which took the swipe. Android lets an app take only 200dp of each edge away from the back gesture, so the edge swipe alone could not fix this: measured on a phone, a swipe from the edge at any other height was read as "back" (second world to the first, first world out of the app). The swipe now also works from anywhere on the screen, like a pager: left for the next world, right for the previous one. Horizontal scrollers keep their own swipes (photo carousels, the sections of Discover and Long reads) and hand the swipe over only when they are on their last page. The edge swipe stays as a shortcut that wins over them, protected from the back gesture in the middle of each edge. - The same swipe only ever worked for the first two worlds: the gesture kept the destination it was given when the screen first appeared, so after one move it kept aiming at the same place. It now always uses the world currently showing. - The edge strip no longer swallows taps and vertical scrolls that start at the edge of the screen; it takes over only once a finger has clearly started moving inward. - Picking, in Orbit, the feed that is already showing (Home → Recent, or Recent with replies) did nothing. It now refreshes that feed and scrolls it to the top. - The app crashed when the Feed gallery section of Discover came on screen if the same feed had been received twice (it is fetched from several relays): the list used the feed's identity as its key and refused the duplicate. Duplicates are now dropped before the list is built. Swiping through the sections of Discover reaches this section far more easily than the section picker did. - Oct 13, 2026 2.0.0### Highlights - Introduced OUTKAST Orbit, a gesture-first navigation model with no persistent bottom bar. - Added inward edge swipes to move between Feed, Discover, Long reads and Inbox with directional transitions, plus a pull-up/tap portal for discoverable navigation. - Centered the OUTKAST wordmark and “You don’t need permission to exist online.” tagline in the Feed header; removed the Latest control and the duplicate header avatar entry point. ### Navigation and workflows
More…
- Home now opens an explicit Recent / Recent with replies choice. - Algorithms now opens inside Orbit, retaining the complete feed list and advanced-search editing without the old side drawer. - Long reads, Discover and Inbox are first-class Orbit destinations while their existing paging, notifications and messages behavior remains intact. - Bookmarks, Profile and Settings are now equal-sized Orbit actions; Profile is no longer duplicated in the header, and Settings is no longer hidden behind an unreachable navigation bar. - Compose remains globally available as a floating action. ### Product and compatibility - Removed the legacy navigation-bar component and the algorithm/bookmark side drawer from the active UI path. - Renamed the built-in default note feeds to Recent and Recent with replies. - Preserved `applicationId = com.librenostr.android`, version upgrade compatibility, relay identity, databases, DataStore state, Android Keystore aliases, provider authorities and release signing. - Release artifact is `outkast-2.0.0-arm64-v8a.apk`, signed with the configured alternative release keystore. ### Verification - `:app:compileDebugKotlin` passed. - `:app:testDebugUnitTest` passed. - `:app:assembleDebug` passed. - Final `altRelease` build and APK signature verification are performed as part of the 2.0.0 release handoff. ### Added - OUTKAST launcher, adaptive and themed icons derived from the supplied O/K artwork. - A direct onboarding choice between creating a new identity and bringing an existing one. - Four gesture-connected content worlds — Feed, Discover, Long reads and Inbox — with a global Create action. - An explicit compatibility and regression plan in `docs/OUTKAST_MIGRATION.md`. ### Changed - Replaced the persistent navigation dock with OUTKAST Orbit: edge swipes move through Feed, Discover, Long reads and Inbox, while a compact pull-up portal exposes the complete map and Bookmarks. Compose remains a floating global action. - Removed the legacy algorithm/bookmark drawer and every duplicate header shortcut. Orbit now owns Recent/Recent with replies, the complete algorithm list, Long reads, Bookmarks, Profile and Settings; all utility tiles share the same compact geometry. - Replaced the Home controls with a centered OUTKAST wordmark and the product tagline. - Rebranded user-facing application, manifest labels, store metadata and release artifacts to OUTKAST. - Replaced eight legacy themes with curated OUTKAST Dark and OUTKAST Light identities. Existing saved theme values migrate by luminance and system-following remains available. - Connected Discover to the existing people, search, feeds, zaps and media experience; Inbox now exposes Activity and Messages together. - Reworked onboarding, empty-state and publishing copy around progressive disclosure and plain Nostr language. ### Compatibility - Preserved `com.librenostr.android`, signing configuration, provider authorities, databases, DataStore files and Keystore access for in-place upgrades. - Oct 12, 2026 1.1.3### Added - **Quotes: a counter and a list.** A note's stats line now shows how many notes quote it, and tapping it opens a new Quotes tab next to Zaps, Likes and Reposts. The tab lists the quoting notes themselves, as full cards, and a tap on one opens that note's thread. Quotes are found the two ways clients write them (a `q` tag, or an `e` mention with the note's link in the text), and a reply that happens to embed the note it answers is still counted as a reply. Notes you quote now carry a `q` tag as well, which is what other clients look for. - **React with any emoji.** A long press on the heart opens a picker with six common reactions and
More…
the whole emoji list. A reaction on a note you already reacted to replaces the old one. The Likes list shows each person's emoji instead of a heart where they sent one. - **Comments the NIP-22 way (kind 1111).** Comments on an article, and replies to those comments, are now published as kind 1111 with the article as the root and the comment as the parent, and read back as a tree: replies under an article are drawn nested, the way thread replies are. Replies to ordinary notes stay NIP-10 kind 1, as the NIP says. Comments of both kinds, including the kind 1111 ones other clients write under plain notes, appear in threads and in notifications. ### Changed - **A tap on a filled heart takes the reaction back.** It used to do nothing, so a mistaken reaction could not be undone. The reaction is withdrawn with a deletion request and the heart empties at once; if the request cannot be published, the heart is filled again. - **GIF search uses LibreNostr's nostr.build access.** Results come from nostr.build with the app's registered key instead of falling back to GIFverse, in one request of up to 200 GIFs (no more paging), searched the way the service asks (trimmed, lower case, no single letters). The picker says "GIFs from nostr.build" with a link to the site, as the service's terms require. When the service limits the app, the picker says so and stops asking until the limit lifts instead of switching provider. Release builds get the key from a repository secret and fail loudly without it. - **Upload errors say what the servers answered.** "Unable to upload file" now carries each server's own words (for instance "Access denied (403)" or "File size exceeds the maximum allowed size of 20 MiB"), so a refusal is no longer indistinguishable from a bad connection. ### Fixed - **Uploads failed over Tor.** blossom.band and blossom.nostr.build refuse uploads that arrive through a Tor exit, and cdn.satellite.earth wants an upload permission nobody has by default, so with the default servers every upload failed. While every connection goes through Tor, servers that accept anonymous uploads (cdn.nostrcheck.me, cdn.hzrd149.com) now come right after your own. - **Videos could not be uploaded.** The default server takes at most 20 MiB and a phone video is usually far larger, so every default server refused it. Large files are now offered to each server first and skipped by the ones that say no, without sending the file, and two more servers that take large files are tried when none of the configured ones will. Progress is also reported in larger steps, which spared a long upload tens of thousands of redraws. - **The media tab of a profile never loaded.** It asked a centralized service that this build does not have. It now reads the author's notes from the relays and shows the ones with a picture or a video. - **Article comments never loaded.** The article itself was looked up with a filter that relays do not match, so the page found no article and, with it, no comments. - **A like that could not be published stayed counted.** The failed reaction left the counter raised and the heart filled until the next refresh. The same went for reposts and zaps. - **Files mirrored onto the server that already had them.** When the first server refused an upload and a later one took it, the mirroring still included the one that took it. - Oct 8, 2026 1.1.2### Fixed - **Older notes were fetched while scrolling but never shown.** Loading more notes stored them in the database without telling the list, whose query deliberately does not watch that table, so the list kept what it had and looked as if it had stopped loading. The new notes only appeared when something unrelated (a like, a mute, a bookmark sync) happened to refresh it. Every page added to a feed now refreshes the list. - **Returning to the feed could skip notes or stop paging.** The feed is replaced with its newest page whenever the screen comes back into view, but the loader still remembered how far back the
More…
previous scroll had gone: the next page started there, skipping everything in between, or, when it repeated a request from a few seconds earlier, ended the list for good. It now starts over from the new page. - Oct 7, 2026 1.1.1### Changed - **Dark Pixel is the default theme.** It applies to anyone who never picked a theme: a fresh install, or an existing one that never opened the appearance settings, no longer follows the system's light/dark setting. A theme you chose stays, and so does "adjust to the system" if you turned that on. ### Fixed
More…
- **Older notes stopped loading while scrolling.** A page that no relay answered (a dropped connection, relays still backing off after one) was read as "there is nothing older", and four of those in a row ended the feed for good, which could happen within a second of a signal glitch. An unanswered page now changes nothing and is asked again on the next scroll, after two quick retries. The same walk had two more ways to stall or skip: a page made only of replies, which a notes feed hides, looked empty even though older notes were behind it, and a busy group of followed accounts could push the page past notes it had not been read to yet, losing them; and when the list was hiding every note a page had just stored, the next request jumped six hours back instead of continuing from where the page ended. - **Long reads disappeared from the Reads tab.** A refresh that no relay answered replaced the cached articles with nothing, and that refresh runs whenever the cache is a few minutes old. It now keeps what it had. Two quick scrolls could also end the list permanently (the guard against repeating a request closed it instead of skipping the repeat), and the whole follow list went out as one filter that relays with a size limit refuse; it is now split into groups of 250 authors, like the note feed. - **Profile header said "Followed by" over the wrong list.** The people shown are the ones the profile follows and you follow too, not its followers. It now reads "Following". - **Polls could not be published with an external signer.** Kinds 1068 (poll) and 6969 (zap poll) were missing from the set of kinds sent to Amber or a NIP-46 bunker, so both were refused before anything was sent and reported as a generic publish error. Voting already worked. - Oct 2, 2026 1.1.0### Added - **GIFs from nostr.build.** The GIF picker now searches nostr.build's index of GIFs uploaded to its free public pool, replacing the Wikimedia Commons search. It opens with results and one-tap topic chips (gm, lol, bitcoin…), suggests search terms as you type, and posts the GIF by its URL with a NIP-92 `imeta` tag (type, dimensions, size, alt text) instead of downloading and re-uploading it. nostr.build only serves registered clients, and LibreNostr is not registered yet: until it is, the picker answers from GIFverse (the index Ditto uses) and says so in its "Powered by" line. Once the registration is done it switches to nostr.build by itself, with no update needed.
More…
- **Custom emoji packs (NIP-30).** `:shortcode:` in a note is drawn as the image the note declares. The composer has a new emoji panel with the built-in LibreNostr Ostrich pack and the packs on your emoji list (kind 10030), and published notes carry the matching `emoji` tags. Settings has a new Emoji packs screen to browse packs from your relays, add one from an `naddr` link, and create, edit or delete your own (images are uploaded to your Blossom servers). ### Fixed - A single failing relay could stall every load in the app — notes, direct messages and notifications alike. Every finished query re-dialled each unreachable relay just to close its subscription while holding one of the few query slots the whole app shares, so a dead relay starved the others until their queries timed out empty. Closing a subscription no longer opens a connection; a relay that fails to connect is now left alone for a growing interval (2 seconds up to 5 minutes, at least a minute when the server refuses outright) and is retried at once when the network changes, when the Tor mode changes, or when you reconnect it by hand; concurrent callers share a single connection attempt; and DM and publish operations no longer connect to their relays one after another before starting. - Sep 29, 2026 1.0.1### Fixed - Deck mode crashed immediately on any tablet, as soon as it activated (opening the app in landscape, or rotating into it). Each column sets up its own view-model store so closing it frees what it opened, but that store wasn't wired to Hilt's dependency injection, so the very first view model a column tried to create — its feed — crashed instead.
- Sep 29, 2026 1.0.0LibreNostr's first stable release. Every data path in the app — feeds, profiles, threads, notifications, DMs, search, bookmarks, mute lists — has run directly against Nostr relays since the 0.x series; this release adds a tablet layout on top of that and closes a long list of bugs found in a full review of the app, several of which could silently lose data. ### Added - **Deck mode for tablets.** Hold a tablet in landscape and LibreNostr switches to a multi-column layout in the style of notedeck; rotate back to portrait and you get the usual tabbed app. Phones
More…
never switch, in either orientation. - Several named decks, switched from a sidebar; each can be renamed, reordered or deleted. - Columns for any of your feeds, a hashtag, a profile, Reads, notifications and messages. A profile column can be picked by name, NIP-05 address, npub or hex key. - Columns can be rearranged by drag and drop (or with the arrow buttons in the column header). - Opening a note, a profile or a DM conversation from a column opens it inside that same column, with a back button to return to the column's feed, instead of leaving the deck. - The deck layout is saved on the device, separately for each of your profiles. - Advanced search now understands `OR` between words, `-word` to exclude a word, `filter:image`/`filter:video`/`filter:audio`, and the custom date range from the date picker (which was previously ignored). ### Changed - **Search is much faster.** Many relays answer a full-text search request by refusing it; the app used to miss that refusal and wait out a timeout of several seconds before trying the fallback, on every step of every search. It now moves on immediately. - Profile search shows matches already stored on the device straight away and refines them as relays answer; typing a new query cancels the previous search instead of letting its results arrive late and overwrite the new ones. - Hashtag feeds and hashtag columns are in chronological order, newest first. Searching `#bitcoin` could previously show posts from years ago at the top. - Loading more notes no longer skips newer notes held only by slower relays: a page is closed only once enough of your relays have answered, not as soon as the fastest one fills it. - Feeds you are not looking at (another tab, a removed deck column) no longer keep a live relay subscription open in the background, saving battery and data. ### Fixed - **Mute list and bookmarks could be wiped.** Muting, unmuting or bookmarking while relays were slow to answer could publish a list containing only that one change, replacing everything else on your relays. Private (encrypted) entries and entries written by other clients were also dropped on every edit. Edits now always start from your latest published list and keep everything they don't change. - With more than one profile in the app, bookmarks and notifications of one profile could overwrite those of another when both had bookmarked the same note or received the same notification. - The extra relays LibreNostr adds to reach people you follow who publish elsewhere were also sent your relay login (NIP-42 AUTH) and your private requests (DMs, private lists). They are now read-only helpers used for public content only. - Profile names and pictures could flip back to an older version when a relay holding an outdated copy answered last. - An author could stay shown as a raw npub for the rest of the session if a screen was closed while their profile was still loading. - Loading older notifications could skip some between one page and the next. - The notification badge never came back after you had opened the notifications once, until the app was restarted. - Tapping the "new notes" pill replaced the feed with just the new notes, dropping everything already loaded below them. - Replying from inside a thread with the undo timer enabled showed no countdown, so the reply seemed to do nothing for several seconds, and leaving the thread in that window discarded it. The countdown now appears there too. - A note could be published twice when "post now" was tapped as the undo countdown ran out. - The media gallery failed to open images and videos whose address contains a query string. - Unread message counts could come back after a conversation had been marked as read. - Searching for text containing quotes or a backslash broke the search. - Profile search no longer matches almost every profile on short queries (it used to match the profile data's field names and fragments of picture URLs). - `bitcoin OR lightning` required both words instead of either, and a `since:`/`until:` date could be misread as a `kind:` filter that matched nothing. - 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