Keep Android 1.3.2 revokes earlier bunker grants and scopes them per account. It also drops a compromised bundled CA root and makes storage fail closed. Nostr WoT extension 0.8.14 adds experimental phone signing over WiFi or Web Bluetooth, and local keys stay unused if the phone disconnects. Zapstore 1.1.3 carries app comments and zaps across a catalog signing key change. Catalog links carry over too. nostr-pubsub 0.5.19 limits identified receiver EVENT and INV exports to explicit public authors, while IP and timing remain visible. A merged Napplet change checks the event ID and signature before headless browser execution. It also checks the exact raw HTML hash first. The deep dive contrasts NIP-37 (topic) encrypted drafts with NIP-48 (topic) signed bridged events.

Top Stories

diVine

diVine is the short-video Nostr client. diVine published stable release 1.0.25 on 19 October, built from its tagged source. It adds motion tracking along with masks and stabilization. Recording backups and hashtag follows are also new. Users can dismiss a chat while keeping its history, and sound reuse requests ask for creator consent. Direct message catch-up is more reliable, with page caps and a Following cursor. Legacy NIP-04 copies now reuse events that are already signed, with bounded retries. Sender copies of reactions reach advertised inbox relays. Account-switch list isolation is still experimental. Related merged work: account-key cleanup, legacy DM relay recovery, sender reaction inbox copies, moderation message classification, Following page continuity, bounded legacy DM copies, concurrent relay sends, same-second Following cursor, durable DM catch-up, hashtag follows, conversation dismissal, sound reuse consent, iOS recording backup, Android recording backup, motion tracking, older DM pagination, experimental account list isolation.

Release status for source changes merged after 1.0.25 is unconfirmed. Inbox history evidence requires a live inbox list before history is marked complete. With explicit reaction retry, retry budgets stay available while the user’s own relays are down. A NOTICE redaction change strips IP addresses from relay NOTICE messages, while raw CLOSED reasons are still shown as received. Mark-as-read feedback now reports how many messages matched and whether a batch was partial. Read state still syncs across the user’s devices through self-addressed messages, and read receipts visible to the other person remain unimplemented. Follow load coalescing removes duplicate contact-list queries and subscriptions. When the user switches accounts, the old account’s scheduled-post relay step is cancelled, while other requests, logs and repository state from that account can persist. Rooms remains a public test proof of concept with its release flag off.

Other merged source work adds on-device Smart people ordering, which ranks people by cached follows, accepted one-to-one conversations and activity. Smart is the default for the user’s own follow lists, with chronological order still available. Exact search matches rank first, and moving someone up takes more than an inbound follow alone. The follower cache is kept per account, with incremental refreshes at most once per 15 minutes and a full refresh weekly. When a read hits its cap before finishing, older rows are kept. Rankings and local message content stay off relays. A private-key search guard stops searches and lookups containing nsec1 or ncryptsec1 strings before any request is sent. Matching is case-insensitive and also catches keys with a nostr prefix or zero-width characters, and the warning omits the key itself. Because the guard matches on the prefix, incomplete or mistyped keys are caught too. Its coverage is limited to search: bare 64-character hex passes through by design, and published captions and comments go out unfiltered, so secrets can still leak through those paths. Copying or sharing a verified Divine username now uses its HTTPS username URL, falling back to the npub when the name is unverified or unavailable, with the cache keyed to the exact claim. This change is source-only and absent from app-store releases.

The handle-ownership check for username search would confirm who owns a Divine handle by asking Divine’s name server. Today the app trusts the NIP-05 claim on a profile or the search index. The proposal covers root _@user.divine.video handles and would put the real owner first, even when another account uses the same display name. The lookup would run in parallel with search and stop after 3 seconds. If it fails or the handle shows as free, pending or reserved, the old results would stay as they are, and blocks would still apply. The cost would be one extra request for each debounced username search. This is not general NIP-05 validation.

The received video DM handling proposal would download and decrypt each received video once, show a real frame from it and reuse the copy. Videos would only load automatically from people you follow or chats you have replied in. Any reply counts, even one declining the conversation. Auto-loading tells the media host when you view the chat. Videos from strangers you have never replied to would load only when you tap them. Blocking or muting a sender would stop downloading and decoding. Automatic downloads would run one at a time, with a 25 MiB and one-minute limit. They would be cancelled when the video scrolls offscreen, unless playback has started. Tap-to-load would keep the existing 100 MB limit. HTTPS redirects would be capped at five, and their bytes would count toward the total. The proposal does not hide metadata in general.

Amber

Amber merged a set of signer hardening changes in source on 16 October. Its require-unlocked-device protection is opt-in and defaults to false. When a user enables it, new checks require an unlocked device before the cached private key is used. Background signing follows the configured device-lock policy. Other merged work covers bunker request routing, backup seed validation, consent before relay rating, secured WebDAV handling and isolation of timed permissions (bunker routing, opt-in device lock checks, proxied WebDAV transport, relay-rating consent, backup seed restoration, timed permission isolation).

Amethyst

Amethyst is the Android and desktop Nostr social client. Merged source since the 1.19.0 release hardens how the client handles untrusted input. Embed decompression now has a size limit, Nostr Wallet Connect responses are verified, addressable events sort correctly, and private zaps check their target. Cancelling work no longer corrupts group recovery. A resumed bulk export now commits its cursor only after delivery, and fixes to outbox and reconnect handling stop relay events from being lost. NIP-34 repository creation now reaches GRASP relays and keeps unknown tags. This work landed in account-scoped deck and group resets, browser data clearing, malformed-host crash prevention, remote-signer Tor routing, large Cyberspace objects, signed desktop updates, list-definition cards, Open Markets parsing, bulk ingest and resumable exports, relay and event-handling repairs and in-flight relay retention.

On desktop, signed updates are checked against the expected author and file hash, and the GitHub fallback only links to downloads. OpenMarkets cards can now tell apart encrypted Shopstr kinds that share kind numbers. Other additions include list-definition cards, GIF support in drawings, shape-aware proof of work, separate storage for each desktop instance, and fixes for video startup on Linux. Large Cyberspace objects that are valid no longer hit an outdated geometry limit. All of this is merged source with no new release yet: see Open Markets cards, interrupted paged fetches, subscription replay and outbox delivery, relay-client API repairs, input validation and cancellation, additional event cards, NIP-34 repository creation, drawing replay GIFs, desktop process isolation, proof-of-work hashing and Linux video startup.

Relay delivery got stricter after that. Treating ordinary OK replies as final means that once a relay accepts or refuses an event, the client stops holding it and skips resending it on reconnect. Auth-required and rate-limited replies still get a bounded number of retries. Counted connection leases build on that, with callers now explicitly keeping and releasing sockets. An unanswerable auth-required refusal is final, and the client waits through at most 10 auth-required replies. Publishing on a socket that is already open starts right away. A replay race while a socket is still connecting can send an event twice, and the client ignores the duplicate OK.

Remote-signer fixes change several parts of the NIP-46 flow. An auth_url challenge now waits for the user to open it from an explicit popup. Client and signer coordinate switch_relays, with a grace period for replies still arriving on the old relays. Logout sends a best-effort notice for up to 15 seconds, and local key removal goes ahead regardless. The command-line tool identifies the account through get_public_key, separate from the transport key. It fails if that lookup fails. Logging in through a signer advertised in NIP-05 requires the returned account to match the resolved identity, and read-only fallback is unavailable when no signer is found. The pairing acknowledgment goes out once the client is listening, so the client receives the first request.

A new in-app developer inspector for Android and desktop recomputes event IDs and verifies signatures. It converts NIP-19 identifiers and looks up kinds. Users can also find which relays hold an event and send raw REQ and COUNT messages as well as raw EVENT messages. The inspector answers AUTH only after the user confirms the relay and challenge. The account also needs the user’s confirmation first. Its crawls respect blocked relays and Tor routing and stay outside the account cache. Manual testing covered the desktop version only, so the Android build and the AUTH path remain untested. Fallback handling for unknown kinds caches unsupported non-ephemeral events by ID or replaceable coordinate and shows them as a generic card. Cached JSON is capped at 32 KB and a nesting depth of 32. It also holds at most 50 tags, and notifications exclude unknown kinds. The card is a generic display, separate from full support for those kinds. Separately, a native crypto replacement moves Apple and Linux native builds to in-tree Kotlin code derived from BearSSL. That code covers AES and GHASH as well as long-input SHA and HMAC. Android and JVM builds keep using JCA. The change migrates code; constant-time behavior and end-to-end security would each need separate verification.

Concord now deduplicates and rekeys its community list by authenticated material ID, fixing a crash from duplicate keys in the hub and a tombstone/leave mismatch that arose when older rescue entries disagreed. Stricter coordinator-key validation and cordn.net links require full 32-byte keys, so the app stays up when given partial input. The same change parses cordn.net chat links and Android deep links while ignoring preview metadata; on Android 12 and later, users enable the deep links manually. A notification-service startup fix keeps the service from restarting Android’s 10-second foreground deadline when it is already in the foreground. While the UI is in front, it starts the service with startService and falls back to a foreground start if the platform refuses. The cold-start crash fix was confirmed in a single test on one SM-T220 device, so behavior on other devices is still unverified. Like the rest of this entry, these changes are merged source awaiting a release.

Amethyst’s MLS engine has been split out of Quartz into a standalone library, mls-kmp. It is a pure Kotlin Multiplatform implementation of RFC 9420 (cipher suite 0x0001) with Marmot policy hooks and Welcome interoperability tests against OpenMLS/MDK and ts-mls. The library contains no Nostr logic, which stays in Quartz’s Marmot binding. It now reuses a newly extracted crypto-kmp primitives library.

MDK

MDK, the runtime for Marmot encrypted groups, adds retained files and host handoff leases to its streaming-media source. It replaces an arbitrary 2 GiB cap with full-disk blocking and moves legacy migration and storage management to the background. A durable retention cursor protects unread messages, and a state-only reorg keeps messages and output intact. Deferred epoch stalls now wake from persisted state, and quarantine isolates broken groups. A consumed last-resort KeyPackage keeps its init_key private material for up to 24 hours after replacement, bounded by not_after. A neutral host deployment configuration replaces the implicit application preset.

Merged avatar media-store conversion sends avatar and group-image fetch, read and background migration through media-store cache files. Verified identical files are shared, so only new files use free space. If a file is missing or corrupt, it is cleared for every owner that shares it and fetched again. An owner that changes during a read follows the current asset. When the disk is full or free space is unknown, migration waits and does not delete anything to make room. cache_bytes is exposed in the bindings. This builds on avatar file-cache storage, which adds deduplication, a 128 MiB budget for unique files, reference counting and encrypted-key cleanup, and stayed backwards compatible until the runtime conversion. Pre-ship migration 0114 copies at most 32 MiB of database avatar bytes, smallest first. Owners beyond that cap are evicted from the cache and fetched again later; no messages or history are deleted. This limits the extra disk needed when an account opens. The 21 October nightly predates all three changes, so none of them is in it.

Merged epoch-gap fallback serves relays lacking NIP-77 by paging events older than the newest 256. Its bounded, durable frontiers survive cuts and capacity waits, so a missing older commit can be found and newer messages decrypted. Merged catch-up scheduling runs up to four slots that refill immediately. It persists complete pending plans and retries refused or skipped goals, while eight NIP-77 permits per endpoint are shared across the SDK pool with cancellation and deadlines. Operational work excludes windows past retention, and history completeness remains unproven.

Merged QUIC broker TLS verification uses bundled Mozilla roots on all platforms, avoiding an Android OS-verifier JNI panic with CA-signed brokers. The trade-off is that OS-managed distrust, custom enterprise CAs and revocation checks drop out of the path, and brokers on a private CA need an explicit certificate pin. An ALPN mismatch on the production broker had previously masked the crash, so universal runtime success remains unestablished. Merged trust-bundle update moves to rustls-webpki 0.103.16 and webpki-roots 1.0.10 to address compromised emSign/eMudhra intermediates in the bundled trust, updating it for both QUIC and relays with no added ignores. Independent cryptographic and runtime exploit validation is still outstanding.

Merged source is not a release. Related tags are dated nightly or snapshot experimental bindings, and stable 0.14 is still unreleased. Supporting source: own-leaf component refresh, recipient-compatible message edits, self-authored agent edits, host-authorized conversation deletion, quarantine receive isolation, deferred quarantined projections, retained encrypted media, persisted epoch-stall recovery, wire download checkpoints, state-only reorg recovery, KeyPackage retention grace, streaming downloads, profile edit completion, staged streaming uploads, attachment handoff leases, storage management, background attachment migration, unread-message retention, bounded reconciliation, explicit neutral deployment configuration and database disk-space reclamation.

MDK has two open proposals. The first, Kind 3 follow-list editing, changes only the target p tag when a follow is added or removed. Unrelated tags and content stay intact, as do petnames and relay hints. Signing and publishing stop once a list reaches 2,048 distinct follows. That includes exactly 2,048, because a list of that size is indistinguishable from a longer one. When the current follow list is unavailable, the operation publishes nothing. The CLI runs the same edit under an account lock. Mute-list cap and onboarding paths still need separate fixes.

Ordered offline catch-up: Older recovered ciphertext is admitted before newer MLS state advances, so messages aren’t lost when they fall out of the retained ratchet window. When NIP-77 is refused it pages the original routes. It saves unresolved ranges, spill data and cursors so they survive a reopen. Admission and backoff are bounded, and completed catch-up results reach the application before the whole pass finishes. Recovered invites become a durable GroupJoined before any network I/O. The new migration 0115 exists in source only, and nothing is claimed as released.

Zeus

Zeus is the mobile Bitcoin and Lightning wallet. A set of Zeus pull requests tightens NWC payment handling. Now pay_invoice uses its own backend result, so unrelated payments or refreshes in the shared transaction store cannot decide its outcome. Pending payments reserve the invoice amount plus the available routing-fee cap against the budget, and unlisted holds last for the lifetime of the HTLC. Callers paying with ecash must supply the invoice they reviewed, so a quote replaced by a concurrent NWC or send flow cannot melt a different invoice. LNURL ecash navigation also keeps the invoice that passed verification. Authorization checks expiry against the current time, and deleting the active wallet removes its NWC connections and keys. Malformed make_invoice amounts or expiries are rejected before native conversion could crash iOS or wrap values on Android (payment status, zero-amount invoices, payment result isolation, ecash quote binding, budget fee holds, expiry and revocation, merchant QR validation).

Switching the selected embedded or NWC wallet advances a connection generation, so results from the old target cannot fill in the new one. LndHub routing fees now count toward NWC spending, although that backend still has no fee-limit support. NIP-47 list_transactions reports pending and failed payments correctly, and zero-amount invoices receive the requested amount. CLINK checks invoice amounts in millisatoshis and refuses onion relays by normalized hostname. NIP-05 onion identifiers return not-found without a clearnet lookup, which does not add Tor NIP-05 support. Scanned merchant QR codes no longer send secrets or legacy NWC strings to external resolvers (onion NIP-05 handling, CLINK relay validation, wallet target generation, CLINK invoice amounts, verified LNURL invoice, LndHub spending fees, invoice numeric bounds).

Two more unreleased source changes continue this work. Embedded LND payment-stream events are now matched by payment hash, so when an NWC service payment and a user payment overlap, each keeps its own final outcome and preimage. Listener cleanup and EOF and keysend timeout handling support the same fix, and AMP payments skip this matching on purpose. Native stream-level errors still lack a payment hash, so they reject all pending listeners together (payment-hash correlation). Zeus also moves to Alby SDK 8.1.1 and sends make_invoice amounts directly as rounded whole millisatoshis, which preserves fractional-satoshi input and meets the SDK’s stricter integer checks (SDK 8.1.1 invoice amounts).

Tagged Releases

algia

algia v0.0.137 fixes a panic that hit every CLI search. In the search context fix, the search command receives the CLI context where it previously got a nil context. That fix shipped in the algia v0.0.137 release.

Angor

Angor is the Bitcoin and Nostr crowdfunding project. Angor 0.2.37 reattaches the Nostr client’s OK and EOSE handlers when the client is rebuilt after a network change. Before this fix, a network switch could leave metadata acknowledgements and query completion unhandled, so publishing a project could time out until the app was restarted. The change is in the handler reattachment pull request.

ants

In ants, search relays now participate in exact npub and NIP-05 lookups for metadata and relay discovery, as described in the ants search relay update. Cached results are tied to the active relay configuration, and lookups that miss are retried. This change is separate from the nested search and routing work covered earlier.

Armada

Armada can now block communities by policy. Opening and joining a blocked community stay disabled until the block is lifted. Previews, badges and notifications are held back as well (community blocking release). Armada enforces the block within the app; relay copies remain. When a role is revoked, the app now rotates the private channel key, which protects future messages; copies already delivered remain. Relay proof-of-work is available as an opt-in setting and is off by default (role and PoW release).

Community search gains typed and date filters. Background backfill for channels and DMs now labels history as incomplete while it is still loading (search and backfill release). Muted words now sync across devices and remote-signer links can be copied. According to the publisher, iOS message notifications are decrypted on the device (sync and notification release).

Cordn

Cordn is the ContextVM-based MLS messenger. Cordn 0.6.0 adds encrypted polls and full-history search shown through a windowed, reactive display. Unread and mention counts use a durable ledger, and grouped reactions have jump links. Coordinator relays refresh automatically with reachability checks. Message ordering still depends on the coordinator. These are the publisher’s notes, and they do not promise unlimited history retention or tested compatibility with other clients.

CustID

CustID 0.2.0 beta adds a direct Android NIP-55 signer with a native key vault and per-app permissions, and it requires Android 14 or later (CustID 0.2.0 beta announcement). Version 0.2.1 fetches identity relay lists from write relays. It also requires manual review of any auth request that follows delivery of a private message to a recipient’s relay, and warns that approving it may reveal identity and timing (CustID 0.2.1 announcement). Cached decisions still show this warning, and timing correlation remains possible after approval. Auto-auth settings still reveal identity.

Feather

Over a long run of releases, Feather added native NIP-88 polls, with votes sent to the relays each poll advertises. It also added NIP-73 podcast sharing, comment discovery and players. Private NIP-51 interest and mute lists now go through the signer, and follow-list edits are guarded so they keep the latest list data. Account settings now sync in encrypted form. Threads and deletions load from cache first so context is kept. If a deleted note’s text is already cached, Feather shows it only locally and never fetches it again. Because several of these features use cache-first or background recovery, what appears on screen is not always freshly confirmed from relays. Feather deliberately leaves out DMs. These features are described in the release announcements.

The latest releases focus on payments and action handling. In 0.92.0, NIP-57 zap splits keep the user’s chosen total through consistent rounding, and a per-recipient payment journal recovers partial or unknown payment outcomes while preventing duplicate sends. Verified relay observations persist across restarts, and known names are cached before engagement. In 0.93.0, Feather collapses suspected duplicate replies once a non-followed author posts five distinct matching events; users can still reveal them, and cached content is kept. The collapse is a heuristic, distinct from proven bot detection. In 0.94.1, reactions, reposts, votes and payments each get their own bounded queue, so social actions keep moving during a payment backlog. Up to four independent reaction or repost changes and two zaps can run at once. Actions on the same note keep their order and signing stays serialized, with the duplicate-payment journal retained. These descriptions come from Feather’s release notes alone, without independent testing.

Smaller media, navigation and tagging updates, such as emoji hashtags in search, note links and new-post tags in 0.93.1, are covered in Feather’s release announcements (first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth, eleventh, twelfth, thirteenth).

FIPS

FIPS 0.5.3 makes Nostr advertisements and discovery resistant to forged or replayed records used for redirection or starvation. It also updates the TLS dependency used by all default Nostr relay connections to address four advisories. This maintenance release is wire-compatible; Windows migration instructions preserve the existing node identity.

Hopp

Hopp is a podcast player that remains usable anonymously. Its 0.2.0 release added optional Nostr identity through Amber, a bunker or a local key, along with episode comments, replies and likes and opt-in boost notes carrying episode context. Version 0.2.1 added invoice preimage verification. If a wallet refuses, disconnects or cancels after a payment is sent, Hopp marks the payment UNKNOWN and blocks retries through other routes. Unknown payments and fees both count against budgets, and an unknown payment stays in its own state, distinct from settled or failed. The 0.2.2 release lets you zap podcast comments publicly, privately or anonymously, copy npubs and nevents, and open Nostr profiles in an external app. Custom relays can now be added and removed, though relays requiring NIP-42 authentication are unsupported. An imported key now uses its own advertised relay list. When a show lacks its own Nostr post, comments include episode and show context so other clients can tell what they refer to.

Iris Chat

Iris Chat’s mid-October releases added private invitations, acceptance across multiple devices, settings recovery, recovery of group history and a notification policy for member mentions in muted groups. A later release adjusted labels and layout. The 2026.10.21.1 release notes describe changes to how messages, invitations and calls handle privacy. Each device now stores its own caller approval and blocking choices. The release also improves nearby routing after an account switch and group delivery to linked devices. Two people must both update to keep messaging and calling each other. Existing history carries over, while old invite links are replaced and must be shared again. The notes are silent on the underlying cryptography and on metadata anonymity. The app’s Double Ratchet messaging has yet to receive an audit, and every behavior listed here comes from the publisher’s own description, with no independent testing behind it. Source: iris-chat-rs.

KithMoot

KithMoot Android builds 0.6.87 through 0.6.96 preserve relay read/write settings and flag relays that acknowledge an event but do not return it. These builds also improve keeper recovery, send long pasted text as an encrypted shared attachment, scope Signet contacts by consent and introduce a new layout for chats, people and boards (build note, build note, build note, build note, build note, build note). In the native and web v0.1.89 release, password-protected meeting links carry the passphrase in the URL fragment. Delayed automatic replies arrived in 0.6.90 and were reverted in 0.6.92 while lost call audio and screenshare problems are investigated, leaving the delayed-reply feature reverted. Camera privacy masks and thermal behavior still lack acceptance testing on physical devices.

Kryfo

Kryfo v0.5.2 is an unaudited alpha release. It delivers messages between peers over Tor and uses Nostr as an offline mailbox. This release adds padded encrypted messages, files and albums, notes export, ending groups and UnifiedPush recovery (Kryfo release announcement). Padding hides the exact plaintext size within a size bucket, but which bucket a message falls into, its timing and its transport size are still visible. Screenshot controls cannot stop external cameras or a malicious recipient.

lief

lief’s latest release waits for the recipient’s relay to acknowledge an encrypted letter and reports the cause when a send fails. Lists are now preserved when a relay misses them, and each account keeps its own relay set. A relay acknowledgement does not show that the recipient read the letter or that the relay will keep storing it. Sticker packs and recipient search arrive in the same release.

Linky

Linky 26.10.6 adds Cashu NUT-18 payment requests. A request completes only when the full amount arrives and fails right away when offline. The release also fixes Nostr relay handling for seen receipts and profiles. The Fazole variant 26.10.3 adds cash-exchange requests, which name an amount and a Linky contact by name, address or npub. When the wallet has enough balance, the contact gets the exchange request. Otherwise they can provide cash as a pledge, and future Bitcoin payments are forwarded to that contact until it’s repaid. Progress shows in chat. Withdrawal search finds Linky profiles, and the shop’s name and photo are republished as a Nostr profile at each startup.

Mailstr

Mailstr 0.3.0 adds workspaces and custom domains. On the server, mail is routed per tenant through an SMTP socketmap domain lookup, with a NIP-05 resolver fallback and direct Nostr delivery. In the client, a DNS health check must pass before mail records are enabled. Domain ownership is verified server-side through a TXT record.

Mailstr 0.3.1, published October 21, tightens sender identity and bridge routing (changes since 0.3.0). The composer now omits receive-only npub mailboxes from its From addresses, so sending requires an account with a usable alias. A reply always goes out from the owned address that received the original message, whichever inbox is selected in the sidebar. Reply identity passes through effective sender handling. A From choice applies to its own composer. Replacing a minimized draft clears its old recipients and subject. Its old thread fields are cleared as well. Outbound bridge resolution follows the From domain set in the composer (_smtp@domain) and falls back to the hosted platform. When the user sets a bridge override explicitly, that bridge is the only one used and fallback is skipped. Retrying also clears a cached failed NIP-05 result so the lookup runs again.

Mostro

A mostro-cli fix for take-sell responses covers take-sell responses that carry an invoice while omitting the order body. The client now saves the taken order, trade keys and trade index from the order book or from a partial record, so an accepted trade keeps progressing and the next trade index is accepted.

On the daemon side, Mostro v0.20.0 implements reputation imports, revocation and republished ratings, which had not been implemented before. It also publishes a kind 38389 health event with encrypted private metrics (health event implementation, reputation import implementation). This release provides the implementation for the 0.20 health and reputation-import changes flagged on 14 October.

The other half, reputation export, is now merged in source. The optional reputation export issuer key is a dedicated key kept separate from the daemon and import keys. With the feature enabled, the daemon starts only when that key is present and valid. Eligibility requires at least 10 completed native trades, at least 5 ratings, an account free of bans and a first date on record. Only native ratings count toward eligibility, and attestations last seven days by default. The export-reputation handler issues an issuer-signed, native-only attestation tied to the transport-proven source identity and destination, and binds each attestation atomically to exactly one identity. Binding happens only after signing succeeds, and when two attestations race, the losing one is dropped. Reissuing to the same bound identity is allowed, while rebinding falls outside the current implementation. Separately, a kind 38389 payout health check fix distinguishes a single bad invoice from a node-wide failure: a failure-rate alert now needs at least two failed orders or insufficient balance. Stale payouts (over seven days), never-attempted payouts and cases with nothing in flight each get their own warning, and retryable old orders stay under watch. The change is limited to health reporting and leaves payout logic as it was. The latest confirmed release tag is v0.20.0, so none of these three changes can yet be confirmed as shipped.

The Mostro mobile app shipped version 2.1.0, a client release separate from daemon v0.20. The app keeps a restore snapshot for each node and keeps trades separate when the user switches nodes. Older trades that lack a recorded node are either assigned to one or cleared. The “order published” notification now waits until the bond locks, and the app handles bond deadlines that have passed. The signed release notes link the underlying app pull requests. These are the publisher’s descriptions, and we have not independently tested them on a device.

NoorNote

NoorNote 1.9.1 sends booking RSVPs to the event owner even when the two users share no relays, and it prevents duplicate reposts. A release note adds a feed of reactions from followed users, which is opt-in and off by default.

A later source change sets NDK’s futureTimestampGrace to 300 seconds in the transport constructor. NoorNote now drops events whose created_at is more than five minutes in the future and accepts clock skew within that window. This stops events with far-future timestamps from staying pinned in feeds. The commit has not been confirmed as part of any tagged release.

nostr-double-ratchet

In nostr-double-ratchet, registration now rebases onto fresh signed roster snapshots, so stale setup data cannot bring back sibling devices that were removed. If setup hits a conflict, it fails in a way that can be retried (roster rebase commit). An optional persistent publication outbox keeps exact signed envelopes through acknowledgement and restarts, with a separate namespace per account. Apps must integrate it explicitly (outbox commit). Selected outbox and enrollment changes shipped in TypeScript releases v0.0.178 and v0.0.179.

Later source commits, still untagged, change how private groups are delivered. In TypeScript, group ciphertext is now wrapped in per-recipient Double Ratchet sessions, so each recipient gets a separately authenticated copy (kind 21113). The full fanout is persisted before the copies are durably queued. On receipt, the pairwise sender is authenticated before group decryption, and the message is persisted before it is acknowledged. Membership, group names, admin data and shared ciphertext are now kept off public group channels for both publishing and reading. The commit leaves network-level anonymity outside its claims. Updated group transport docs say fanout cost grows with the number of member devices, and they describe the group ciphertext as a local intermediate, separate from any shared public channel. Integrators must wrap the Rust GroupManager transport planner themselves, because each host’s transport policy lies beyond what the SDK can enforce.

Other unreleased commits tighten private invites and recovery. Private session responses now strip public invite reference and linkage fields in both TypeScript and Rust. This keeps private publication and public discovery apart from account-authenticated receives. Private invite publication now requires a single delivery recipient and rejects ambiguous multi-target distribution. Private group control rumors are excluded from observer delivery. Private group delivery now recovers once authenticated membership keys are ready, with a cap on key repair attempts and retry readiness that persists. These descriptions come from reading the patches; the changes have not been independently audited.

nostr-vpn

nostr-vpn v4.1.18 limits relay discovery to the configured application and fixes discovery for joining and for signed updates. Existing settings and identities are preserved. The source work is in nostr-vpn pull request 78.

nostter

nostter published its first public packages, nostr-kit v0.1.0 and nostr-protocol v0.1.0. They expose relay URL policy and ordering for events that share a replacement key, and the packaging preserves its existing behavior. In a separate set of changes, nostter rejects malformed NIP-05 public keys. Diagnostics compare the returned key with the profile, and the original casing of the identifier is kept (relay URL policy extraction, event replacement ordering, NIP-05 key validation, address diagnostics, profile-key diagnostics, identifier casing preservation).

NosTube

NosTube merged source that goes beyond its earlier scheduling work. In nsite hosting for the creator site, the server republishes a managed nsite root manifest once Blossom mirrors are confirmed, so a creator can publish a public site without a public origin server. add S3 storage and Studio controls adds hybrid local and S3-compatible storage with range playback, bounded per-blob migration, recovery after restart and degraded startup. Real-cloud operation remains unverified, and the test fixture does not independently verify SigV4 signing. NIP-5A is an existing NIP, and the Blossom URI proposal has its own separate status.

The trust filter now also covers video recommendations from the search service as well as relay recommendations. It fetches author scores and waits while they are pending. It applies to recommendations only and does not filter search results in general. Under the new report handling, an account is blocked as illegal only when the current account has filed its own NIP-56 kind 1984 report, so reports from other users do not block anyone.

Embeds at /embed.html load the standalone player again, and the documented autoplay, muted, controls and quality parameters now reach the player. oEmbed and canonical URLs accept a forwarded protocol only if it is http or https. This assumes a trusted proxy overwrites that header. None of these changes has been validated as a general moderation system.

Pages by Form*

Pages by Form* published 1.0.0 with encrypted documents that several people can write to (Pages 1.0.0 announcement, follow-up release note). Each author writes to their own replaceable slot, and readers share a viewKey. Editing can be limited to a list of named editors or opened to anyone with the link. When authors’ versions diverge, Pages displays the most recent one, chosen the same way every time, and keeps the other versions separately. CRDT merging and key epochs remain absent; existing readers retain access.

Share-link timestamp collisions were fixed, and rotating a link now creates a new viewKey (multi-writer document slots, share-link rotation). Rotation cannot take back content that has already been read. In separate source work, Markdown backup and import and relay presence checks add Markdown zip backup and import with an unsigned device-only option, plus per-relay presence and rebroadcast.

Pakstr

Pakstr, an Android application shell and packaging toolkit, adds import of an existing nsec to its native signer in v0.28.0 and v0.29.0. Import checks the checksum and key range, asks the user to confirm the npub, protects the key with Android Keystore and AES-GCM, and preserves any existing key (signer import change). NostrAppShell, the name used in the source, refers to this same project.

podtunes

podtunes adds opt-in boost posts that are published publicly on Nostr. They are signed through an external Android signer such as Amber, so the key stays in the signer (announcement).

Pollerama

Version 2.1 fixes how the trust network is built from sparse or capped kind-3 contact lists, so a partial fetch can no longer shrink the cached network (trust union pull request). Incomplete runs now retry. NIP-25 reactions carry complete target tags, and quote previews are fixed (2.1 announcement, follow-up note).

Submarine

Submarine’s new release adds password-protected export of the vault key, an explicit full relay resync and file-server settings. On Android the app has a new app ID, so users must reopen their vault with the vault key. Version 0.1.0 was covered previously, and this release adds recovery and control options.

SummaReader

SummaReader 0.118.0 lets users subscribe to one author’s verified Nostr notes and articles, fetched from that author’s advertised write relays. An edited article stays one item, and replies are left out. In version 0.119, users can set their own Nostr discovery and profile relays. Summaries run locally by default, but users can point the app at a remote API. Summarization output has not been tested independently.

Tenna

Tenna 0.14.3 fixes signing responses that were too large to return through links, and it fixes encryption and decryption of messages over 64 KB. Long nsite identifiers now show and open correctly (site name fix).

In version 0.15, you can log in on desktop over Bluetooth. Both devices show a matching six-digit code, and you approve on the phone before the private key is transferred to Din on the desktop. The desktop receives a copy of the private key.

YakiHonne

YakiHonne 2.1.0 lets users save selected text as NIP-84 highlights that keep the source context, including text shared from Safari. Replies marked as spam are hidden until revealed, and authors get controls over them, though spam detection is not guaranteed to be accurate. DM history is cached and live messages arrive while the DM tab is closed. Unread state and feed position are restored (YakiHonne 2.1.0 announcement). These details come from the publisher’s signed release notes and were not tested independently.

On the web side, YakiHonne web app v6.0.5 (release notes, 21 October) brings highlights to the browser client. According to the release notes, users can highlight text in a note or article and share it in a note. Highlights appear in the home feed, relay feeds and profiles, have their own tab in the content source, and support reactions, reposts, comments and zaps. The same notes list reposting for articles and highlights, plus an optional filter for likely spam in comments that users switch on in content moderation settings. Hashtags are now always published in lowercase, and the note editor gets fixes for line-break handling and for rendering text before image links.

Zaplite

Zaplite first restored apps from relay-signed catalogs and reran cached checks that had wrongly left them out (catalog restoration release). The corrected 1.0.8 release stops treating a relay’s NIP-11 key as an app’s publisher.

monostr

Releases 0.20 through 0.23.0 add privately synced list feeds, pinned tabs and account onboarding (list feeds note, onboarding note). The client now rejects local-network endpoints supplied as relay or watcher hints. This is a client policy, not full protection against DNS rebinding (endpoint policy note). When a feed first loads from cache, mutes and pending interactions are kept (cache display note).

Roadstr

A Roadstr update adds optional trip history sync. History is stored in encrypted application-data events, split into per-device shards with integrity manifests. Trip history and sync are each off by default, and location privacy depends on that encryption. Offline voice search and exploration are also new, but the voice engine only runs on eligible arm64 devices.

Staircase

Staircase’s 0.1.23 release announcement added NIP-88 polls inside encrypted MLS chats that work with Cordn. Results stay hidden until you vote or the poll closes, and votes stay out of the unread count. The release also added group repair and rejoin, which keep local history and handle multiple devices. It also routes replies from Android notifications through the same durable queue. Replying from a locked device requires Android 12 or later, and the user must first get past the screen lock. Staircase omits read receipts, and marking a chat read by hand applies to the local device alone. Staircase 0.1.24 brings the Cordn-compatible MLS group messenger to the web for the first time. The web version requires a browser-extension signer that supports NIP-44. Key creation and import are absent from the web version, and private keys stay out of browser storage. The local chat database in the browser is encrypted. Secrets for the database and links are encrypted to your own key through the signer, so the database opens only with the matching key. The publisher says the web version uses the same wire fixtures and test vectors as the phone app, a claim that still lacks independent confirmation. Browser origin and CORS rules may block attachments, so attachments may fail on some hosts. Every behavior in both releases comes from the publisher’s descriptions, without independent testing. Source: code.relay.tools.

My Signet

My Signet releases 0.21.0 through 0.21.4 enforce explicit NIP-46 method and kind scopes, and each scoped deletion must be approved on its own. Retained relay hints now survive temporary pairing, and the signer uses up to three app relays. It also recognizes newer app metadata. Persona-first signup and Heartwood pairing now wait for actual device confirmation. Guardian and app policy stays app-specific, and anonymity still depends on those application policies. Release 0.21.5 changes the default remote-signing relay from nos.lol to relay.primal.net. Installs that used the old default migrate automatically, and the change syncs to the user’s other devices through settings sync. Apps or devices that were paired only through the old relay have to be paired again. The publisher says the old relay stopped responding around 19 October. That is the publisher’s own report, not an independently confirmed global outage. Release announcements: first release announcement, second release announcement, third release announcement, fourth release announcement, fifth release announcement and 0.21.5 release announcement.

Napplets - Web Packages

A batch of versioned packages adds a proposed GAMEPAD API with runtime and conformance support. It ships in @napplet/core 0.34.0, @napplet/nap 0.34.0, @napplet/sdk 0.30.0 and @napplet/shim 0.32.0. Replacing native namespaces is still deferred. The source changes behind it are GAMEPAD runtime and tooling and published GAMEPAD runner selection.

@napplet/conformance 0.20.2 keeps extra signed Nostr tags, repeated values and content intact through deployment, snapshots, signing and migration (signed-tag preservation). Screenshot manifests now use the captured image URL (captured screenshot URLs). The batch also includes these tooling releases: @napplet/conformance 0.20.1 and @napplet/conformance-cli 0.3.4; @napplet/cli 0.9.1, 0.9.2, 0.10.0, 0.10.1, 0.11.0 and 0.12.0; @napplet/boilerplate 0.4.0 and @napplet/vite-plugin 0.16.1.

A newly merged change tightens the reference conformance runtime (manifest-verified conformance runs). The runtime injects the maintained shim and reports a failed namespace install separately from errors in the app under test. Headless runs with --manifest verify the event ID and signature. They also check the structure and require the raw HTML’s SHA-256 hash to match exactly. All of these checks finish before any code runs in the browser. Runs without a manifest report the check as SKIP. Because the runtime reuses the loaded HTML snapshot, sandboxed and same-origin debug runs see the same document. Domain grants and app protocols stay as they were. The change is merged source only. Packaging moves to a follow-up Version Packages pull request, and that pull request is not a release in itself.

nostr-social-graph

nostr-social-graph 3.0.0 is a breaking release. Private contact facts are now stored as standard event IDs, without the owner and draft wrapper. Legacy signatures are verified before the old form is discarded, and per-field clocks and clear operations carry over. The Rust identity crate 0.6 and the TypeScript 3 package now share test fixtures.

Nostr WoT extension

Release v0.8.14 adds an experimental signer that runs on the user’s phone. It connects over local Wi-Fi, or over Web Bluetooth in browsers that support it. This phone bridge is separate from the 0.8.13 passkey vault. Wi-Fi pairing starts from a QR code or a pasted link, and the user confirms pairing by checking that a code matches on the phone. From then on, the phone handles site approvals, signing and encryption. Pairing works while the extension vault is locked; the phone’s public key is not imported into that vault. Temporary Network accounts are removed when the bridge tab closes, while existing accounts stay. Switching to the phone cancels any local signing permissions still in progress, including for an account that is already active. The extension verifies each signature from the phone, records an invalid one in activity and returns it as an error. Phone coverage is limited to NIP-07 and classic NIP-04/NIP-44 encryption. Wallet identity, internal publishing and post-quantum features are unavailable, and a disconnect never falls back to local keys. Sound pairing is disabled because the content security policy blocks its decoder. Bluetooth requires a compatible phone build and browser Bluetooth support, while Wi-Fi pairing works without browser Bluetooth support.

The earlier release v0.8.13 adds a passkey vault that can be recovered through a provider, an encrypted file or a relay, along with an archive explorer that is separate from the archive feature in 0.8.12. If an NWC payment outcome is uncertain, the extension blocks retries. Quoted fees count toward allowances. Passkey recovery depends on browser and provider support, which varies.

Pull requests browser-verified top-frame fallback and NostrConnect prompt availability add a browser-verified top-frame fallback. When Chrome hides the page URL, the fallback still opens the signing or key-access prompt, excluding disconnected and other sites. This fixes availability of NostrConnect approvals.

With passkey recovery support, apps can reuse existing key, seed or vault recovery through passkeys. The SDK uses largeBlob storage when the provider confirms support and keeps the relying-party binding. Explicit relay fallback and host adapters cover other recovery paths. These recovery interfaces accompany the project’s extension release.

White Noise

The Android release from 14 October adds on-device translation, home screen widgets and shortcuts, contact and privacy workflows, and cancel and retry for media uploads. A signed store announcement went out at 16:10 UTC, and the GitHub release followed at 16:18 UTC. These features come from the publisher’s notes and have not been independently tested on a device.

Zzub

Zzub is a fork of Buzz. Its 0.0.30 release brings encrypted channel attachments, reactions, edits and deletions to phones, with the same guards the desktop app uses.

Zapstore

Zapstore 1.1.3 keeps comments, zaps, stacks and saved apps linked to an app after its catalog signing key changes. Installed files are matched by hash, following the upcoming relay contract. App comments, replies and reports name the app ID. If an app is no longer on the relay, Zapstore closes its page but keeps the local copy. A replaced catalog listing is removed locally only after the new listing and its installable file are stored durably.

Keep Android

Keep Android is the Android FROST threshold signer. Keep Android v1.3.2 security release moves to keep 0.12.2. That version bundles webpki roots and rejects certificate chains that pass through compromised intermediates on every relay and bunker TLS connection. The certificate handling has not been independently audited. Switching, removing, importing or creating an account now stops the bunker, removes the previous clients, rotates the bunker URL and revokes grants. If that reset fails, the change is blocked. Revocation works while the bunker is stopped, and bunker credentials are bound to both the account and the bunker key. Approvals that were remembered before now ask again. Storage restrictions fail closed. The app requires Android 13 or later.

The release follows a cluster of signer-safety changes merged in source. Revoking a NIP-46 client now removes its grants and rotates reusable bunker credentials. The same cleanup runs on upgrade, so some clients may need to pair again. A listed relay is eligible, and authorization still requires a grant or prompt. Storage reads now return one of three states. When storage is unreadable, the app keeps the PIN and lockout, kill switch, signing policy, audit secrets and anchors, keys and share registries intact. Active-share lookup keeps the user’s explicit account selection. An auto-signed response is sent only after its audit row commits, and switching a sensitive kind from deny to allow reapplies the duration cap. Sources: per-package sign-policy migration markers, storage faults across the FFI, sensitive-kind duration clamp on permission flips, absent versus unreadable stored values, share, audit and whitelist overwrite guard, database key minting guard, absent database key for an existing database, unreadable audit anchor or tamper flag treated as tamper, absent audit secret check against the anchor, NIP-55 requests and foreground recording, failed-removal reporting, pre-binding values at the derivable key name, derivable-name rule for public derivation keys, audit row before an auto-signed response, override markers cleared on account switch, unreadable metadata reported as a fault, active-share resolution, refused values reported as unreadable, fail-closed legacy kill switch, unreadable relay whitelist reported as a fault, recovery path for an unreadable relay whitelist, three-way PIN record read, keep re-pinned to main and bunker URL rotation on every client revoke.

nostur

Nostur 1.34.0 ships DM recovery changes that were earlier only in source. Healthy gift-wrap subscriptions now stay open after EOSE (gift-wrap subscription commit). If an encrypted attachment upload fails, Nostur retries it on another configured Blossom server (Blossom retry commit). The release also updates Web of Trust in the background while the device is charging and fixes profile nesting and relay reconnection. Photo uploads now show progress and can be retried.

In Development

Safebox Acorn

Safebox Acorn, a Nostr-backed wallet component, adds an optional library API for sender-paid fees on confirmed direct ecash relay transfers. In commit be112f5, quote_ecash_transfer checks mint input fees and picks denominations covering the net recipient amount plus the receiver’s redemption fee; the spend path revalidates that quote before spending. The encrypted Nostr relay payload names the sender as fee payer and records the net amount and receiver fee. Sender-paid transfers require confirmed payment mode and settle receipts individually; legacy callers keep current behavior. Shipped wallet UI support is yet to be shown.

Commit 19b4f9f makes cancelled relay-coordinated wallet-lock acquisition release only the local process lock it owns. A relay lease awaiting verification stays in place, since publication may already have succeeded, and its expiry keeps guarding other wallet instances. Added unit tests cover cancellation at each acquisition stage.

Applesauce

Applesauce is the JavaScript Nostr toolkit. Merged changes require the exact secret for unpinned NIP-46 pairing and make NWC deadlines cover capability negotiation. They also add a negentropy codec that is safe for large integers and a stricter structural guard for events (event structure validation, NWC negotiation deadlines, NIP-46 pairing authentication, bounded negentropy integers). A redaction pass that removes secrets and plaintext from debug logs is still an open proposal in debug-log redaction proposal.

Source commits (optimistic verifier, trusted monitor liveness, loader outcome routing) add an optional OptimisticEventVerifier. It always checks the event hash but only checks a sample of signatures. That sample drops toward 10% after 10,000 verified events over 14 qualifying days within a 30-day evidence window. Callers must opt in. This is not full cryptographic verification, so authentication and payment paths should keep strict checks. Liveness data from trusted NIP-66 monitors and loader outcomes now feed relay routing. A new skipped value in SyncRelayState means apps with exhaustive switches need updates. A changeset requests minor version bumps, but no published release has been confirmed.

An open fix for filterTimelineByMutes targets a reversed filter that keeps only muted events. With the fix, the filter would remove events from muted pubkeys, words, hashtags and threads. The bug is reproduced in a unit test, but there’s no release or integration proof yet.

Open proposal: a reworked COUNT request scheduler would start with up to 8 requests in flight and double that limit while the scheduler is saturated. Slow responses and timeouts would no longer count as congestion, but errors and rate limits would still halve the limit and trigger a cooldown. It adds a new timeout variant to the CountFailure union, which would break code that handles every variant of that type. In the author’s own live test against three relays, 120 counts had a median time of about 1.1s, against 2.5–6.5s before. That is one author benchmark, not an independent or general performance result.

Auditable Voting

Auditable Voting merged three questionnaire changes to its source; there is no release yet. Conditional showIf handling decides which questions accept answers and which count toward tallies (conditional questionnaire handling). Questionnaires can now carry signed English, French and Tamil translations, with optional legacy English sibling strings. This changes the questionnaire format exchanged between clients, not just the UI. Existing definition hashes stay the same, and tests check that the browser WASM and worker compute the same hash. Malformed translations fall back to English, and conditional and admission flows are unchanged (signed translations).

Printable admission credentials are now 10-character Crockford codes, replacing the printed nsec and serial (admission codes). The app stores one combined hash of the election, master list and code, plus lifecycle state. Issuance, replay and authorization run in both the browser and the worker. Since hashes are the only stored record, the app cannot revoke older codes when the same roster is regenerated after a reload. Duplicate checks last only for the current session, and the organizer controls completion. The change is still untested against live relays.

better-auth-nostr

Client-side event signing adds a client-side nostr.signEvent. It reuses the signer chosen at sign-in (nsec or NIP-07) and makes no server call. Before an event is returned, the pubkey must match the signer and the rebuilt protocol fields must pass signature verification. One timeout covers both getPublicKey and signing. Remote signers still need permission for each event kind.

Bitcredit

Bitcredit Core now validates incoming Nostr identity-chain and company-chain blocks as a candidate before storing them (identity-chain validation, company-chain validation). Both are merged pull requests, not a tagged release. During relay resync and recovery, both processors select the protocol-valid prefix of a chain. The company-chain processor stores the validated prefix once, and both hold Nostr contact and restore side effects until after the data is stored. Validation and storage are still separate steps. Wrapping them in a single atomic database transaction remains future work, so the code does not yet roll back changes if a write fails partway.

Bitcredit Core opened a proposal to validate and prepare incoming bill chains before they are saved. It follows the earlier merged identity (identity-chain PR) and company (company-chain PR) chain changes. The patch makes bill_chain_event_processor check for a valid prefix and for forks before it applies Nostr event updates or contact changes. An atomic database transaction is still a future TODO, so there is no rollback.

Buzz

Buzz merged several channel and community changes in source. Channels can now carry labels, and system channels can be limited to access control. Discovery filters by type and creator. Membership changes produce typed notices. Initial members are created atomically, so an identical retry is safe. Positional SQL tag checks keep a decoy tag from taking another event’s page slot. On mobile, caches and read marks stay within their relay community. Older ambiguous entries are reloaded. Mobile users also get Solo chats and projects with read-state sync. Channel sources: channel labels and label and creator filters applied before the page limit. Access sources: system channels limited to reads that name them and unreadable write targets treated as missing. Search sources: profile search over name and display_name only and people search through the relay’s name-only profile search. Other sources cover positional pushed-down tag matching and full signed events for operator listeners, along with catch-up and visible-message read marks matching the web app and agent and team config stored as NIP-AR artifacts (NIP-AR topic).

Operator listeners that receive full signed events now need a new registration signed by the target, plus fresh read authority. Legacy registrations keep working for 30 days. Operators also gain issuer allowlists stored in the database and mesh JWKS. Hosted mobile onboarding is opt-in, and hosted features turn on once auth domains are configured. A WebSocket client header option lets a client send a project NIP-FI assertion in the connection upgrade alongside NIP-42 AUTH. Redirects go unfollowed, and credential renewal stays with the caller. NIP-CL, NIP-FI, NIP-AP, NIP-FA and NIP-AR are Buzz project specifications that sit outside the accepted NIP set. Sources: Bring synced Solo chats and projects to mobile, keep cached state with its community, store per-community NIP-FI issuer bindings, account onboarding, key recovery and hosted reconnect, resolve NIP-FI issuer bindings from the database, support explicit mesh JWKS transport, define agent-key assertions in NIP-FA and NIP-FI, tag every membership notice with its channel type, start a channel with its members in one create and wait for the peer’s Close before dropping any WebSocket.

Later merges tighten relay membership and read scope. Buzz now writes the NIP-43 membership list in the same transaction as each membership change (NIP-43 topic), including owner boot and transfer. The relay signs this kind 13534 list, and a failed list write rolls back the membership change. Live fan-out after the commit can still fail while the stored list stays correct. When several updates land in the same second, timestamps are bumped forward one at a time, so bursts can push them ahead of the clock. Broad channel reads now use a fixed allowlist of channel types: stream, forum, DM and workflow. Future types appear only when a request names or recognizes them. A #h or #d filter on state kinds is handled as a non-legacy request with access checks, and system #t/#P opt-in applies only within system scope. Push delivery first reused the read path’s channel scope. A follow-up then allowed system-channel push only for an explicit #h filter naming a readable channel the subscriber belongs to, and broad filters stay excluded. Current clients leave these channels unnamed, so their behavior stays the same. In the message, forum and comment builders, mention tags must be 64-character ASCII hex. Tags are normalized for case and deduplicated, and one malformed member rejects the whole list. The check covers format alone, without testing whether the key lies on the curve.

Two fixes are proposed but not merged. Scoping each live REQ filter on its own would fix two bugs. Channel state queried by #d loaded on the first fetch, but later live updates were dropped. A subscription that mixed a channel filter with a community-wide filter also lost messages. Under the proposal, each filter matches only the topics it is authorized for, so it can’t pick up access from another filter in the same REQ. Separately, atomic channel-settings updates would write the kind 9002 request, every setting change and the related system messages in one database transaction. A failure would return an error and the client could resend. Today, switching a channel from public to private can fail while reporting success, and the retry is then rejected as a duplicate. Live cache updates and subscription revocation would run only after the transaction commits.

Chama

Chama added 99 deterministic public replay vectors and a device-independent protocol entrypoint. Other implementations can use them to check that they reach the same final states and refusals for the covered cases. Their evidence covers those replay cases; full consensus remains unproven and consensus rules stay unchanged. This source work landed across device-independent protocol core, Amber callback binding, replay conformance vectors and encrypted browser storage.

When Amber returns a callback key, Chama now accepts it only once and only if Chama has its own pending request. Saved Nostr keys and NWC strings in the browser are encrypted with AES-GCM. Browser crypto failure still falls back to plaintext storage. XSS and browser-profile access remain outside this protection. A content security policy now limits script execution to the scripts Chama ships. These are merged source changes (Amber callback binding, browser key storage).

Conduit

Conduit’s source now includes experimental occurrence commerce, added in occurrence assignments and durable merchant acceptance. Each merchant-owned kind 30410 product assignment is tied to an exact market and date. When a merchant accepts an order, stock is debited once, atomically, and the exact order identity is kept. Rescheduling updates only unused allocations, and existing orders keep their original terms. Under centralized app policy with additive coverage, publishing also covers app and personal relays while keeping frozen destinations and signed bytes. A third registry search endpoint is still pending, and executable authority is absent.

Follow-ups build on this. Event commerce checkout and recovery routing routes checkout and organizer stock handout. It also routes recovery. Accepted orders and recovery checkpoints are stored encrypted per account and device. Exact retry envelopes are stored with them. Restoring on a fresh device re-encrypts them, and portable checkpoints reject device-storage markers. Participant-bound order conversations separate local messages and replies by order ID and by the buyer–merchant pair. Payment evidence is separated the same way, which keeps records apart even when a signed order ID is reused. Wire IDs and encrypted history are preserved, and ambiguous legacy links stay unselected. Bounded anonymous checkout endpoints cap authentication and signing requests at 16 KiB as each request streams in. Tip requests get the same cap. The first chunk over the limit cancels the request, while valid split UTF-8 is kept. Existing signer and authorization rules still apply.

Verified wallet phrase and membership recovery now works when only some relays respond (recovery with partial relay availability). Optional encrypted name and approval records keep local progress (custom-address approval and activation). Event discovery batches all followed authors (discovery across all followed authors). Unsigned creation drafts that were blocked from publishing can still be recovered (blocked organizer draft recovery). All of this is merged source only. Release inclusion, deployment, deployed edge and external services, and funded end-to-end operation remain unverified.

Open PR #682 would have Conduit write every new Market order as one Open Markets numeric-v2 envelope. Complete order terms travel in a versioned extension. The PR fixes issue #623 and builds on merged participant-bound conversations. It removes the buyer-facing compatibility selector and the format switches based on features or size. Common fields must agree with the extension, and unknown or conflicting extensions are rejected. The encrypted transport size limit is still enforced, without truncation or switching formats. Multi-option shipping, pickup and routed-payment orders require explicit support declared on the exact merchant-signed listing revision. Existing named and numeric-v1 orders keep their original writers, invoices, signed delivery bytes and recovery state. Version 9 decode rules recover that history without rewriting signed envelopes.

In the same proposal, direct messages inherit order context only through authenticated references and reply ancestry. Merchants can explicitly resolve missing fulfillment as digital or shipping. That decision is bound to the original parties and terms, and the order itself stays unchanged. Replaying verified historical inventory acceptances leaves stock debited once. The PR remains open and undeployed. Its required E2E aggregate still fails on an unchanged 404 timeout, and funded-settlement and device qualification are still outstanding.

ehagaki

Two ehagaki pull requests, IndexedDB upgrade recovery and its follow-up, change how the local database recovers in source. An upgrade now proceeds independently of the worker, drops old display history and keeps drafts. Databases with a newer schema version stay closed. Previously displayed posts stay gone after recovery. A further WebKit legacy upgrade fix moves schema work so it runs synchronously inside upgradeneeded. Previously, metadata deletion in an async callback aborted the upgrade and triggered a retry loop. Legacy import markers are now read before any version is specified. An empty database list, version 0 or an error now counts as inconclusive about whether data exists. Drafts, deletion requests and shared media are kept while display history is cleared. Schema versions 170–179 open, and 180 and above stay closed and are left in place. This is merged source, and release inclusion is still unconfirmed.

Formstr Drive

Formstr Drive’s share-link and upload tray change turns each share link into one NIP-19 naddr pointer. The upload tray now follows the actual Android native-service handoff and respects server size limits. This share and open behavior differs from earlier source work. It does not promise that every upload service survives process death.

Separately, an open DriveKey recovery proposal would have the client merge every DriveKey copy it can find. It would read versions from cache and local storage as well as directly from relays. Each write would first be checked against its relay. A relay would receive a write only when it includes the version just read from that relay or after a real EOSE confirms the relay holds none. Every outbox send would therefore follow a check. Keys from old relays that come back online would be merged in, with convergence retries backing off from 2 to 30 minutes. Creating a new key would require that no history or version exists and that at least 2 of the 4 app relays confirm this. Cross-tab Web Locks would keep that creation to a single tab. At a recovery dead end, the user could explicitly confirm a new key. An old key that reappears later would still be merged. The proposal remains open and unmerged. It has not been released.

Grimoire

Grimoire now waits for its loader to finish before writing follow or list membership changes, preserving contact lists when relay reads time out. Relay mode edits publish to the union of old and new write relays. Zap one-line previews take sender, content and amount from the zap request, attributing the zap to its sender. Grimoire also renders Cyberspace SNO objects with bounded run-length expansion and placeholders for missing references. Nested objects and cycles are handled as well. Other game-client behavior remains outside this rendering support (follow and relay fixes, zap preview attribution, SNO rendering).

Kehto - Web Runtime

Kehto merged several host changes. A NIP-46 connect acknowledgement no longer counts as identity: the host always fetches and validates the public key. Revoking relay read access, or blocking a relay, ends matching live subscriptions and drops late callbacks, including after access is granted again. Upload callbacks are tied to a window and session and refuse stale reuse. When ACL settings fail to save, the host reports the failure and does not claim they will survive a reload. Service messages must pass source, principal, domain, ACL and firewall checks. Opt-in extension contracts do not give arbitrary domain access on a stock host. Sources: support policy-aware registered service routing, retire relay subscriptions on ACL revocation, report ACL persistence failures to callers, expose principal-scoped storage quota setter, return canonical principals from ACL listing, isolate upload teardown and suppress stale replies, retire empty-pubkey session indexes, expire environments across source retirement, surface ACL persistence failures and resolve NIP-46 identity with get_public_key after connect.

Paja, Kehto’s host, can now open napplets addressed under NIP-5D (proposed NIP-5D addressing in Paja). NIP-5D remains an unmerged draft proposal, and Paja implements that proposal. A root napplet (kind 15129) resolves from an naddr that gives the publisher and kind, with an empty identifier and no #d tag. When several match, the newest timestamp wins and the lowest event ID breaks ties. A named napplet (kind 35129) uses its literal identifier, and an immutable snapshot (kind 5129) opens from its exact nevent. Because a snapshot tab’s identity includes the event ID, two snapshots with identical artifact bytes still open as separate tabs. Signature checks, hash checks and the sandbox work as before.

Paja also has a Share overlay for verified root, named and snapshot tabs (tab Share overlay). It shows a selectable link with copy feedback and a manual fallback. While it is open, the napplet behind it is inert, keyboard focus stays inside the overlay and returns afterwards, and the app stays loaded. Shared links keep the exact pointer identity. Only verified, advertised contracts can still create intents. This is a fix to the host interface, not a new wire protocol.

LaWallet

A merged account endpoint change shows the active courtesy NWC wallet before an account has a paid address. Without it, users could end up unable to receive and could create wallets more than once. Another merged change, NIP-98 origin validation (NIP-98 topic), checks only the configured endpoint when one is set, so untrusted Host or X-Forwarded-Host headers can no longer widen the accepted origin.

Separately, an 18 October native Android commit ports LaWallet to Kotlin and Compose. It adds NIP-47 wallet interaction with Amber login. Notification catch-up accompanies this native port of the existing protocol. Tagged release and Play Store acceptance remain unverified.

Marmot TypeScript

In marmot-ts v0.7.0, group images require explicit Blossom configuration and verify uploads. Uploads support cancellation; replacement and clearing follow the MLS confirmation workflow. Remote blobs and previously shared credentials remain after clearing an image.

Separately merged source changes authenticate each proposal sender on its own and let removed admins accept their own removal. Invitees validate roles and components, inner events decode strictly, epoch forks resolve deterministically, kind 445 backfill is bounded and profiles are checked against the resulting state (deterministic epoch fork ordering, strict inner-event decoding, per-sender proposal authorization, existing-group dictionary order, invitee profile compatibility, removed administrator acceptance, result-state profile checks, bounded kind-445 backfill).

Mostr

A Mostr commit dated 20 October 02:41 UTC sends ActivityPub Create(Note) activities through the common text-note converter, including video notes from Loops. It removes the separate video path that produced addressable kind 34235 (horizontal) and kind 34236 (portrait) events. Under the revised test, a Loops video becomes a kind 1 event with an imeta tag carrying the URL, MIME type and dimensions. Clients must query kind 1 to receive these imports. A release tag, production deployment and cross-client playback remain unverified.

myco

Merged myco source adds an Android file picker for a subset of NAP-FS that asks for user consent (NAP-FS picker and limits, native file inputs). Napplets get opaque session paths to the selected files only, with access confined to those selections. Each operation is capped at 1 MiB, in-flight data at 4 MiB and a session at 64 files. Local install blobs are verified before any network fetch, enabling offline and LAN installs. A corrupt cache falls back to fetching and rehashing (install verification).

For npub mesh dialing, myco now queries node DNS directly to avoid failures from vendor or private DNS. Mesh backlog streams are routed and deduplicated by subscription generation (mesh dialing, backlog routing). Merged work also adds an Android TV remote and a choice of handler for napplet intents (TV remote, intent handler).

napplet.soy

soyli v0.29.0 adds account-scoped NIP-65 OUTBOX and INTENT handling, with explicit user consent for signing and structured-clone handoffs. A local Studio beta arrives in soyli v0.30.0. It creates and remixes playable napplets and publishes them through a reviewed signed-shell and GRASP flow.

Hosted Studio arrives in soyli v0.31.0, where users bring their own provider keys. It builds in the browser or on an isolated server, limits server maker runs and keeps drafts, checkpoints and settings private. Provider keys are stored encrypted outside the project, and workers receive a scoped inference connection (account-scoped outbox, local browser Studio, hosted BYOK Studio).

Newly merged source changes, separate from the releases above, help hosted Studio keep work when a run fails. When a run hits its time limit, the controller now holds a 30-second export reserve inside its execution budget. A typed STUDIO_TIMEOUT result lets the edits be verified directly without another inference call. Truncated chat diagnostics omit large file frames. The worker and controller must be deployed together, and soyLI and the protocol stay as they were (timeout edit recovery). Edited source can now be recovered even when the worker running it crashes, for example after memory allocation or threads run out. Disposable workers are cleaned up before the Git export, and thread and process use is capped. CPU and memory isolation remain as strict as before, and so does network isolation (crash-independent source recovery). For hosted remixes, discovery of public signed WSS/HTTPS sources now runs on credential-free Node workers. This avoids the blocked temporary CONNECT tunnel and the trusted install worker. The existing egress guards still apply, as do the DNS and TLS guards. Firewall and private-network restrictions remain as before (credential-free remix discovery).

Remixing now has a review loop for the original author (author review and merge of remix proposals). The author can view a proposal’s diff, try a private playable merge candidate and explicitly merge the NIP-34/GRASP source, while publishing the updated napplet takes its own separate approval. Each review is pinned to the account, proposal revision, target branch and checked source; a stale review is rejected, and a retry reuses the signed delivery. Browser merging stays bounded: edits to protected build config, dependencies or tests still require local git or soyLI review. A new My work dashboard gathers drafts, publications, incoming proposals, contributions and activity, and its read markers are stored in the browser, so they stay on that device. My work also keeps relay hints from napplet source links and from configured and publication relays. The browser merge shell keeps its existing permission set, including the NIP-34 kind 1631 it already allowed and its current iframe permissions (relay-hint preservation).

ndk

ndk is the JavaScript Nostr SDK. A reviewed but still open ndk pull request proposes turning default verification of every event back on for relays added at runtime. It would also bind the claimed ID, hash, cache entry and signature together. The fix remains an unmerged, unreleased proposal.

NIPs by Pollerama (better-nips)

A merged pull request adds server-rendered pages for Nostr community specs. A durable PostgreSQL relay index backs the pages, with verified handling of events and deletions plus shareable metadata. When the browser loads data from relays, it can replace a stale indexed revision. Its four patch commits were written on 13 and 14 August, and the in-window merge marks adoption. Deployment remains unverified.

nostr-relay

This relay merged a change so that a request with an empty filter list matches no events, bringing its NIP-01 handling in line. Clients that send an empty filter list will get no results from relays running this code.

nostr-tools

A merged nostr-tools zap validation change rejects zaps that contain duplicate recipient or event tags. Before this change, the library used the first tagged target.

An open subscription-count fix would have prepareSubscription count each real operation and make close safe to call repeatedly, so each subscription is released exactly once. The proposal says two paths can currently miscount: cleanup after a relay’s CLOSED plus EOSE, and the NIP-77 shared pool. Either can decrement twice or close an uncounted operation. The result can be a connection closed as idle while other subscriptions are still live, or a negative count that stops idle closing altogether. The change is limited to how existing operations are counted and leaves the protocol as it is.

nostr.build

A nostr.build URL import fix rechecks every redirect and every public DNS answer, then pins the connection to the checked address. This covers the server-side request path used for NIP-96 uploads and Blossom mirroring.

nostream

nostream 3.5.0 ships bounded, PostgreSQL-backed NIP-77 sessions, which are disabled by default. The relay advertises NIP-77 only while the feature is active. Authenticated restricted-query scoping stays in force for the whole reconciliation. Version 3.6.0 adds bounded NIP-66 probe history. It keeps 168 runs by default, and history can also be limited by age. A later admin operations console exists only in source. Related pull requests: add bounded NIP-66 probe history and timeline, add NEG-OPEN/NEG-MSG/NEG-CLOSE wire protocol, advertise NIP-77 in NIP-11 and expose its settings in the admin and add the operations console.

Also in source only, an opt-in paid write-access subscription lifecycle turns on only when payments.enabled is set and at least one plan is configured. Invoice confirmation and the start or extension of a subscription happen in one atomic step, and an early renewal extends from the current end date. Maintenance runs bounded grace and expiry and sends a renewal invoice about three days early. Access checks use a cache whose lifetime ends at or before the end of the paid period. Invited and NIP-43-admitted users keep their existing access without a subscription. Release inclusion and any deployed billing are still to be established.

Two open pull requests would change relay operations if merged. Opt-in rate limits and retention per paid plan would apply only when payments are enabled and a plan sets its own limits. Users whose plan is active or in its grace period would get that plan’s rate limits. Expired or removed plans, and failed lookups, would fall back to the global limits. The plan cache would not outlive the user’s access. Per-plan retention would only take effect when the global purge is enabled, and expired users would get the global retention at the next purge. The proposal has no per-plan limits on connections or subscriptions. A second proposal would remove static mirroring, meaning the StaticMirroringWorker plus the admin mirror health checks and probes. A leftover mirroring.static setting would be ignored with a warning, and NIP-77 sync is suggested instead. Operators with static mirroring configured would lose it on upgrade.

Nostroots

Nostroots pull request 310 restores live throttling of Trustroots identity verification and adds an atomic lockout after five attempts. These controls decide which identities the bridge admits. No test against a deployed SMTP server or bridge is reported.

ONOSENDAI

A cyberspace specification pull request adds normative protection for hidden items. Hidden kind 1 messages become unsigned rumors, and each one’s canonical ID is checked and attributed through a verified container. Hidden items carry the NIP-70 protected marker so ordinary relays will not republish them. Published containers and references do not carry it. This proposal is separate from the earlier action-chain proposal.

Pact

Merged pull requests mutual consent and private proofs and relay and reaffirmation handling tighten mutual bond handling. Consent uses the latest valid sides from two distinct authors and must still stand. Accepting a withdrawn proposal is rejected. Invisible private bonds retain their private channel scope. Private proofs are bound to their author and state. Stale relays and reaffirmation spam are reduced.

Discovery stays explicitly opt-in, and an acceptance repeats the proposed kind. Package and image publication are outside these source changes; deployment remains unverified.

Pensieve

A Pensieve pull request makes the ClickHouse index queue durable, so it keeps retrying after outages. Before this change it gave up after three attempts and stayed stuck until a restart. The archive was already durable; this change repairs query-index recovery.

Pensieve also updates the bundled TLS root dependencies used for relay ingestion, negentropy sync and avatar fetching, so they no longer trust the affected eMudhra certificate paths. The pull request reports a handshake test before and after the change against a host on an affected chain, with a normal relay as a control (TLS roots). A running instance gets the fix only after a rebuild and redeploy. Merging the lockfile does not patch an existing process. Follow-up changes mount the patched host CA directories into supporting containers, and the project documents its own deployment and health checks (container CA mounts, deployment notes).

pyramid

A pyramid commit adds a bounded archive for members’ replaceable lists. It keeps up to five versions for up to 30 days. A query for a single author and a single kind with a limit above 1 can retrieve the archived versions.

Route96

Route96 is the NIP-96 and Blossom media backend. Path PUT and hash uploads add uploads by path PUT and by hash. Strict auth applies, and the body hash is checked against a per-request temporary file before commit. Supported methods are advertised through OPTIONS. The pull request text describes this as following an upstream BUD-13 draft, so its upstream status remains a draft proposal. Separately, Route96 Base64URL authentication accepts unpadded Base64URL Blossom auth while still accepting standard and padded encodings, and its clients output Base64URL. That change is an interoperability fix.

rust-nostr

Merged rust-nostr changes fix how subscriptions are restored after a reconnect. A queued REQ is sent once. Each restored query resets its EOSE state and event count, preventing erroneous relay bans (duplicate REQ fix, restored query reset).

Sidecar

Sidecar tightened its site permissions. Standing sign grants are now scoped to account, host, event kind and d tag while lock and destructive-overwrite checks still apply, forgetting a site revokes its short signing and decryption windows and its timed automatic grants, and bulk Allow all now excludes kind 9734 zap requests, whose amount sits in tags the approval prompt does not display, along with destructive list-overwrite kinds (scoped standing grants, site revocation, zap-request approval, list overwrite approval). NIP-19 naddr stream announcements can be resolved and shared; wrong kinds or unavailable addresses fail visibly. A finished-post receipt allows composing and replying to continue and preserves a newly written draft (stream addresses, composer draft preservation). The composer now requires a word boundary before @, so email and Lightning addresses are no longer rewritten into Nostr mention URIs (mention boundaries).

Tollbooth-DPYC

The DPYC oracle’s v0.4.0 release ships the authorization changes that were previously only merged in source. Register-advocate and publish-campaign requests must be signed with the author’s own npub. Tool identity comes from NIP-98 or the OAuth holder’s wallet (NIP-98 tool identity, signed campaign authorization). The release also limits operator-registry writes to the Authority. Free tools remain public, so the own-npub check applies only to these actions, not to every tool.

TollGate

The merged conformance corpus pins the event grammar for Nostr kinds 10021, 1022 and 21023, sets recipient pubkey rules, and records where implementations currently differ, alongside HTTP and token test vectors. Recipient p tags contain a pubkey or are omitted; MAC addresses are invalid.

Zap Cooking

Zap Cooking merged eleven frontend pull requests that change how it handles Nostr data; these are source changes outside any tagged release. Profile edits, NIP-05 claims and Spark address sync keep existing kind 0 fields and tags, and republishing proceeds only when the newest profile read arrives in time, confirmed and well-formed (profile preservation). Signup now publishes kind 0 with the new private key it just created and checks the signed pubkey. Previously, a NIP-46 or NIP-07 signer restored from an earlier session could overwrite an existing profile. Updates now go through only when the signing pubkey matches the loaded profile. Clearing a field removes both its canonical key and any alias keys, without introducing new aliases (signup signer check).

Profile lookups query purplepag.es separately for each author. The kind 0 created_at decides which late-arriving names replace existing ones, and a name appears as anonymous only after a confirmed miss (per-author lookup, late profile updates). Mentions and repost names now share one profile store per pubkey with the sidebar. That store merges nprofile relay hints. Until a profile is confirmed missing it shows a placeholder, which keeps false anonymous names off the screen. Relay hints that arrive late trigger a new shared lookup. Avatar and recommendation paths still use the older cache (shared profile store).

Rebroadcast verifies a recovered signed copy and resends the original event unchanged to at most 12 relays, counting only confirmed deliveries (signed rebroadcast). Client tags reference one NIP-89 kind 31990 handler address owned by the organization; whether that handler event has been published is unconfirmed (handler attribution). The “All reads” feed filters spam using signature-checked organization block and hide lists, plus trust folds that can be undone (feed moderation). The NIP-99 market lists verified members’ listings and reports failed membership lookups as errors (market membership), and the composer leaves email and Lightning addresses intact (mention boundaries).

Zap Cooking also updated the parser and sanitizer dependencies it uses at runtime to process untrusted Nostr content. The updates address reported markdown and linkify problems, including quadratic-time parsing and copy-paste XSS (parser dependency updates). The author’s own audit count fell from 74 findings to 15. That number comes from the author’s audit, not an independent check of whether anything can be exploited. Known Svelte 4 SSR issues and unfixed transitive dependencies remain.

gittr

While a NIP-46 signature request is pending, gittr keeps its existing kind 24133 response subscriptions open and adds subscriptions on bunker relays it reaches during the wait. After the bunker accepts a request, gittr waits up to 15 more seconds for the reply and does not send a second request envelope.

Repository tips from signed-out visitors use plain Lightning invoices, which create no public Nostr receipts. When the payer is signed in and the recipient’s LNURL endpoint supports zaps, gittr sends a NIP-57 zap request that references the repository’s kind 30617 coordinate. Repository zap receipts from the network are counted together with the local ledger, and duplicates are removed. These are merged source changes, and their deployed behavior has not been checked independently.

Manent

Manent upgraded Dart NDK from 0.7 to 0.10.1 to pick up re-authentication of subscriptions on relays that require auth. The same change updates the Amber and NIP-07 signer interfaces. Manent’s NIP-46 client metadata still requests only get_public_key, nip44_encrypt, nip44_decrypt, and sign_event for kinds 33301 and 5. The adapters for NDK’s pending-request interface return an empty list and report false for cancellation, and the integration has not been verified at runtime.

bitchat

An open iOS panic-wipe notification proposal would make the iOS panic wipe also remove notifications the app has already delivered, including when a wipe fails or is interrupted. It would also drop an unused sender nickname from the DM notification userInfo. Android already clears notifications, so this is not a new Android feature. Removing notifications is also not the same as erasing them: the OS notification history may still keep a record outside the app.

Shopstr

An open NIP-09 listing-deletion proposal (NIP-09 topic) would have Shopstr’s server act on kind 5 deletion requests for listings. When authors delete their own kind 30402 listings, the cached versions would be removed and tombstoned by both event ID and address. Tombstone rows would be added only for the requester’s own known events, and of the declared kinds, only listings would be processed. The cache would check tombstones as events enter it, keeping a deleted listing from returning and being bought again while still accepting a newer relisting. Shopstr’s MCP delete tool would include the a and k tags. The proposal isn’t deployed and leaves the NIP-09 text as it stands.

nostr-pubsub

Four TypeScript releases of nostr-pubsub, all published on 2026-10-20, separate private delivery from public traffic. In v0.5.16, each private encrypted relay EVENT and each retry opens a fresh anonymous auth or message-server connection. Device and invite discovery each get their own anonymous scope per subject. The release notes say IP address and timing are still visible. Public and private queues are now separate and both persist, and retired shared groups are quarantined. In v0.5.17, retry intent is stored outside the disposable connection and survives until actual delivery, even after a host-local queue accepts the event. A relay-only entrypoint also avoids loading the optional FIPS browser imports.

The next two releases cover the FIPS path. In v0.5.18, private FIPS sends use a fresh anonymous endpoint for each event, each recipient copy and each retry. Each send waits for a provider receipt for that exact event. Identified receivers can no longer export the private cache or replay history, and public discovery uses one connection per subject. The optional anonymous provider needs FIPS 0.5.35; without it, sends stay queued as pending. In v0.5.19, identified receivers export EVENT and INV data only for authors marked as explicitly public. Privately fetched profiles, endpoint ads and future event kinds are blocked from broad replay, stale-cache replay and exact-ID replay. The full public gossip role is unchanged, and Rust consumers need FIPS 0.5.36.

Alby js-sdk

Alby js-sdk 8.1.0 and 8.1.1, released on October 20 and 21, change how the SDK handles Nostr Wallet Connect. Version 8.1.0 adds an optional recordEvent hook for recording incoming requests, since/until bounds on subscriptions, notification publication, and a check that amounts are positive safe integers (amount validation). The hook gives services a place to record requests and by itself does not make a payment run exactly once. Version 8.1.1 fixes a regression from 8.1.0: when a handler finishes after unsubscribe, its first kind 23195 response is still published once and retries stop, while a fully closed service skips the attempt entirely (response after unsubscribe). Handshake attempts now default to the pool’s maxWaitForConnection of 3 seconds, and a newer reconnect is now protected from eviction by a stale socket that timed out (connection timeouts). Old timed-out native sockets can still remain open until the platform’s own timeout.

Alby Hub

An Alby Hub pull request makes PostgreSQL transaction lookup sort rows with a NULL settled_at last. Previously, a failed first attempt could hide the successful retry, so NIP-47 lookup_invoice could return a result that omitted its preimage. SQLite behavior stays the same. The change is merged, and it is still unconfirmed whether any Hub release includes it.

shockwallet

A shockwallet test-branch implementation reworks the wallet’s custom Nostr RPC transport. It is merged to the test branch, which is separate from stable releases. Each call now tracks three phases. First it waits for readiness. The second phase is sending. In the third, it waits for a response. A safe request reuses any send already in flight. An unanswered safe request may be sent again after foregrounding with the same request ID. Payment calls are unsafe to repeat, so they are excluded from automatic retry. A new typed publish timeout signals that the EVENT may already have been written even though no acknowledgement arrived. Treat the RPC or payment outcome as unconfirmed in that case. The project’s own tests run the real TransportPool against a mock relay for signed events.

MintRadar

MintRadar, still in development, publishes signed kind 30385 health assertions for mints. These cover probe counts and checks on active keysets. They also record how long a mint has been offline. A status change becomes eligible at the next run once at least five minutes have passed. Eligible changes share a budget of 30 state changes per hour, and deferred changes wait in a pending state (status feed). The mint_down_since and mint_keyset_final_expiry values now use UNIX seconds, replacing the ISO timestamps that earlier code wrote (timestamp format). Existing active subscribers now get DMs when a change to a mint’s public key or input fee is confirmed. Any existing notification flag makes a subscriber active. These DMs are deduplicated and count toward the shared daily cap. A new informational mint_last_change tag appears in the next health event that is otherwise eligible, and on its own it triggers nothing (change DMs). The health reports record operational observations only. They make no claim about solvency or custody. They also give no advice on where to deposit.

Nymbot

Nymbot, a private AI assistant that works over Nostr, released version 1.0.8. Each conversation turn now uses fresh connection keys, and the reply goes to a key used only for that turn. The client resends recent context or a running summary each time, and that history syncs across the user’s devices. Rotating the keys keeps message content readable to the services that handle it: the Nymbot server reads each message to answer it, and the AI provider sees it too. The publisher says message text is kept out of storage and logs, while progress data stays briefly in server memory. It also says gateway logging is turned off. These retention claims have yet to be independently audited. The release also adds an approval workflow in which the assistant can propose a plan for the user to approve and can ask clarifying questions. Tasks can watch pull requests, and their changes can be reverted with transcripts kept. Wiping account data also wipes it on the user’s other devices.

Grocery

Grocery 1.0.5 adds a shared household pantry: a catalog with units and minimum stock levels, plus best-before lots that get used up earliest-expiry first. The pantry shares the encrypted list key through the same process the app already uses for lists. The project Grocery says lists are stored as AES-256-GCM-encrypted JSON in Nostr kind 30078 events and the key is sent to members with NIP-44. Only the content is encrypted, so relays can still see which npubs are members of a shared list. Older clients ignore the new household type. These are the publisher’s descriptions and haven’t been audited.

Postr

Postr is the Android Nostr composer. Postr 1.3.0 adds opt-in previews. Before previewing a referenced event, it checks that event and its signature. This covers Nostr note and nevent references as well as article naddr references. A Quote action inserts a nostr: URI with NIP-18 quote tags, and verified events go into a size-limited cache with retries. For bare web domains, Postr fetches previews over HTTPS and leaves the posted text as written. Private-IP destinations are blocked, as are redirects and images. Relay hints in references are followed only when they point to public, encrypted destinations. A browser action opens the note on njump. Existing accounts and drafts are unchanged. Outbox behavior also stays as it was. This description comes from the publisher and still awaits independent testing. Source: Postr on gitworkshop.

Nostrautica

Nostrautica is a Nostr client with groups and communities (source code). In version 0.13.2, new messages in a group you just joined appear live while the app keeps running. Communities can be open or invite-only, and approval-based communities are supported too. The app stops a join early when a required code is missing. At logout, anything you’ve published counts as sent once at least one relay has acknowledged it. Login links that carry a key now ask for your consent and leave the active account in place. Edits made on two devices are now merged, replacing the old behavior where the last write overwrote the other. The publisher says the app has had two external audits, and we have yet to verify that independently.

ContextVM

ContextVM opened a proposal for paid execution and result delivery, which depends on PR #110. It would use an authenticated NWC settlement lookup to catch up on missed payment notifications. It would also keep a durable store of paid outcomes and result-publication generations. After a worker restart, disconnect or republish, recovery reuses the stored result without a second payment or handler execution. Caller response IDs and stream reservation ownership are preserved, and cancel and cleanup are bounded. The provider is mocked, and live NWC, LNbits and zap settlement remain untested. A published result is distinct from a client receipt, and the proposal has no automatic refund or restoration of consumed rights.

Wisp

Wisp is the native Android Nostr client. Two Wisp security proposals harden checks on relay events. PR #679 covers Nostr Wallet Connect (NWC), whose standalone relay connection bypassed RelayPool’s signature gate and matched responses by e tag alone. A response would complete a pending request only when it is signature-verified, authored by the connection’s wallet-service pubkey and p-tagged to the client. The kind-13194 info event needs local signature and author checks before its encryption tag is trusted, since a hostile relay could otherwise steer negotiation with a fake one. NIP-04 remains the fallback when negotiation fails. The author calls this defense-in-depth: forging response content still requires the wallet-side ECDH key, so no demonstrated forgery exploit is closed.

PR #678 targets spoofed zap receipts. Wisp trusted the sender, message, amount and relays in a kind-9735 receipt’s unvalidated description tag, letting a self-authored receipt show any zapper and amount in notifications, per-note zap lists, live-stream chat, DM receipts and zap-poll votes. A shared parseValidatedZapRequest validator applies NIP-57’s client-side checks: the embedded request must be a signature-valid kind 9734 addressed to the receipt’s recipient with matching e-tag presence and value, the invoice’s description hash must equal the SHA-256 of the exact request string, and an amount counts only when the invoice matches the request’s signed amount tag. Invalid receipts fall through the existing sats > 0 and null-zapper gates with no call-site changes. This ties invoice to request and leaves open whether the receipt author is the recipient’s authorized zap endpoint and whether payment settled.

Both proposals are open, unmerged and unreleased. The author reports that physical Android regression tests passed, which we have not reproduced; real-wallet end-to-end testing and integration testing of duplicate and late NWC responses are pending.

Dark Wisp

Dark Wisp’s open PR #99 reworks how NIP-53 live streams are found, how their chat loads and how zap totals are counted (NIP-53 topic). It remains an unmerged proposal against main (head eeba9aa) and is unreleased. A stream appears when it is marked live, has a streaming URL and has republished its kind 30311 event within the last hour, and recent chat activity alone is insufficient. Chat opens with the newest 50 messages. You can scroll back through older pages of 50 using an inclusive until bound, and the view keeps up to 1,000 rows and holds your place. The live subscription starts 10 seconds before the present. Zap receipts are gathered from both the chat and archive relays, deduplicated and summed per stream. A trailing “+” marks a total that may be incomplete because the scan covers a limited window. Turning on the hide-live setting now stops stream discovery immediately, where before it only hid the UI. Playback stays on ExoPlayer’s native streaming, and the iOS LL-HLS workaround is left out of this port. For users, this should mean fewer stale or dead streams and chat history they can scroll through, with zap totals that flag when they may be incomplete. The main caveat is that the author’s live-device tests ran on the upstream Wisp build. For this Dark Wisp port the only reported check is compileDebugKotlin, so it remains untested on a physical device.

Snort

Snort, a Nostr web client, now treats NIP-22 kind 1111 comments as timeline content in source. Commit 1252f74 adds comments to the shared event kinds its timeline builders request and classifies every kind 1111 event as a reply, alongside events with e or a tags. Conversations and profile feeds can therefore show comments, while the posts-only Following view filters them out. Added end-to-end fixtures encode that split, including a user’s own comments on their profile. A released build carrying the change is still unconfirmed.

New Projects

backchat

Backchat, a Linux Bitchat implementation built on GPUI, published its first tag, backchat v0.1.0, on 17 October. It supports relay-based geohash chat and is designed to be compatible with Bitchat’s encrypted envelopes. Bluetooth LE runs on a separate path. Interoperability with other Bitchat clients is reported by the project and remains unverified here on devices.

ditto-blossom

On 17 October, ditto-blossom added a Rust replacement Blossom server that indexes blob operations in LMDB. Ban and preserve administration followed on 20 October as separate source work. All performance figures come from the project’s own benchmarks and remain independently unverified.

iskra-bridge

iskra-bridge v0.1.0, released 17 October, exposes encrypted TCP streams relayed over Nostr to Matrix homeservers. Relays act as a blind transport, and Matrix TLS stays end to end. The repository includes older history; this release marks the current stream-v2 milestone.

Lumen

Lumen published its first release, Lumen 0.1.0, on 15 October as a signed Android build. It supports NIP-47 balances, sending and receiving across multiple wallets, along with encrypted local history. A 0.1.1 follow-up changes only ABI packaging and the version number. Independent funded-payment validation remains unverified. The release is scoped to Android.

ngit-mirror

Initial code from 14 October mirrors the refs of public GitHub organizations into ngit under a restricted NIP-46 signing policy. GitHub stays the source of truth, including for force pushes and deletions. Deployment remains unverified.

Nomisma

Nomisma, a prototype expense ledger, published its first releases, 0.1.0 through 0.1.2. It syncs encrypted operations with Amber, NIP-44 and NIP-59 (0.1.0 release). Version 0.1.1 fixes Android slash escaping that made operation IDs non-canonical, and both participants need 0.1.1 or later to sync (0.1.1 release).

Version 0.1.2 adds recipient search that checks signatures and NIP-05, along with invite recognition (0.1.2 release). Pairing intentionally resets unsynced configuration, including theme settings. The README describes the app as an advanced prototype or internal beta. Signed distribution and public source show that the app is listed and reviewable, not that it has been independently validated on devices.

nosfry

nosfry v0.1.0, tagged on 19 October, is a new Rust relay that runs a native LMDB-backed NIP-01 service. Commits on 20 October add COUNT, authentication and protected events, but these landed after the tag and remain unreleased development work. Workers-version parity and independent performance validation remain unverified.

nostrmix

An initial Go implementation of nostrmix, committed on 16 October, provides a loopback WebSocket gateway and a CLI that route relay traffic through Nym’s SOCKS5 proxy. Upstream connections fail closed and event signatures are checked. It is an unreleased prototype, and its anonymity is a design goal that has not been audited.

Verify

Changes in file-relay outage detection, HTTP(S)-only attestation links, chunked file hashing and trusted-verifier descriptions and URLs choose a file’s description and URL by agreement among trusted verifiers. Agreement supersedes first-arrival or backdated assertions. With zero trusted verifiers, Verify shows the earliest value and marks it unconfirmed. Publisher control of the URL remains unverified by web-of-trust agreement.

For files over 512 MB, hashing runs in 8 MB chunks with the same hash semantics, so gigabyte-sized artifacts can be checked without loading the whole file into memory. Only HTTP(S) attestation URLs become links or publish inputs, which blocks javascript: and data: URLs from untrusted verify events. Verify also queries its own file relay and uses close evidence to tell an outage apart from a missing verification while other relays stay connected.

Pagemates

Pagemates is a new Firefox extension. Its sidebar turns the current page or site into a shared room with chat, cursors, clicks, highlights and drawings. Nostr relays carry signed presence events. PeerJS connects peers to each other, and the actual interaction runs over encrypted WebRTC. Public room hashes can be guessed, and relays and peers can see IP addresses. Automatic joining is on by default but never happens in private browsing, and history is kept only in memory. Source commits introduce version 1.0.0 on 20 October and 1.1.0 on 21 October.

QRST Signer

QRST Signer is a new Android app that moves Nostr keys between devices using the nostr-nsec profile of the draft QR Secret Transfer 1.6 protocol. The key is encrypted with NIP-44 inside an ephemeral kind 21059 gift wrap and sent over a relay. The receiver then confirms it with digits. Nostr keys are encrypted for storage with an Android Keystore-backed AES-GCM key. On a phone with a lock screen, releasing a stored key requires device authentication. A 21 October handoff commit added qrst: handoff from any compliant bounce page. The project warns that the protocol is an unaudited draft and should only be used with throwaway keys. Despite its name, the app does not sign events yet.

HERDR White Noise remote

codr is a new Linux plugin for HERDR that lets you reach local sessions from a phone over White Noise. It creates one encrypted White Noise/MDK group per local session and invites a configured phone identity. Prompts from the phone go only to the matching session, and completed final replies are sent back. Final-reply extraction works for OpenCode, Codex and Claude Code. Other backends get status updates, but final-reply extraction is not guaranteed. Session mappings survive HERDR’s native session restore, and group labels follow HERDR tabs. Attachments and terminal key commands are not supported.

Protocol and Spec Work

NIP-01 makes empty-list filters match nothing

The empty-list filter change said an empty list matches nothing. An omitted field still places no constraint on that field. Network-wide relay conformance is not established here. On the relay side, cagliostr’s empty-filter fix makes empty ids/authors/kinds and tag lists match nothing across REQ and COUNT. This also applies to live subscriptions, on both SQLite and PostgreSQL.

NIP-01 discourages empty-list requests

The follow-up clarification, merged 20 October, keeps that MUST rule, removes conflicting text saying lists hold one or more values, and says clients SHOULD NOT send empty lists.

NIP-59 recipient-deleted gift wraps proposal

An open gift-wrap deletion proposal, created 19 October, says relays SHOULD refuse to store kind 1059 event IDs again after they are deleted under the recipient p-tag deletion rule. This would stop a rebroadcast from undoing a recipient’s deletion. The wire format stays the same, and the requirement is SHOULD-level. NIP-62 already covers rebroadcast after a request to vanish.

Napplet gamepad interface

The GAMEPAD draft, merged 15 October, makes the runtime the only reader of physical controllers. The focused, visible napplet gets live values. Background napplets get neutral axes, buttons and timestamps but can still see controller connection information. This optional domain uses a subscribe and state-snapshot protocol. Enforcement depends on the host blocking native controller APIs. Its reference implementation points to a napplet-soy feature branch, so broad shipped support is not established.

Napplet motion interface proposal

An open MOTION draft, created 16 October, gives the runtime ownership of device sensors. The runtime would ask for user consent and send live samples only to the focused napplet. Subscribers can still see availability, permission and focus state. Native sensor APIs are denied only where the host allows it, so isolation depends on the host.

Napplet location interface proposal

Under the open LOCATION draft, also created 16 October, the default permission grants coarse position only. Precise location and background delivery each need a separate grant. A visible napplet with a grant receives positions. A hidden napplet receives them only if it also has the background grant. No shipped implementation is claimed.

Napplet mesh interface proposal

An open mesh domain draft, created 15 October, lets napplets publish, subscribe and count blobs through people who have deliberately paired with each other, with no relay or internet connection required. Its ttl counts trust-circle edges, not physical transport hops. The runtime handles pairing, routing and deduplication. A napplet picks a hop budget within a cap the user sets. Strangers on the same radio transport are not circle members, and publishing to Nostr networks remains a separate action. The draft makes no implementation guarantee.

Napplet navigation interface proposal

The open intent navigation draft, created 17 October, has the runtime keep history, visit IDs and the current position for each authenticated napplet instance. Napplets report committed locations for the intents they advertise. Back and Forward send the stored invocation to the same live instance. Delivery alone does not move the position. The napplet’s next report is linked to the IntentDelivery.id. Top-level and browser-back policy belong to the shell, and native History API or hash changes are not reported automatically.

ContextVM interface proposal revision

New commits landed on 14 October in the ContextVM bridge draft, which has been open since June. ContextVM carries MCP over encrypted Nostr messages. The revision isolates pending requests, close handling, events, client identity and payments for each authenticated napplet endpoint. Users can deny a request or require a prompt. They can also allow it within an allowance, and budget checks hold when requests run concurrently. Tools now match by portable per-tool schemaHash values and provider pins, which replace shell-local names. Timeouts range from 1 to 300000 ms, with 30000 as the default. The author describes a partial kehto implementation. Its conformance cases are requirements, not passing runtime tests.

Marmot existing-group component activation

Existing groups can now adopt new components under Marmot’s component activation rules, merged 15 October. Each client updates the support list in its own authenticated LeafNode. A group becomes eligible only when every canonical leaf advertises the component. An authorized, explicit activation Commit then installs the initial GroupContext state and the required component ID in one atomic step. Upgrading apps does not trigger activation. After activation, a member cannot drop required support and stay in the group. KeyPackages without that support are rejected for additions. No shipped client support is claimed.

Marmot last-resort init-key grace

Under Marmot’s init-key grace rule, merged 16 October, clients SHOULD keep a last-resort KeyPackage’s init_key after confirmed replacement so delayed Welcomes can still decrypt. The recommended window ends 24 hours (86400 seconds) after confirmed replacement or at Lifetime.not_after, whichever comes first. They MAY delete it earlier once they stop accepting them. Deletion rules for consumed packages that are not last-resort are unchanged. A compromised old key could open recorded Welcomes during the retention window, which extends exposure by at most 24 hours. It does not give general access to future epochs.

Marmot account-sync idea

A non-normative account history and backup design was merged 15 October. Under this idea, sibling devices would send read-only history and attachment keys to each other in bundles sealed to the recipient, never MLS state. Small state such as read positions and mutes would travel with them. Backups would use a separate recovery key and would not restore membership. Imported history depends on the sending device and cannot later be authenticated independently through MLS. Expired messages are left out, and attachment availability still depends on external storage. The design creates no implementation requirement.

Marmot multi-device account proposal

An open multi-device specification proposal, created 17 October, would move the lifecycle of devices and KeyPackage slots into normative text. Each installation would get one random, persistent d slot, with no hardware-derived ID. An account could provide at most 10 fresh valid packages per invitation. Leaves would represent an account’s devices. Removing a person removes all of that person’s leaves in one Commit, and removing a single device remains valid. An optional client tag is self-reported metadata and plays no part in validity or identity. Using NIP-09 to delete slots is cleanup, not cryptographic revocation. Relays may ignore those deletions. The diff uses spec language about itself, but the proposal is unmerged. Pairing and device-group protocols are still separate design work.

NWC get_budget method

The optional NWC-13 get_budget draft (NWC-13 topic), covered previously as a proposal, has now merged into main, on 20 October. It builds on NIP-47. Its permission is separate from get_balance, and it reports only the requesting connection’s allowance. The request takes no parameters. Responses give used_budget and total_budget in millisatoshis and a renewal_period of daily, weekly, monthly, yearly or never. A renews_at field is required for renewing budgets and omitted for never. An empty {} result means no budget is configured, which is different from a configured limit of zero. Wallets advertise the method in wallet info and in authorized get_info methods, and SHOULD advertise extension 13. The method cannot create or change budgets, and an allowance does not prove that the wallet holds the funds. No wallet implementation is claimed.

NIP-01 atomic subscription replacement proposal

An open NIP-01 proposal would let a REQ that reuses an existing subscription ID replace the whole old filter set atomically at the source. The swap is lossless: events before the REQ match the old filters and events after it match the new ones, with everything matching the old filters flushed before any later EOSE or CLOSED. The initial query may return duplicates, which clients remove by event ID. A refused replacement produces a CLOSED that also ends the old subscription, and the client receives nothing further, EOSE included, until a REQ is accepted. The change needs no new message types or prefixes. It adds no NIP-11 fields either. The author’s local measurements across five relays are unreplicated and describe those tests only, separate from current network-wide behaviour. This proposal is separate from the empty-filter-list clarification.

Concord forum presentation rules merged

Concord PR #24 is merged into the spec. It gives CORD-03 an optional ChannelMetadata view field that selects chat or forum presentation. Clients must fall back to chat whenever view is absent. The same fallback applies when its value is unknown or unimplemented. Chat Plane key and address rules stay the same, and so do its folding rules. view uses the existing wire transport with no new cryptographic derivation.

In the merged rules, a kind 9 subject tag makes a titled post limited to 256 UTF-8 bytes; receivers truncate an overlong displayed title and keep the message. Clients must preserve view when they update metadata, which keeps a chat-only client from switching a forum back to chat. This is a spec merge, and an app release or wide implementation has yet to be shown.

Concord roles and voice proposal

Concord PR #25 is an open proposal for Roles v2, which would rank permissions and allow per-channel and per-category overwrites, with private-channel key distribution tied to VIEW_CHANNEL. Restricted channels would use writer-address keys and writer certificates. The proposal also covers moderation and nicknames, along with channel categories. For voice, it proposes a peer-to-peer iroh mesh that is relay-only by default, with signed presence and moderator directives; its transport ALPN is concord/voice/1.

PR #25 remains open and unmerged. Nothing from it has been released. Its Vector widescreen reference implementation and live tests are the author’s claims, which we have not independently checked. The PR body says the work is planned for Vector 0.5.0. Voice interoperability is explicitly incomplete: Vector’s peer-to-peer transport and Armada’s brokered transport can’t share a call yet. CORD-08 (disappearing messages) is excluded, and the evidence falls short of showing Discord feature parity or support across all clients.

NIP deep dive: NIP-37 and NIP-48

NIP-37 and NIP-48 set rules on either side of publication. NIP-37 stores an unsigned draft in encrypted form before the author publishes it, and NIP-48 labels a signed Nostr event whose content originated on another network. Both specs are marked draft and optional. They are separate mechanisms: neither requires the other, and neither supplies the other’s privacy or provenance properties.

NIP-37: Draft wraps

NIP-37 defines kind 31234 as encrypted storage for an unsigned draft of any other kind. The draft’s JSON string is encrypted with NIP-44 to the signer’s own public key. Its ciphertext goes in content. The d tag sets the addressable coordinate, so a later save under the same identifier replaces the earlier wrap. Its required k tag names the draft’s kind, and a NIP-40 expiration tag is recommended. A blank content signals that the draft was deleted. Kind 1234 checkpoints hold the same kind of encrypted payload and point to their parent with an a tag of the form 31234:<pubkey>:<identifier>, which gives a revision history.

Kind 10013 lists the relays where a user prefers to keep private events such as draft wraps. Its relay entries are private tags: JSON-stringified, NIP-44-encrypted to the signer and stored in content, with the public tag array left empty. Clients must publish kind 10013 to the author’s NIP-65 write relays and should send kind 31234 events to the relays it lists. The spec recommends that these storage relays require NIP-42 authentication and serve events only to the authenticated signer (NIP-37).

The following kind 31234 event was retrieved from nos.lol and is reproduced unchanged. Its plaintext is unknown.

{
  "kind": 31234,
  "id": "4667eefd63450b03db19cc0b9297ecf1fe2b65fc9ccdd56f065fbae13981e083",
  "pubkey": "64acf4055fa826bcab8457e24ef8fba7490abb1e76dbab6aa8752a53a0eb4d4a",
  "created_at": 1792437134,
  "tags": [
    [
      "d",
      "bb0d7e8d-6ee6-407b-8426-85e43a0b954c"
    ],
    [
      "k",
      "1"
    ]
  ],
  "content": "AsSHMdC3Yuw9szbDej9OMmPUF5q37XUHBLnY2YaZ14zo/h3cwtZ7iZ30ONchDUrJmRSG4GZ7nbv0u6KMovyBZwNWJdwOlkjTjsoVCJ01RaQwt3fS74GU52xmYlDEYxMcLiVm6Qo/vukluILTqN9RBBYDcNap35v21ZzllMeGbqmPqfeq4DIihNjjALOPBgw0R42OCgY/o6pt/ZXPU1LUiiH+cJwKFlvhTRk4cAmb/y/uWNEghffUvNaAog0fLFdq6B5PBgTROcDG+O8o1URoZyYqj53/MEkOU/qbcnDML2cXW76A3Hz1jeqxvwmvpSHpXUwBak1QLsWL6wNWiSd833yK7Y0ge4noHLN1MbSLat0aQyClZHFPjJ6Yz7MbicnwumKH",
  "sig": "0bd82e078e215b5ac6071b5facfb1ddcfb1a2ca8d2f2cec06849f83e1cf69503724a0ba116389d642181e755b9ac6ada6733f3420a3ff1fc2143d2c6d13223e1"
}

The k tag declares a kind 1 draft and the d tag is a random UUID. The event has no expiration tag, so it skips the spec’s recommendation and gives relays no NIP-40 signal for dropping it. Anyone who can fetch it reads the author pubkey, created_at, kind and both tags, and the ciphertext length gives an approximate size for the draft. Decrypting content requires the author’s private key (NIP-37).

These properties set the privacy limits. NIP-44 hides the draft body, leaves the outer pubkey, timestamp, kind and tags readable, and a relay can still copy the event. Authenticated download is a recommendation for relay operators that a client cannot enforce. Expiration and replacement signal a change in the stored draft; blank content signals deletion. Earlier ciphertext can remain in relay storage or archived copies. A kind 10013 event on public write relays keeps its relay URLs encrypted but shows that the list exists and when it changed. Every draft and checkpoint is encrypted to the same key, so a compromised key exposes all of them (NIP-37).

NIP-48: Bridged events

NIP-48 lets any event kind carry a tag of the form ["proxy", <id>, <protocol>], which indicates the event originated outside Nostr. The <id> must be universally unique regardless of protocol. The spec lists four protocols and allows more to be added: activitypub with a URL, atproto with an AT URI, rss with a feed URL plus a GUID fragment, and web with a URL. Clients may use the tag to reconcile duplicates bridged from other networks or to link to the source object. The spec defines no bridge registry, deduplication algorithm or trust policy.

The following kind 1 event, created in August 2023 and retrieved by ID from relay.mostr.pub and nos.lol, is the same event NIP-48 uses as its ActivityPub example. It is a historical illustration and is reproduced unchanged.

{
  "kind": 1,
  "id": "55920b758b9c7b17854b6e3d44e6a02a83d1cb49e1227e75a30426dea94d4cb2",
  "pubkey": "79c2cae114ea28a981e7559b4fe7854a473521a8d22a66bbab9fa248eb820ff6",
  "created_at": 1691091365,
  "tags": [
    [
      "proxy",
      "https://gleasonator.com/objects/8f6fac53-4f66-4c6e-ac7d-92e5e78c3e79",
      "activitypub"
    ]
  ],
  "content": "I'm vegan btw",
  "sig": "a72f12c08f18e85d98fb92ae89e2fe63e48b8864c5e10fbdd5335f3c9f936397a6b0a7350efe251f8168b1601d7012d4a6d0ee6eec958067cf22a14f5a5ea579"
}

The id is the hash of a fixed serialization of pubkey, created_at, kind, tags and content, so JSON key order has no effect on the id or sig. The proxy tag names an object URL on gleasonator.com and the protocol activitypub (NIP-48).

The signature proves that the holder of the pubkey shown signed this event, including its proxy claim. For bridged content that signer is usually the bridge. The signature leaves the remote authorship and source-site authenticity unverified. Whether the source still hosts the object, and whether its content matches the Nostr copy exactly, also require separate checks. A client seeking more assurance can fetch the source object and decide which bridge keys it trusts. Deduplication is optional, and the tag discloses the claimed origin to every reader of the event (NIP-48).

Implementation examples

Amethyst

Amethyst’s Quartz library implements these mechanisms in source.

  • The draft wrap model requires the signer’s pubkey to equal the wrap’s outer pubkey before NIP-44 decryption. It parses the inner JSON and recognizes blank content as a deleted draft. A draft can contain e and a tags that reference public events, and the model deliberately offers no relay hints for them, so private storage relay URLs do not leak into hints for those public events.
  • The kind 10013 relay list writes new lists with relay tags in encrypted content and an empty public tag array. On update it moves public relay tags left by older clients into the encrypted content, and on read it accepts both locations for compatibility. The migration does not erase public copies that relays or archives already hold.
  • The proxy tag parser and its tag helpers parse and assemble proxy triples, define constants for the four listed protocol codes, enumerate every proxy tag or return the first, and detect whether an event carries a non-empty valid triple. Parsing reads the claim without verifying the remote origin, and the parser alone does not determine how any screen displays or deduplicates bridged content.

Notedeck

At commit 9395544, Notedeck implements NIP-37’s private relay list. Private relay URLs for kind 10013 are stored as JSON relay tags inside NIP-44 content that is encrypted to the account’s own key. They are not published as public NIP-65 read/write flags. When parsing, Notedeck decrypts with the account secret and normalizes the URLs. Read-only pubkey accounts get an empty set, and malformed JSON is logged and ignored. private_sync.rs passes these relays to a private client that handles local ingest, fan-out, NIP-77 history catch-up and live REQ. This covers the relay-list part only, not a full kind 31234 draft UI. No independent runtime or interop test was run.

Mostr

In Mostr’s transmute.ts (20 October commit), toNoteEvent appends ["proxy", note.id, "activitypub"] before calling signEvent(event, note.attributedTo). It emits kind 1111 for comments with a parent and reply, and kind 1 otherwise. note.id is the ID of the remote ActivityPub object. The tag labels where the event came from. The signature does not prove Fediverse authorship, account control or that the objects are the same.

Short history

NIP-37 first appears under that number in 48674e5 (Vitor Pamplona, 2024-05-30). That commit moved it from NIP-35; it is not where draft storage was first proposed. NIP-48 began as “Proxy Tags” in 064a79f (Alex Gleason, 2023-08-03).

Using the two mechanisms

NIP-37 encrypts an unsigned working draft for its author and routes private data, while NIP-48 puts a visible origin claim on a signed public event. Both remain optional drafts that work independently. NIP-37 protects the author’s unsigned draft. For NIP-48, proof of origin stops at the bridge’s signature and does not authenticate the external author. A client may keep a future proxy tag inside an encrypted draft, though the existing encrypted example leaves its plaintext unknown.