#Amethyst v1.14.0: New Share Intents, Relay Login, and a Muc...

Amethyst
npub142gywvjkq0dv6nupggyn2euhx4nduwc7yz5f24ah9rpmunr2s39se3xrj0
hex
00d306e01792e48b93638b73b57a7eb8b89622a338b1b4f529622150d46cd710nevent
nevent1qqsqp5cxuqte9eytjd3ckua40flt3wyky23n3vd5755kyg2s63kdwyqprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgs24yz8xftq8kkdf7q5yzf4v7tn2ek78v0zp2y427mj3sa7f34ggjce8cn8wKind-1 (TextNote)
#Amethyst v1.14.0: New Share Intents, Relay Login, and a Much Faster Start
Highlights:
- Improves NIP-84 Highlights — composer, feed, and share intent.
- Redesigns relay login (NIP-42) and ends the per-relay prompt storm.
- Adds Share targets to Pictures, Videos, Shorts and Torrents feeds.
- Adds a screen that explains why every relay subscription exists.
- Fixes the cold-start out-of-memory kill and cuts time to first paint.
- Brings Desktop to parity on profiles, DMs, settings and key backup.
- Adds Trusted Lists (kinds 30392–30395) to Quartz.
New Features
Highlights (NIP-84)
- Adds a Highlight composer, with an annotation field, a passage editor, and a source reference that can be a Nostr event or a web URL.
- Adds a Highlights feed, filterable by authors, follows, hashtags and geohashes.
- Accepts shared text from any app as a new highlight.
Feeds and Composing
- Adds four home feed content types: Pictures (NIP-68), Videos and Shorts (NIP-71), and Torrents (NIP-35), each with its own toggle.
- Adds "New Picture", "New Short" and "New Video" share targets, so media shared into Amethyst opens the matching composer instead of a text note with a link.
- Adds a bulk audience picker to the short-note composer: search people lists and follow packs, review the members, then add them all at once.
- Adds a poll results page with per-option vote counts and a filterable voter list, replacing the feed card's four-avatar preview.
- Shows rich previews for comments scoped to external content (NIP-73), both in the "replying to" line and as the thread's title.
- Offers a "Copy Original / Copy Translated" chooser when copying a note that has been translated.
- Opens the edit screen when a draft reply is tapped in a thread.
Relay Login (NIP-42)
- Redesigns the relay login permissions screen. Explicit exceptions, relays blocked by your block list, and recent logins are now three separate sections.
- Starts new accounts on "always log in" instead of deciding per relay.
- Remembers a login for the rest of the session when you answer without ticking "remember", so a reconnect stops asking again.
- Honors "always log in" for relays your own account does not publish to.
- Makes the "reading someone I follow" toggle reachable — it sat behind a first-party gate that could never be true.
- Counts NIP-29 groups and Concord communities as rooms you joined, so their host relays authenticate under "my relays and venues".
- Waits for an auth challenge to resolve rather than letting the fetch time out.
Relay Traffic, Explained
- Records why every relay-bound filter exists — its purpose, the entities it serves and the account that asked — and renders that back on a new screen.
- Fixes the multi-account subscriptions that screen exposed as never running.
- Breaks the resource ledger down by cause, so it reports why relay data was spent, not just how much.
- Stops the automatic "High resource usage detected" dialog on app open. The ledger keeps recording and Settings still shows the report.
Chats, Groups and Communities
- Mutes a public chat from a long press in Messages or from the channel menu.
- Deletes (kind 9008) and archives NIP-29 channels, with the Buzz community UI to match.
- Keeps a channel invite's replies, reactions and zaps inside the relay that sent the invite, instead of broadcasting them to your outbox.
- Derives Buzz channel invites from cached membership notices, so they stop appearing and disappearing.
- Redesigns channel invite cards as feed rows, with the person who added you as the row's author.
- Shows the hosting relay's name chip on relay group message headers.
- Splits the Concord Control Plane's stream key so a staff-held
control_rootwrite-gates it (CORD-02 §2). - Closes the Concord CORD-05/06 invite lifecycle: an Invite List, a re-mint on Refounding, and revocation.
- Stops pinning Concord entities whose chain crosses a Refounding, which was discarding their newer state on every refold.
- Closes seven Concord soft-ban holes — a banned member kept
control_root, half the Control Plane never read the banlist, and the invite button still worked.
Everything Else
- Makes the left drawer configurable, so entries you don't use can be hidden.
- Adds ngit-specific search to the Git Repositories screen.
- Supports IPv6 overlay relays (Yggdrasil) with RFC 5952 canonical addresses, fixing one relay counting as two and Tor-proxying an unreachable overlay.
- Adds a Nostr badge watermark to the notification icons, reshapes the mention icon, and adds dedicated reply and mark-as-read action icons.
- Runs verified NIP-5D artifacts in an opaque
srcdocsandbox behind a first-head CSP, and advertises only the NAP domains actually implemented.
Performance
- Scans NIP-19 entities, hashtags and legacy
#[n]references without ICU. On Android,Regex.matchAtcopied the whole note content into native memory per candidate, which grew a cold start to ~1.9 GB and got the app killed. - Scans note content by literal instead of restarting the regex engine at every position in every note.
- AOT-compiles the relay ingest path with a baseline profile. Release cold-start ingest was spending 36× more CPU interpreting bytecode than verifying signatures.
- Demotes the ~650 relay and ingest worker threads below the UI thread, so the connect storm cannot starve the first frames (~40% faster first paint).
- Reclaims memory under heap pressure and stops leaking sandboxed WebView Activities.
- Bounds the duplicate-frame decoder cache in both size and age.
- Stops blocking coroutine workers on synchronous OkHttp calls, which released their CPU permits and starved the dispatcher.
- Stops the outbox getting slower with every publish — it rebuilt an immutable map per send, copying every pending entry.
- Stripes the subscription-state lock per relay, ending the ANR convoy that had 37 of 52 workers spinning on one lock.
- Memoizes Concord guestbook envelope opens, so the fold stops re-decrypting the whole buffer on every arrival.
- Caches the painter on its first miss in
painterRes. - Optimizes the proof-of-work mining hot loop for the Android runtime.
- Skips the ~220 ms system call when the app locale has not actually changed.
- Confines the Blossom cache probe and server resolver to the IO dispatcher, and re-probes it when the toggle flips.
- Releases dead subscription rows, so connect and disconnect stop scanning every subscription ever created.
- Prefetches NIP-73 external-content preview URLs so those cards stop popping in mid-scroll.
- Adds fixed-size hex codecs for 32- and 64-byte values.
Improvements and Bug fixes
- Settles the keyboard inside navigation, so leaving a screen mid-animation stops
stranding
imePaddingacross the whole app. - Routes the draft-saving editors through
KeyboardAwareBackHandler, so a predictive back gesture no longer races the IME close. - Raises the keyboard again when you tap a field in an embedded tab that was already focused.
- Pads for the soft keyboard in full-screen napplet hosts on Android 15+.
- Fixes the crash when switching between two pinned web-app tabs.
- Stops drawing a blank parent card above a top-level community post.
- Fixes Cashu wallet balances reading low: proofs are now backfilled past the relay's page cap and history is paged.
- Keeps PDF previews stable — the page ratio is cached, so scrolling back no longer collapses the card and replays the grow-in animation.
- Stops rendering non-media NIP-94 files as video.
- Repairs
imetaMIME types written as a bare subtype, so those images can be shared again. - Works around a fatal media3 crash on Low-Latency HLS streams.
- Drives the "Can't reach this relay over Tor" banner from live socket state instead of a bare six-second timer.
- Stops a lone repost from being bundled into the always-on service notification, where it inherited the ongoing flag and refused to swipe away.
- Fails push registration loudly on an HTTP error, instead of caching a token for a device that will never receive anything.
- Listens for location only while foregrounded, and fixes the meter that reported 7 hours of listening against 9 seconds of foreground.
- Excludes quote characters from parsed URLs.
- Fixes the OpenGraph meta parser losing every tag after an apostrophe inside a comment or script, which broke link previews on some sites.
- Requests the follower-count provider's kind 30382 cards, so the count stops
rendering as
--. - Gives the invite roster line's member count its unit, so a bare number no longer reads as counting the avatars beside it.
- Removes the recent-poster facepile from Concord and Buzz channel rows.
- Renders every NIP-71 video subtype through the shared interface.
- Reworks the chat bubble reply swipe on lower-level pointer APIs, so it only claims the gesture once the motion is clearly horizontal.
- Turns the default log into a boot narrative instead of a firehose.
- Converts the drawer's hidden-count to a plural, fills the untranslated backlog for Czech, German, Swedish and Brazilian Portuguese, restores placeholders dropped from German and Polish plurals, and drops an unused plural.
Desktop
- Enriches the DM composer and message list: emoji picker with custom emoji, @mentions, reply-quoting with jump-to-original, Nostr-native GIF search, rich message rendering, per-message image quality, and encrypted file uploads.
- Redesigns Settings as a searchable accordion of labeled cards, with expand/collapse-all and a filter over titles and keywords.
- Brings the profile screen to parity: banner, rich-text bio, a CLINK offer field, six new tabs (Followers, Following, Relays, Bookmarks, Yours, Zaps received) and header actions.
- Adds a guided "save your keys" step on first run and a key backup in Settings. Android gets a soft nudge after signup.
- Loads metadata and reactions only for what is on screen, through the shared
finders in
commons, and unsubscribes when it leaves. - Enables the master notification switch when the OS permission is already granted.
- Publishes Windows arm64 and Linux arm64 desktop builds.
Cli
- Gives
amythe Concord key lifecycle it was missing: accept a promotion, follow a Refounding, perform one, and recover when left out of it. - Publishes Windows and Linux arm64 assets for
amyandgeode. - Reports "no relays" only when there really were none, and pins the buzz wrapper copies against the argument surface they call.
Quartz
- Adds Trusted Lists (kinds 30392–30395), the aggregate counterpart to NIP-85 Trusted Assertions, and indexes their labels for NIP-50 search.
- Fixes a
SharedKeyCachecollision that could return one peer's shared secret for another peer's message, and compares MACs in constant time. - Measures NIP-66 relay health from traffic the client already makes, streams probe verdicts as relays answer, checks read and write separately, lets a monitor publish what it learned without dialling, and merges verdicts into the record they replace instead of overwriting it.
- Measures
rtt-openas the transport handshake, not the time the call spent queued in the dispatcher. - Records sync coverage per kind rather than one interval per filter, keys its
persistence with a typed band, closes a drained leg, and terminates a paged walk
against a relay that ignores
until. - Strikes a host out and tracks its unreachability with publish-safe semantics, so a dead host stops being retried at the same rate as a live one.
- Sizes negentropy reconcile windows from the caller's own index, states the relay's cap, and lets a caller decline an id before its body crosses the wire.
- Normalizes every accessory timeout to an idle window, drops the
maxTotalMsceiling that cut healthy fetches, and stopsfetchAllPagescropping a streaming page. - Stops COUNT inheriting the REQ page size, which capped a count at 500.
- Suspends the incoming-message chain down to
SubscriptionListener.onEvent, so a consumer that cannot keep up no longer blocks every shared worker. - Compares every filter in
FiltersChanged, not just the first. - Fixes an
InProcessWebSocketrace that delivered a connect-time AUTH challenge beforeonOpen. - Adds
StoreQueryContext, carrying the NIP-42-authenticated caller identity into observer-relative stores. - Adds a NIP-50 search grammar (quoted phrases, negation) with weighted field extraction, and shares the store-semantics rules across implementations.
- Parses metadata leniently everywhere, and recovers blank, single-element and malformed kind-0 content instead of dropping the profile.
- Parses
ServiceTypewithout splitting on a separator that may not be there. - Declares pointer hints on Report, ChatMessage, Classifieds and ChannelCreate.
- Refreshes
created_atwhile mining, so a post that takes minutes to mine does not publish stale. - Decouples the
LocalCacheandAccountgod classes into single-purpose collaborators, 3,800 lines lighter, with no behavior change.
Build & Documentation
- Adds a
:baselineprofilemodule that records a real startup journey, replacing the hand-authored profile's wildcards. - Notarizes the macOS DMG and verifies it, adds
libegl1to the arm64.debdependencies, and moves the Homebrew and Winget bumps onto a maintainer machine. - Shrinks the mirror-sync throughput corpus on CI, which had been timing out the
test-geodejob for weeks. - Confines the QUIC stream drainer to the producer's event loop, deflaking it under parallel test load.
- Hardens
workflow-ship.shand pins it with a regression harness. - Adds three store-implementer skills: event store semantics, NIP-85 trusted assertions and searchable events.
- Bumps 30+ dependencies plus Gradle, Compose, Firebase, Media3, Ktor and OkHttp.
Contributors
- nostr:nprofile1qqsyvrp9u6p0mfur9dfdru3d853tx9mdjuhkphxuxgfwmryja7zsvhqpzamhxue69uhhv6t5daezumn0wd68yvfwvdhk6tcpzpmhxue69uhkummnw3ezumt0d5hszythwden5te0dehhxarj9emkjmn99uwfvhl6
- nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx
- nostr:nprofile1qqs9vyevafl4f7rqluqykt500e9nj5ase8eh5k423rgwtfw6qdjhd4spz4mhxue69uhhyetvv9ujuerpd46hxtnfduhszrnhwden5te0dehhxtnvdakz7qghwaehxw309aex2mrp0yh8qunfd4skctnwv46z7fr94k8
- nostr:nprofile1qqswum4p82uluhz2dr40nvdrflspffntgqghc58w9fs57nx6jkdkuaqpzamhxue69uhhyetvv9ujuct60fsk6mewdejhgtcpr9mhxue69uhhyetvv9ujuur0wd6x2u3wwpkxzcm99uq3vamnwvaz7tmgd9ehgtnwdaehgu3wd3skuep09tugna
- nostr:nprofile1qqswwud0pvzu362lehm0av6sq4zd97cue5uy0z8f7jgtk0hz368dvmcpzamhxue69uhhyetvv9ujuurjd9kkzmpwdejhgtcpr4mhxue69uhkcatwvd5xymmc9eekzmnywa5kx6pwveshymf0qy88wumn8ghj7mn0wvhxcmmv9u62vnak
- nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgpzemhxue69uhhyetvv9ujuerfw36x7tnsw43z7qgcwaehxw309aex2mrp0yhxgun9v9kkjarg9e6x7tcpzamhxue69uhhyetvv9ujuurjd9kkzmpwdejhgtcadg58a
- nostr:nprofile1qqsyxxz7mm9kwkyjsf935da90ulyqlaautk6wgq68q5m3n6t5lzmfuqpz9mhxue69uhkummnw3ezuamfdejj7qg4waehxw309aex2mrp0yhxgctdw4eju6t09uqsuamnwvaz7tmwdaejumr0dshsqfznmg
Translations
- Czech by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx
- Dutch by nostr:nprofile1qqs82l74z7g3x8j3avpn2wrjrwn855nyvmpxa4v5pftfvtv5lrvrc5cppemhxue69uhkummn9ekx7mp074ge6h
- German by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx
- Hindi by nostr:nprofile1qqs88dt78wgnzvaph6fcstfvsd98xc2qs8eg8tllwv2zlutu8ehec2cppemhxue69uhkummn9ekx7mp0qythwumn8ghj7un9d3shjtnswf5k6ctv9ehx2ap0qyt8wumn8ghj7un9d3shjtnyd968gmewwp6kytcmlz0lu
- Hungarian by nostr:nprofile1qqsxekg0s8kxpcrka8ccwztv2m73kz6jy0ur8f7jc04rwr5p44w5acspzamhxue69uhhyetvv9ujumn0wd68ytnzv9hxgtcppemhxue69uhkummn9ekx7mp0qyg8wumn8ghj7mn0wd68ytnddakj7c0ns2l
- Latvian by nostr:nprofile1qqs0a8c9nt88dm9c0dtx84xxeqsmwj7zdzgs739ut0q7770yd2larlgpzpmhxue69uhkummnw3ezumt0d5hszrnhwden5te0dehhxtnvdakz7qgawaehxw309ahx7um5wghxy6t5vdhkjmn9wgh8xmmrd9skctcmf88sy
- Polish by nostr:nprofile1qqsdyfz0ewdhmgp3a4r3pxvezx5r8yalrgvjn38v2ml5qrusnv7yywgpzemhxue69uhkummnw3ezucm6v9ejuurvw4ej7qg0waehxw309a3h5ctn9e6x7up0qyg8wumn8ghj7cm6v9ejuurvw4ej79s8c53
- Brazilian Portuguese by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx
- Swedish by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx
原始 JSON
{
"kind": 1,
"id": "00d306e01792e48b93638b73b57a7eb8b89622a338b1b4f529622150d46cd710",
"pubkey": "aa9047325603dacd4f8142093567973566de3b1e20a89557b728c3be4c6a844b",
"created_at": 1787417867,
"tags": [
[
"p",
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
"wss://vitor.nostr1.com/"
],
[
"p",
"ca89cb11f1c75d5b6622268ff43d2288ea8b2cb5b9aa996ff9ff704fc904b78b",
"wss://nostr.mom/"
],
[
"p",
"56132cea7f54f860ff004b2e8f7e4b3953b0c9f37a5aaa88d0e5a5da036576d6",
"wss://relay.damus.io/"
],
[
"p",
"ee6ea13ab9fe5c4a68eaf9b1a34fe014a66b40117c50ee2a614f4cda959b6e74",
"wss://relay.azzamo.net/"
],
[
"p",
"e771af0b05c8e95fcdf6feb3500544d2fb1ccd384788e9f490bb3ee28e8ed66f",
"wss://relay.primal.net/"
],
[
"p",
"0461fcbecc4c3374439932d6b8f11269ccdb7cc973ad7a50ae362db135a474dd",
"wss://relay.ditto.pub/"
],
[
"p",
"43185edecb675892824b1a37a57f3e407fbde2eda7201a3829b8cf4ba7c5b4f0",
"wss://nostr.wine/"
],
[
"p",
"757fd51791131e51eb033538721ba67a526466c26ed5940a56962d94f8d83c53",
"wss://nos.lol/"
],
[
"p",
"73b57e3b913133a1be93882d2c834a73614081f283afff73142ff17c3e6f9c2b",
"wss://nos.lol/"
],
[
"p",
"6cd90f81ec60e076e9f187096c56fd1b0b5223f833a7d2c3ea370e81ad5d4ee2",
"wss://relay.nostr.band/"
],
[
"p",
"fe9f059ace76ecb87b5663d4c6c821b74bc268910f44bc5bc1ef79e46abfd1fd",
"wss://nostr.mom/"
],
[
"p",
"d2244fcb9b7da031ed4710999911a83393bf1a1929c4ec56ff400f909b3c4239",
"wss://nostr.czas.plus/"
],
[
"t",
"Amethyst"
],
[
"t",
"amethyst"
],
[
"zapraiser",
"1000000"
],
[
"zap",
"460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c",
"wss://vitor.nostr1.com/",
"0.53"
],
[
"zap",
"ca89cb11f1c75d5b6622268ff43d2288ea8b2cb5b9aa996ff9ff704fc904b78b",
"wss://nostr.mom/",
"0.12"
],
[
"zap",
"56132cea7f54f860ff004b2e8f7e4b3953b0c9f37a5aaa88d0e5a5da036576d6",
"wss://relay.damus.io/",
"0.11"
],
[
"zap",
"ee6ea13ab9fe5c4a68eaf9b1a34fe014a66b40117c50ee2a614f4cda959b6e74",
"wss://relay.azzamo.net/",
"0.03"
],
[
"zap",
"e771af0b05c8e95fcdf6feb3500544d2fb1ccd384788e9f490bb3ee28e8ed66f",
"wss://relay.primal.net/",
"0.0367"
],
[
"zap",
"0461fcbecc4c3374439932d6b8f11269ccdb7cc973ad7a50ae362db135a474dd",
"wss://relay.ditto.pub/",
"0.03"
],
[
"zap",
"43185edecb675892824b1a37a57f3e407fbde2eda7201a3829b8cf4ba7c5b4f0",
"wss://nostr.wine/",
"0.03"
],
[
"zap",
"757fd51791131e51eb033538721ba67a526466c26ed5940a56962d94f8d83c53",
"wss://nos.lol/",
"0.03"
],
[
"zap",
"6cd90f81ec60e076e9f187096c56fd1b0b5223f833a7d2c3ea370e81ad5d4ee2",
"wss://relay.nostr.band/",
"0.03"
],
[
"zap",
"fe9f059ace76ecb87b5663d4c6c821b74bc268910f44bc5bc1ef79e46abfd1fd",
"wss://nostr.mom/",
"0.03"
],
[
"zap",
"d2244fcb9b7da031ed4710999911a83393bf1a1929c4ec56ff400f909b3c4239",
"wss://nostr.czas.plus/",
"0.0333"
],
[
"client",
"Amethyst"
]
],
"content": "#Amethyst v1.14.0: New Share Intents, Relay Login, and a Much Faster Start\n\nHighlights:\n\n- Improves **NIP-84 Highlights** — composer, feed, and share intent.\n- Redesigns **relay login (NIP-42)** and ends the per-relay prompt storm.\n- Adds Share targets to **Pictures, Videos, Shorts and Torrents** feeds.\n- Adds a screen that explains **why every relay subscription exists**.\n- Fixes the cold-start **out-of-memory kill** and cuts time to first paint.\n- Brings **Desktop** to parity on profiles, DMs, settings and key backup.\n- Adds **Trusted Lists** (kinds 30392–30395) to Quartz.\n\n## New Features\n\n### Highlights (NIP-84)\n\n- Adds a Highlight composer, with an annotation field, a passage editor, and a\n source reference that can be a Nostr event or a web URL.\n- Adds a Highlights feed, filterable by authors, follows, hashtags and geohashes.\n- Accepts shared text from any app as a new highlight.\n\n### Feeds and Composing\n\n- Adds four home feed content types: Pictures (NIP-68), Videos and Shorts\n (NIP-71), and Torrents (NIP-35), each with its own toggle.\n- Adds \"New Picture\", \"New Short\" and \"New Video\" share targets, so media shared\n into Amethyst opens the matching composer instead of a text note with a link.\n- Adds a bulk audience picker to the short-note composer: search people lists and\n follow packs, review the members, then add them all at once.\n- Adds a poll results page with per-option vote counts and a filterable voter\n list, replacing the feed card's four-avatar preview.\n- Shows rich previews for comments scoped to external content (NIP-73), both in\n the \"replying to\" line and as the thread's title.\n- Offers a \"Copy Original / Copy Translated\" chooser when copying a note that has\n been translated.\n- Opens the edit screen when a draft reply is tapped in a thread.\n\n### Relay Login (NIP-42)\n\n- Redesigns the relay login permissions screen. Explicit exceptions, relays\n blocked by your block list, and recent logins are now three separate sections.\n- Starts new accounts on \"always log in\" instead of deciding per relay.\n- Remembers a login for the rest of the session when you answer without ticking\n \"remember\", so a reconnect stops asking again.\n- Honors \"always log in\" for relays your own account does not publish to.\n- Makes the \"reading someone I follow\" toggle reachable — it sat behind a\n first-party gate that could never be true.\n- Counts NIP-29 groups and Concord communities as rooms you joined, so their\n host relays authenticate under \"my relays and venues\".\n- Waits for an auth challenge to resolve rather than letting the fetch time out.\n\n### Relay Traffic, Explained\n\n- Records why every relay-bound filter exists — its purpose, the entities it\n serves and the account that asked — and renders that back on a new screen.\n- Fixes the multi-account subscriptions that screen exposed as never running.\n- Breaks the resource ledger down by cause, so it reports *why* relay data was\n spent, not just how much.\n- Stops the automatic \"High resource usage detected\" dialog on app open. The\n ledger keeps recording and Settings still shows the report.\n\n### Chats, Groups and Communities\n\n- Mutes a public chat from a long press in Messages or from the channel menu.\n- Deletes (kind 9008) and archives NIP-29 channels, with the Buzz community UI to\n match.\n- Keeps a channel invite's replies, reactions and zaps inside the relay that sent\n the invite, instead of broadcasting them to your outbox.\n- Derives Buzz channel invites from cached membership notices, so they stop\n appearing and disappearing.\n- Redesigns channel invite cards as feed rows, with the person who added you as\n the row's author.\n- Shows the hosting relay's name chip on relay group message headers.\n- Splits the Concord Control Plane's stream key so a staff-held `control_root`\n write-gates it (CORD-02 §2).\n- Closes the Concord CORD-05/06 invite lifecycle: an Invite List, a re-mint on\n Refounding, and revocation.\n- Stops pinning Concord entities whose chain crosses a Refounding, which was\n discarding their newer state on every refold.\n- Closes seven Concord soft-ban holes — a banned member kept `control_root`, half\n the Control Plane never read the banlist, and the invite button still worked.\n\n### Everything Else\n\n- Makes the left drawer configurable, so entries you don't use can be hidden.\n- Adds ngit-specific search to the Git Repositories screen.\n- Supports IPv6 overlay relays (Yggdrasil) with RFC 5952 canonical addresses,\n fixing one relay counting as two and Tor-proxying an unreachable overlay.\n- Adds a Nostr badge watermark to the notification icons, reshapes the mention\n icon, and adds dedicated reply and mark-as-read action icons.\n- Runs verified NIP-5D artifacts in an opaque `srcdoc` sandbox behind a first-head\n CSP, and advertises only the NAP domains actually implemented.\n\n## Performance\n\n- Scans NIP-19 entities, hashtags and legacy `#[n]` references without ICU. On\n Android, `Regex.matchAt` copied the whole note content into native memory per\n candidate, which grew a cold start to ~1.9 GB and got the app killed.\n- Scans note content by literal instead of restarting the regex engine at every\n position in every note.\n- AOT-compiles the relay ingest path with a baseline profile. Release cold-start\n ingest was spending 36× more CPU interpreting bytecode than verifying\n signatures.\n- Demotes the ~650 relay and ingest worker threads below the UI thread, so the\n connect storm cannot starve the first frames (~40% faster first paint).\n- Reclaims memory under heap pressure and stops leaking sandboxed WebView\n Activities.\n- Bounds the duplicate-frame decoder cache in both size and age.\n- Stops blocking coroutine workers on synchronous OkHttp calls, which released\n their CPU permits and starved the dispatcher.\n- Stops the outbox getting slower with every publish — it rebuilt an immutable map\n per send, copying every pending entry.\n- Stripes the subscription-state lock per relay, ending the ANR convoy that had\n 37 of 52 workers spinning on one lock.\n- Memoizes Concord guestbook envelope opens, so the fold stops re-decrypting the\n whole buffer on every arrival.\n- Caches the painter on its first miss in `painterRes`.\n- Optimizes the proof-of-work mining hot loop for the Android runtime.\n- Skips the ~220 ms system call when the app locale has not actually changed.\n- Confines the Blossom cache probe and server resolver to the IO dispatcher, and\n re-probes it when the toggle flips.\n- Releases dead subscription rows, so connect and disconnect stop scanning every\n subscription ever created.\n- Prefetches NIP-73 external-content preview URLs so those cards stop popping in\n mid-scroll.\n- Adds fixed-size hex codecs for 32- and 64-byte values.\n\n## Improvements and Bug fixes\n\n- Settles the keyboard inside navigation, so leaving a screen mid-animation stops\n stranding `imePadding` across the whole app.\n- Routes the draft-saving editors through `KeyboardAwareBackHandler`, so a\n predictive back gesture no longer races the IME close.\n- Raises the keyboard again when you tap a field in an embedded tab that was\n already focused.\n- Pads for the soft keyboard in full-screen napplet hosts on Android 15+.\n- Fixes the crash when switching between two pinned web-app tabs.\n- Stops drawing a blank parent card above a top-level community post.\n- Fixes Cashu wallet balances reading low: proofs are now backfilled past the\n relay's page cap and history is paged.\n- Keeps PDF previews stable — the page ratio is cached, so scrolling back no\n longer collapses the card and replays the grow-in animation.\n- Stops rendering non-media NIP-94 files as video.\n- Repairs `imeta` MIME types written as a bare subtype, so those images can be\n shared again.\n- Works around a fatal media3 crash on Low-Latency HLS streams.\n- Drives the \"Can't reach this relay over Tor\" banner from live socket state\n instead of a bare six-second timer.\n- Stops a lone repost from being bundled into the always-on service notification,\n where it inherited the ongoing flag and refused to swipe away.\n- Fails push registration loudly on an HTTP error, instead of caching a token for\n a device that will never receive anything.\n- Listens for location only while foregrounded, and fixes the meter that reported\n 7 hours of listening against 9 seconds of foreground.\n- Excludes quote characters from parsed URLs.\n- Fixes the OpenGraph meta parser losing every tag after an apostrophe inside a\n comment or script, which broke link previews on some sites.\n- Requests the follower-count provider's kind 30382 cards, so the count stops\n rendering as `--`.\n- Gives the invite roster line's member count its unit, so a bare number no longer\n reads as counting the avatars beside it.\n- Removes the recent-poster facepile from Concord and Buzz channel rows.\n- Renders every NIP-71 video subtype through the shared interface.\n- Reworks the chat bubble reply swipe on lower-level pointer APIs, so it only\n claims the gesture once the motion is clearly horizontal.\n- Turns the default log into a boot narrative instead of a firehose.\n- Converts the drawer's hidden-count to a plural, fills the untranslated backlog\n for Czech, German, Swedish and Brazilian Portuguese, restores placeholders\n dropped from German and Polish plurals, and drops an unused plural.\n\n## Desktop\n\n- Enriches the DM composer and message list: emoji picker with custom emoji,\n @mentions, reply-quoting with jump-to-original, Nostr-native GIF search, rich\n message rendering, per-message image quality, and encrypted file uploads.\n- Redesigns Settings as a searchable accordion of labeled cards, with\n expand/collapse-all and a filter over titles and keywords.\n- Brings the profile screen to parity: banner, rich-text bio, a CLINK offer field,\n six new tabs (Followers, Following, Relays, Bookmarks, Yours, Zaps received) and\n header actions.\n- Adds a guided \"save your keys\" step on first run and a key backup in Settings.\n Android gets a soft nudge after signup.\n- Loads metadata and reactions only for what is on screen, through the shared\n finders in `commons`, and unsubscribes when it leaves.\n- Enables the master notification switch when the OS permission is already\n granted.\n- Publishes Windows arm64 and Linux arm64 desktop builds.\n\n## Cli\n\n- Gives `amy` the Concord key lifecycle it was missing: accept a promotion, follow\n a Refounding, perform one, and recover when left out of it.\n- Publishes Windows and Linux arm64 assets for `amy` and `geode`.\n- Reports \"no relays\" only when there really were none, and pins the buzz wrapper\n copies against the argument surface they call.\n\n## Quartz\n\n- Adds Trusted Lists (kinds 30392–30395), the aggregate counterpart to NIP-85\n Trusted Assertions, and indexes their labels for NIP-50 search.\n- Fixes a `SharedKeyCache` collision that could return one peer's shared secret\n for another peer's message, and compares MACs in constant time.\n- Measures NIP-66 relay health from traffic the client already makes, streams\n probe verdicts as relays answer, checks read and write separately, lets a\n monitor publish what it learned without dialling, and merges verdicts into the\n record they replace instead of overwriting it.\n- Measures `rtt-open` as the transport handshake, not the time the call spent\n queued in the dispatcher.\n- Records sync coverage per kind rather than one interval per filter, keys its\n persistence with a typed band, closes a drained leg, and terminates a paged walk\n against a relay that ignores `until`.\n- Strikes a host out and tracks its unreachability with publish-safe semantics,\n so a dead host stops being retried at the same rate as a live one.\n- Sizes negentropy reconcile windows from the caller's own index, states the\n relay's cap, and lets a caller decline an id before its body crosses the wire.\n- Normalizes every accessory timeout to an idle window, drops the `maxTotalMs`\n ceiling that cut healthy fetches, and stops `fetchAllPages` cropping a streaming\n page.\n- Stops COUNT inheriting the REQ page size, which capped a count at 500.\n- Suspends the incoming-message chain down to `SubscriptionListener.onEvent`, so a\n consumer that cannot keep up no longer blocks every shared worker.\n- Compares every filter in `FiltersChanged`, not just the first.\n- Fixes an `InProcessWebSocket` race that delivered a connect-time AUTH challenge\n before `onOpen`.\n- Adds `StoreQueryContext`, carrying the NIP-42-authenticated caller identity into\n observer-relative stores.\n- Adds a NIP-50 search grammar (quoted phrases, negation) with weighted field\n extraction, and shares the store-semantics rules across implementations.\n- Parses metadata leniently everywhere, and recovers blank, single-element and\n malformed kind-0 content instead of dropping the profile.\n- Parses `ServiceType` without splitting on a separator that may not be there.\n- Declares pointer hints on Report, ChatMessage, Classifieds and ChannelCreate.\n- Refreshes `created_at` while mining, so a post that takes minutes to mine does\n not publish stale.\n- Decouples the `LocalCache` and `Account` god classes into single-purpose\n collaborators, 3,800 lines lighter, with no behavior change.\n\n## Build \u0026 Documentation\n\n- Adds a `:baselineprofile` module that records a real startup journey, replacing\n the hand-authored profile's wildcards.\n- Notarizes the macOS DMG and verifies it, adds `libegl1` to the arm64 `.deb`\n dependencies, and moves the Homebrew and Winget bumps onto a maintainer machine.\n- Shrinks the mirror-sync throughput corpus on CI, which had been timing out the\n `test-geode` job for weeks.\n- Confines the QUIC stream drainer to the producer's event loop, deflaking it\n under parallel test load.\n- Hardens `workflow-ship.sh` and pins it with a regression harness.\n- Adds three store-implementer skills: event store semantics, NIP-85 trusted\n assertions and searchable events.\n- Bumps 30+ dependencies plus Gradle, Compose, Firebase, Media3, Ktor and OkHttp.\n\n## Contributors\n\n- nostr:nprofile1qqsyvrp9u6p0mfur9dfdru3d853tx9mdjuhkphxuxgfwmryja7zsvhqpzamhxue69uhhv6t5daezumn0wd68yvfwvdhk6tcpzpmhxue69uhkummnw3ezumt0d5hszythwden5te0dehhxarj9emkjmn99uwfvhl6\n- nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx\n- nostr:nprofile1qqs9vyevafl4f7rqluqykt500e9nj5ase8eh5k423rgwtfw6qdjhd4spz4mhxue69uhhyetvv9ujuerpd46hxtnfduhszrnhwden5te0dehhxtnvdakz7qghwaehxw309aex2mrp0yh8qunfd4skctnwv46z7fr94k8\n- nostr:nprofile1qqswum4p82uluhz2dr40nvdrflspffntgqghc58w9fs57nx6jkdkuaqpzamhxue69uhhyetvv9ujuct60fsk6mewdejhgtcpr9mhxue69uhhyetvv9ujuur0wd6x2u3wwpkxzcm99uq3vamnwvaz7tmgd9ehgtnwdaehgu3wd3skuep09tugna\n- nostr:nprofile1qqswwud0pvzu362lehm0av6sq4zd97cue5uy0z8f7jgtk0hz368dvmcpzamhxue69uhhyetvv9ujuurjd9kkzmpwdejhgtcpr4mhxue69uhkcatwvd5xymmc9eekzmnywa5kx6pwveshymf0qy88wumn8ghj7mn0wvhxcmmv9u62vnak\n- nostr:nprofile1qqsqgc0uhmxycvm5gwvn944c7yfxnnxm0nyh8tt62zhrvtd3xkj8fhgpzemhxue69uhhyetvv9ujuerfw36x7tnsw43z7qgcwaehxw309aex2mrp0yhxgun9v9kkjarg9e6x7tcpzamhxue69uhhyetvv9ujuurjd9kkzmpwdejhgtcadg58a\n- nostr:nprofile1qqsyxxz7mm9kwkyjsf935da90ulyqlaautk6wgq68q5m3n6t5lzmfuqpz9mhxue69uhkummnw3ezuamfdejj7qg4waehxw309aex2mrp0yhxgctdw4eju6t09uqsuamnwvaz7tmwdaejumr0dshsqfznmg\n\n## Translations\n\n- Czech by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx \n- Dutch by nostr:nprofile1qqs82l74z7g3x8j3avpn2wrjrwn855nyvmpxa4v5pftfvtv5lrvrc5cppemhxue69uhkummn9ekx7mp074ge6h\n- German by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx \n- Hindi by nostr:nprofile1qqs88dt78wgnzvaph6fcstfvsd98xc2qs8eg8tllwv2zlutu8ehec2cppemhxue69uhkummn9ekx7mp0qythwumn8ghj7un9d3shjtnswf5k6ctv9ehx2ap0qyt8wumn8ghj7un9d3shjtnyd968gmewwp6kytcmlz0lu \n- Hungarian by nostr:nprofile1qqsxekg0s8kxpcrka8ccwztv2m73kz6jy0ur8f7jc04rwr5p44w5acspzamhxue69uhhyetvv9ujumn0wd68ytnzv9hxgtcppemhxue69uhkummn9ekx7mp0qyg8wumn8ghj7mn0wd68ytnddakj7c0ns2l \n- Latvian by nostr:nprofile1qqs0a8c9nt88dm9c0dtx84xxeqsmwj7zdzgs739ut0q7770yd2larlgpzpmhxue69uhkummnw3ezumt0d5hszrnhwden5te0dehhxtnvdakz7qgawaehxw309ahx7um5wghxy6t5vdhkjmn9wgh8xmmrd9skctcmf88sy\n- Polish by nostr:nprofile1qqsdyfz0ewdhmgp3a4r3pxvezx5r8yalrgvjn38v2ml5qrusnv7yywgpzemhxue69uhkummnw3ezucm6v9ejuurvw4ej7qg0waehxw309a3h5ctn9e6x7up0qyg8wumn8ghj7cm6v9ejuurvw4ej79s8c53 \n- Brazilian Portuguese by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx \n- Swedish by nostr:nprofile1qqsv4zwtz8cuwh2mvc3zdrl5853g365t9j6mn25edlul7uz0eyzt0zcpzpmhxue69uhkummnw3ezumt0d5hszxnhwden5te0wf5kymewv46jumn0wd68y6tp9eshqup0qyd8wumn8ghj7um9dejxjapwdehhxenvv9ex2tnrdakj7nrm3sx",
"sig": "eb8855915dba0ac3653587c39a71e379f0adc034395c52f66728ca897aaa9f1170add713d0b3b2695a3702dd4a318e209a546ffbcb387253ac90ae120677a19f"
}