L’organizzazione Marmot Protocol apre tre nuovi repo per una bozza di protocollo v2 e una linea di client nativi: un workspace Rust chiamato darkmatter, un’app iOS SwiftUI darkmatter-ios e un’app Android Kotlin/Compose darkmatter-android. L’originale Flutter Whitenoise viene archiviato. Chama comprime diciassette release in una settimana e attraversa la linea di app standalone con v3.0.0 prima di portare un ridisegno completo della UI della trade room e storefront per venditore in v3.1.0, sopra a share Shamir solo per il detentore, sostituzione dell’arbitro, routing di community mondiale e notifiche di trade end-to-end. Coracle lancia un servizio di relay ospitato a pagamento sostenuto dallo stack open-source Caravel e zooid, con integrazione profonda con Flotilla pianificata. Angor passa a mainnet di default in v0.2.30 e porta un test di funding UAT a 3 utenti in v0.2.29. Amethyst porta 41 PR non rilasciate che continuano il lavoro NIP-32 / NIP-F4 / Tor della scorsa settimana. NIP-67 (hint di completezza EOSE) e autocomplete NIP-50 sono mergiati, chiudendo due gap di correttezza di lunga data nel protocollo relay core. NIP-GART propone un wire format a tutela della privacy per gli alert di emergenza, e NIP-46 acquisisce un metodo di logout.

Storie principali

Marmot v2 (Dark Matter): ridisegno del protocollo, client nativi, app Flutter archiviata

Tre nuovi repo sono apparsi sotto l’organizzazione GitHub marmot-protocol questa settimana, che insieme formano la forma dei primi progressi di una bozza di protocollo Marmot v2 e una linea di client nativi che sostituisce la linea di app Flutter. darkmatter (Rust, creato il 13 maggio, trentaquattro commit negli ultimi sette giorni) contiene la bozza del protocollo v2 in spec/, un engine CGKA sostenuto da OpenMLS in crates/cgka-engine, un simulatore di conformità con property test e un modello formale Tamarin per prove di convergenza. darkmatter-ios (Swift, creato il 25 maggio) è un client SwiftUI sostenuto da un xcframework MarmotKit UniFFI vendorizzato generato dal workspace Rust. darkmatter-android (Kotlin/Jetpack Compose, creato il 25 maggio) siede sugli stessi binding Rust. L’originale Flutter Whitenoise è stato contrassegnato come whitenoise-archive (“ARCHIVED: This was the original White Noise Flutter app”); un nuovo repo Dart whitenoise porta la linea Flutter attiva in parallelo.

Leggete questo come progresso iniziale verso un Marmot più affidabile, non come un pivot finito. Il README di darkmatter si etichetta come “Candidate Marmot v2 protocol draft, CGKA engine, and conformance workspace” e dice direttamente: “MDK remains the deployed Rust protocol implementation until this draft and engine are adopted.” All’interno del workspace, il crate cgka-engine è taggato 0.1.0, “single internal consumer, not semver-stable”. Ogni pagina di spec porta “Status: draft for internal review”. Tre stelle sul repo del workspace e zero sulle app iOS e Android confermano che il lavoro è pre-annuncio. Direzione, ambito e disciplina sono il segnale qui; la prontezza per la produzione non è la rivendicazione.

La bozza del protocollo rende concreti i delta da v1 a v2. L’estensione MLS monolitica marmot_group_data di MIP-01, che ha portato nome del gruppo, descrizione, pubkey admin, id di routing del gruppo Nostr, lista relay, dati immagine del gruppo e impostazioni di messaggi a scomparsa sotto un unico ombrello sin dall’inizio di Marmot, viene divisa in componenti applicativi versionati: marmot.group.profile.v1 per nome e descrizione, marmot.group.admin-policy.v1 per pubkey admin, marmot.transport.nostr.routing.v1 per il nostr_group_id casuale e la lista relay canonica, marmot.group.blossom.image.v1 per hash immagine, chiave di cifratura, nonce e chiave di upload, e marmot.group.message-retention.v1 per i secondi dei messaggi a scomparsa. Ciascun componente possiede i propri byte esatti e il proprio percorso di versionamento, così una funzionalità futura può revisionare un componente senza forzare il resto dello stato del gruppo a ripercorrere il consenso sulle estensioni MLS. Le credenziali MIP-00 ottengono anche un nuovo documento fondazionale account-identity-proof-v1.md, indicato come “new in v2 and breaking”. La prova di identità vive ora sulla propria superficie, separata dalla costruzione del KeyPackage.

I delta della libreria supportano il ridisegno della spec. cgka-engine è la nuova macchina a stati locale del gruppo: avvolge OpenMLS, possiede gli stati di epoch Stable, PendingPublish, Merging e Recovering, traduce gli intent in commit MLS, restituisce valori tipizzati IngestOutcome e GroupEvent per ogni inviluppo di trasporto in ingresso e rilascia esplicitamente nessun trasporto e nessuna persistenza. Un trait TransportPeeler separa Nostr dall’engine, e un trait StorageProvider separa SQLite (via storage-sqlite, backed da SQLCipher) dall’engine. L’MDK di oggi impacchetta tutto ciò insieme; dividere i layer consente a un engine di stare sotto un trasporto relay Nostr ora e i trasporti QUIC stream e broker anch’essi rilasciati più tardi, senza riscrivere il modello di convergenza. La convergenza stessa è documentata come distributed-convergence.md e provata in un modello Tamarin che copre selezione deterministica di branch, eleggibilità gated dalla policy, replay di anchor mantenuti, rifiuto di branch obsoleti, riordinamento della consegna, duplicazione, invalidazione dell’output applicativo, handoff welcome/commit, consumo di proposal e gating in uscita durante la sync. I property test Rust controllano poi che l’engine segua le stesse regole con oggetti OpenMLS reali e l’harness del simulatore. Il lavoro di affidabilità con metodi formali di questa portata è assente dallo stack Marmot attuale.

Entrambi i client nativi abbandonano Flutter per toolkit UI nativi della piattaforma. darkmatter-ios è puro SwiftUI con una Notification Service Extension che decifra i push wake MIP-05 sul dispositivo, vendorizza un pacchetto Swift MarmotKit generato dal workspace Rust e si registra sotto il bundle ID e l’app group dev.ipf.darkmatter. darkmatter-android è Kotlin e Jetpack Compose, con una build pilotata da just che produce un APK arm64-v8a firmato e legge endpoint di telemetria da local.properties. Il README Android dichiara direttamente il principio architetturale: “Dark Matter owns protocol data and stores it in SQLite. The Android app should render that data, manage Android platform behavior, and keep UI lifecycle state. The Android app should not become a second database for Dark Matter data.” Questo rispecchia la disciplina di confine che il README di cgka-engine impone nel layer Rust, applicata al layer UI.

I client nativi contano per Marmot perché la debolezza più citata del protocollo è stata l’affidabilità mobile in condizioni di consegna non uniformi: notification wake mancati, race di commit MLS durante fluttuazioni di rete, limiti di background-fetch che bloccano gli avanzamenti di epoch. SwiftUI e Compose danno ai client accesso diretto alle primitive di background-processing della piattaforma che Flutter raggiunge tramite un bridge plugin, e il percorso di binding UniFFI mantiene la logica di protocollo in un unico workspace Rust rilasciato come libreria statica su entrambe le piattaforme. La linea Flutter Whitenoise continua nel repo non archiviato whitenoise, quindi l’annuncio è additivo: una nuova linea di client nativi corre accanto all’app Flutter mentre la spec v2 converge. Il cutover di produzione da MDK o dall’attuale app Whitenoise attende che bozza, engine e client raggiungano release pronte per la produzione.

Chama v2.0.0 fino a v3.1.0: escrow P2P standalone in una settimana

Il client di escrow P2P Nostr-native introdotto nella Newsletter #25 alla v1.3.0 ha rilasciato diciassette release taggate negli ultimi sette giorni, terminando a v3.1.0 il 9 giugno con un ridisegno della UI della trade room e storefront per venditore. La scia di versioni racconta la storia: v2.0.0 è la base BREAKING, poi v2.0.1, v2.0.2 e v2.0.3 chiudono i gap della funding-rail Fedi WebView; v2.1.0, v2.2.0, v2.3.0 e v2.3.1 rafforzano il layer dell’arbitro; v2.4.0, v2.5.0 e v2.6.0 aggiungono superfici di self-custody e routing di community mondiale; v2.7.0, v2.8.0, v2.9.0 e v2.10.0 stratificano copia di chiavi in inglese semplice, applicazioni di gruppo, arbitraggio di deadline di disputa e reputazione. v3.0.0 lega il pacchetto insieme con notifiche di trade end-to-end, e v3.1.0 del 9 giugno ridisegna la schermata di trade attorno a una spina di progresso Reserved → Locked → Settled, card di azione con colori di ruolo e una classe di storefront per venditore (curated swap, loanbook e bill) che rilascia annunci.

Il pivot architetturale vive in v2.0.0. Il formato LOCK dell’escrow è cambiato così ogni share di uno split Shamir 2-di-3 è cifrata solo verso il suo detentore (sharePolicy holder-only-v1). L’ecash bearer della federazione non si ricostruisce più da un singolo partecipante da solo, chiudendo un percorso in cui una parte malevola con sia la propria share sia una share detenuta dalla federazione poteva completare il trade senza consenso. I client pre-2.0 falliscono in modo evidente con “can’t find your share”; il trade non può completarsi su un client obsoleto, e nessun fondo viene perso nel processo. Un lock v2.0 richiede che ogni parte sia su v2.x per essere regolata. v2.0.0 ha aggiunto anche storefront multi-unità e una vista Market solo-sats.

v2.1.0 ha introdotto la sostituzione dell’arbitro: la share dell’arbitro all’indice Shamir 2 è ora cifrata a un ordine di priorità deterministico sopra il pool di arbitri della community, così un arbitro assente può essere sostituito senza bloccare il trade. v2.2.0 ha provato che la sostituzione ha funzionato sul campo su un trade da ₿121 e ha aggiunto backup di healing-substitution. v2.3.0 ha chiuso l’ultimo gap di front-running dell’arbitro controllando l’appartenenza dell’arbitro dell’annuncio alla community al momento del lock, e v2.3.1 ha chiuso la race gemella in cui uno slot di arbitro auto-assegnato era un’anteprima finché il lock non li insediava.

Le superfici di self-custody sono arrivate in v2.4.0 (frase di recupero BIP-39 per il wallet ecash Fedimint, memorizzato cifrato su Nostr) e v2.5.0 (backup master nsec che possiede l’identità Nostr e il seed del wallet). v2.6.0 ha rifatto l’onboarding attorno a un picker di community globale così gli utenti in paesi senza una Chama locale sono instradati alla federazione più vicina; le build precedenti facevano rimbalzare l’utente senza fallback. v2.7.0 ha riscritto la schermata di chiave di recupero in inglese semplice (“the only key to your account and the money in it; Chama never sees it and can’t reset it; if you lose it, no one can get your account back”). v2.8.0 ha aggiunto applicazioni di gruppo, tema chiaro/scuro e due nuovi kind di evento (38120 roster, 38121 application). v2.9.0 ha cambiato la risoluzione di disputa alla deadline: i trade contestati che raggiungono la loro scadenza si risolvono ora per ruling dell’arbitro; il comportamento precedente rimborsava automaticamente. La release è marcata COORDINATED così tutte le parti in una disputa devono aggiornarsi. v2.10.0 ha aggiunto rating per-trade pollice su/pollice giù come nuovo kind di evento 38123.

v3.0.0 è la milestone in cui l’app smette di aver bisogno di una community di coordinamento per operare. Le notifiche di trade end-to-end pingano l’utente solo sulle transizioni di stato attuabili: la controparte ha lockato i sats, payout pronto per essere reclamato, la disputa richiede la decisione dell’utente come arbitro, o trade regolato o scaduto. Un toggle nella schermata Me accende o spegne le notifiche, e il prompt di permesso scatta solo quando il toggle è abilitato. La deduplicazione fire-once impedisce che un ricaricamento di stato inneschi una tempesta di alert. Un bug di guardrail wrong-chama è stato anche chiuso in PR #103, dove le versioni precedenti potevano contrassegnare un annuncio con l’etichetta di una chama ma la federazione di un’altra chama. I bundle desktop Windows e Linux sono rilasciati con la release; il dmg macOS è trattenuto finché la firma e la notarizzazione non arrivano.

Chama si unisce ora a Mostro e Shopstr come marketplace Nostr-native, distinta per architettura serverless, escrow Shamir 2-di-3 supportato da Fedimint, cifratura di share solo per il detentore e l’unica delle tre che rilascia un client desktop e mobile autonomo senza una community di coordinamento.

Coracle Hosting: servizio relay a pagamento più stack Caravel open-source

Il 3 giugno Hodlbod ha annunciato Coracle Hosting a hosting.coracle.social, un servizio di relay di community ospitato che accetta pagamenti lightning ricorrenti su NWC o carta. Il servizio è alimentato da Caravel, il frontend di billing e provisioning di Coracle, e zooid, un runtime di relay che ospita molti relay virtuali su una singola macchina. Entrambi sono open source sul gitea self-hosted di Coracle. Caravel è rilasciato con integrazione opzionale livekit e Blossom che gli operatori possono abilitare per relay. Un tier gratuito con limiti di conteggio membri consente agli operatori di valutare il servizio prima di impegnare dettagli di pagamento.

Hodlbod è schietto sul modello di business: monetizzare l’open source vendendo una versione ospitata di uno stack che chiunque altro può anche far girare. Il fossato competitivo è l’integrazione Flotilla, che è il prossimo passo pianificato. Flotilla possiede la superficie utente, così l’opzione ospitata servita dall’interno di Flotilla diventa il percorso di default per qualunque utente che preferisca infrastruttura gestita. Hodlbod ha offerto di aggiungere altri operatori Caravel al picker di hosting alternativo di Flotilla se si mettono in contatto, tenendo aperta la porta a un mercato di hosting federato.

Caravel si unisce a relay.tools come piattaforma pubblica di provisioning di relay Nostr con tier a pagamento per membro. relay.tools precede Caravel ed è rilasciato come il servizio dominante di creazione di relay oggi, con la propria directory di relay di community e flussi di join per membri o moderatori a pagamento. La caratteristica distintiva di Caravel è lo stack coordinato: il runtime del relay (zooid), il frontend di billing e provisioning (Caravel stesso) e il picker lato client (integrazione con Flotilla, ancora in corso) sono rilasciati come un unico design. L’altra caratteristica distintiva è la densità many-relay-per-process di zooid, in cui i relay dei clienti condividono un singolo processo host così l’operatore ammortizza i costi di hosting su molte piccole community. Questo è lo stesso argomento di densità che ha reso il web hosting condiviso praticabile all’inizio degli anni 2000, applicato al layer relay di Nostr.

Rilasci

Angor v0.2.29 e v0.2.30: default mainnet e test UAT funding a 3 utenti

Angor v0.2.29 del 4 giugno e v0.2.30 dell'8 giugno sono le due release di questa settimana per il protocollo decentralizzato di funding Bitcoin-e-Nostr. La modifica principale di v0.2.30 è PR #893, che porta la rete di default a mainnet. Angor è ancora rilasciato come release alpha unstable, ma lo switch al default mainnet segnala che il protocollo è oltre la fase solo testnet per i client desktop e mobile. v0.2.30 porta anche un flusso mobile di creazione di progetto single-tap con upload immagine e reset dello scroll (PR #889) e risolve una race condition in cui lo spinner di invoice lightning poteva bloccarsi (PR #890).

v0.2.29 ha aggiunto un test UAT end-to-end in PR #881 che copre 3-user send funds su 10 round con spese non confermate, il primo test di flusso di funding multi-utente nella suite di test Angor. La release ha aggiunto anche un piano di implementazione per una CLI Angor e un server MCP (PR #792), con miglioramenti CLI per il workflow di test MCP in PR #880. PR #885 di DavidGershony ha corretto un invoice lightning Boltz che usava la rete sbagliata dopo un cambio di rete a runtime, un bug che sarebbe emerso in produzione dopo il default mainnet di v0.2.30. Le impostazioni offrono ora una purga opzionale del file wallet di recupero durante il data wipe (PR #883).

Sprout v0.3.15: refresh del TTL dei canali effimeri e comandi slash ACP

Sprout v0.3.15, rilasciato il 10 giugno, è l’ottava release in una serie iniziata con v0.3.7 il 2 giugno. La Newsletter #25 ha coperto la serie da v0.3.1 a v0.3.6 con l’integrazione mesh-llm e il lavoro sulle sezioni di canale; da v0.3.7 a v0.3.15 sono a valle di quello, focalizzate su rifiniture e alcune aggiunte rivolte all’utente. La modifica più visibile all’utente è un refresh del TTL per canali effimeri in PR #902: quando un utente disarchivia un canale effimero, Sprout estende il time-to-live del canale così il disarchivio non ri-archivia immediatamente sotto il timer di scadenza originale. Gli emoji custom mobile arrivano in PR #906 insieme a un redesign delle impostazioni, e i conteggi delle reazioni ora animano al cambiamento (PR #904).

PR #905 corregge un gap di lunga data in cui i display name multi-parola si rompevano e l’estrazione di mention NIP-27 nostr:npub cadeva silenziosamente. Una UI di team basata su directory per desktop è rilasciata in PR #912 con comandi install, sync e reveal. I comandi slash ora passano ai connector ACP in PR #919, consentendo a Sprout di inoltrare comandi in stile /help direttamente ai runtime degli agenti mentre la UI di Sprout resta fuori dal percorso.

Wisp v1.1.1: integrazione wallet Spark e guardia contro il paste di nsec

Wisp v1.1.1, rilasciato il 5 giugno, porta una schermata Connect wallet a due livelli con sub-schermata Spark in PR #548 e parità dashboard con la UI wallet iOS in PR #549. La release include una guardia contro il paste di nsec a livello di sistema che rileva un paste con prefisso nsec1 ovunque nell’app e blocca il campo dall’accettarlo, chiudendo uno degli errori più citati nella UX Nostr. Il login QR-scan più una modalità watch-only per npub e nprofile è rilasciato in PR #552, consentendo a un utente di sfogliare un profilo in sola lettura. I messaggi zap ora si rendono come mini-post nel drawer di engagement (PR #559) così le note zap portano il loro testo insieme all’importo in sat. Un filtro web-of-trust sulle risposte al thread arriva in PR #583, consentendo agli utenti di nascondere lo spam di risposte da account fuori dal loro grafo di follow.

Nostria v3.1.46 e nospeak 1.1.3: rifacimento delle notifiche e restart ICE

Nostria v3.1.46 del 7 giugno chiude una serie di tre release che ha rifatto il contatore delle notifiche per contare solo le nuove notifiche dalla vista precedente, eliminando un’inflazione di lunga data in cui caricare notifiche più vecchie scrollando faceva salire il conteggio del badge. Nostria v3.1.45 ha corretto un bug di split-payment che colpiva pagamenti lightning e QR-code e ha abbandonato una UI traslucida precedentemente pianificata come non fattibile sul compositor Android.

nospeak v1.1.3 del 4 giugno aggiunge il restart ICE su stato FAILED per chiamate voce 1-on-1. Il comportamento WebRTC standard scarta una chiamata quando i candidati ICE vanno in timeout senza un percorso alternativo; il percorso di restart ICE rinegozia i candidati così la chiamata recupera da cambi transitori di NAT o rete. Le chiamate Android ora tengono lo schermo acceso durante le videochiamate.

Modifiche non rilasciate

Amethyst: 41 PR che continuano la traccia NIP-32 / NIP-F4 / Tor

Amethyst ha mergiato 41 PR questa settimana senza tagliare una release tag, sopra le 52 PR della scorsa settimana e il lavoro sull’etichettatura hashtag NIP-32 e podcast NIP-F4 trattato nella Newsletter #25. La branch attiva continua ad accumulare funzionalità per la prossima release taggata, stratificando rifiniture sulle aggiunte principali della scorsa settimana: scoperta di labeler hashtag, schermata podcast, tracce musicali e playlist, watchdog di auto-heal Tor, signer effimeri per upload anonimi e zap onchain con filtraggio NIP-05. Il throughput di PR di Amethyst resta il più alto di qualunque client Nostr, e la coda non rilasciata è la roadmap de-facto per ciò che altri client Nostr Android dovranno eguagliare.

Damus: tracciamento dei relay dai messaggi OK e changelog v1.17

Damus PR #3786, mergiata il 3 giugno, aggiunge i messaggi OK riusciti da un relay alla lista dei post-relay. Le build precedenti di Damus popolavano la lista dei relay visti solo quando ricevevano un messaggio generico dal relay, il che significava che un relay che confermava il post ma non consegnava eventi era invisibile all’utente. Il cambiamento conta per gli utenti che vogliono confermare che il loro post sia arrivato sul loro relay outbox preferito. PR #3796 corregge un ciclo AttributeGraph su Profile View, e PR #3725 porta il changelog v1.17 in vista della prossima release taggata.

Shopstr: dual-publishing NIP-34

Il repo shopstr su ngit di Shopstr è stato annunciato su Nostr questa settimana come repo git NIP-34, unendosi ai repo tracciati di ngit. Il repo GitHub del client shop resta la superficie primaria di sviluppo; l’annuncio NIP-34 rende disponibile un percorso parallelo di collaborazione git-over-Nostr. Questo è il secondo grande progetto marketplace Nostr a dual-publish su NIP-34 dopo Mostro, e continua la migrazione graduale dei metadati di progetto sul trasporto git di Nostr.

Hermes-Marmot: gateway di agente AI su MLS

hermes-marmot, un plugin per l’Hermes Agent, connette la superficie di messaggistica di un agente AI ai gruppi Marmot (MLS-over-Nostr) usando mdk-python, i binding Python al Marmot Development Kit Rust. Il plugin consente a un utente di DMare un agente AI da qualunque client Nostr che parla messaggi MLS di kind 445, incluso Whitenoise. I DM in ingresso usano l’unwrapping gift-wrap NIP-59 tramite i binding Python di nostr-sdk, e i welcome in ingresso fluiscono attraverso UnwrappedGift.from_gift_wrap a mdk.process_welcome e mdk.accept_welcome. Il controllo di accesso passa attraverso MARMOT_ALLOWED_USERS (una allowlist di npub separata da virgole) o MARMOT_ALLOW_ALL_USERS=true per accesso di sviluppo aperto.

Il repo è nuovo (ultimo aggiornamento 27 maggio) e piccolo. La sua importanza è architetturale: è il primo ponte pubblico fra un runtime di agente LLM e un canale di messaggistica Nostr cifrato con MLS, e il primo uso in produzione di mdk-python oltre a Whitenoise stesso. Il pattern punta verso comunicazione agente-a-agente in cui entrambi gli endpoint detengono chiavi MLS e il relay vede solo ciphertext.

Aggiornamenti NIP e lavoro di spec di protocollo

NIP-67 hint di completezza EOSE (PR #2317) mergiato

PR #2317 di mattn mergiata il 6 giugno, aggiungendo NIP-67 al protocollo. Il NIP estende il messaggio relay EOSE con un terzo elemento opzionale: ["EOSE", <subscription_id>, "finish"] segnala che ogni evento memorizzato che corrisponde al filtro è stato consegnato, mentre un nudo ["EOSE", <subscription_id>] non porta alcuna dichiarazione di completezza. Un relay che omette l’hint sta dicendo al client che potrebbe esserci di più; un relay che omette la pubblicità NIP-67 in NIP-11 mantiene il comportamento di oggi sotto l’euristica legacy esistente. Il cambiamento è backward compatible in entrambe le direzioni: i client legacy ignorano l’elemento finale dell’array e i relay legacy lo omettono.

La motivazione nella spec mergiata è duplice. Primo, perdita silenziosa di dati: un client chiede le ultime 500 note contro un relay con un cap interno di 300 eventi, il relay restituisce 300 eventi, e il client (usando l’euristica standard received < limit) conclude che il risultato è completo. La 201esima fino alla N-esima nota più vecchia che corrisponde restano sul relay non lette, con il client cieco a quel fatto. Secondo, round-trip sprecati obbligatoriamente: quando un relay cappa le risposte a 300 eventi, qualunque sottoscrizione che esaurisce il cap richiede un secondo REQ con until=<oldest_created_at> puramente per confermare il completamento, anche quando il filtro corrisponde esattamente a 300 eventi. Entrambe le modalità di fallimento sono pagate da ogni client su ogni sottoscrizione che esaurisce il cap. L’hint "finish" è una stringa opzionale su un messaggio esistente ed elimina entrambi i costi.

Estensione autocomplete NIP-50 (PR #2357) mergiata

PR #2357 di Alex Gleason mergiata il 6 giugno, aggiungendo un token autocomplete:true/false alla ricerca NIP-50. L’estensione consente a un client di marcare una query come un lookup typeahead così il relay usa prefix matching, con la full-text search come default per query senza il token. Il relay di Ditto lo implementa per follow pack, lista e qualunque evento con un tag title, restituendo match contro il prefisso del titolo; il percorso di ricerca di default esegue lo scoring full-text. Senza questo token, le UI stile autocomplete non avevano modo di comunicare l’intento di prefix search e i relay dovevano indovinare dalla forma della query. Il token è un hint per-ricerca, non una capability a livello relay, così un relay può implementarlo per una classe di eventi (titoli) senza rivendicare supporto autocomplete generale.

NIP-GART alert di emergenza e broadcast di posizione (PR #2374)

PR #2374 di disinqa, aperta il 9 giugno, definisce un wire format a tutela della privacy su Nostr per alert di emergenza e broadcast di posizione indirizzati a un gruppo di destinatari fidati. L’obiettivo di design dichiarato è nascondere l’identità del mittente, l’appartenenza al gruppo e il payload agli operatori del relay mantenendo gli eventi replay-safe e verificabili tramite firma end-to-end. Il numero NIP è ancora TBD, la proposta è in bozza iniziale. Il caso d’uso è il pattern standard di alert di emergenza: un utente sotto minaccia broadcasta un ping di posizione che solo un gruppo pre-condiviso di contatti fidati può decifrare, con il relay cieco a mittente, set di destinatari e payload. I dettagli del wire format vivono nella PR e probabilmente evolveranno mentre i manutentori revisionano.

Metodo logout NIP-46 (PR #2373)

PR #2373 di hzrd149, aperta l'8 giugno, aggiunge un metodo logout a NIP-46 così un client può dire esplicitamente a un bunker che la sessione è terminata. Finora, l’unico modo per terminare una sessione bunker era aspettare il timeout della sessione o smettere di usare la connessione, entrambi i quali lasciano il bunker a detenere stato di sessione per un client che è scomparso. La proposta è breve (un nuovo metodo) ed è il tipo di modifica di manutenzione che rende le integrazioni bunker a lungo termine più pulite.

Proposta ibrida relay-P2P NIP-95 circolata come long-form

Una specifica NIP-95 long-form è circolata come post kind:30023 dall’npub 91bea5cd9361504c409aaf459516988f68a2fcd482762fd969a7cdc71df4451c il 4 giugno sotto il titolo Protocolo Híbrido Relay-P2P via WebRTC. Il documento in lingua portoghese definisce un protocollo relay ibrido peer-to-peer in cui i client Nostr si connettono l’uno all’altro direttamente via WebRTC per la messaggistica live continuando a usare i relay per il recupero di eventi memorizzati e la consegna offline. L’autore ha esplicitamente inquadrato la spec come “LLM-ready”, fornendo definizioni di messaggi, flussi logici, schemi di dati e regole di stato a un livello di dettaglio che lascia a un modello AI la possibilità di generare codice client o server funzionante. La proposta non è ancora arrivata come PR NIP; la circolazione tramite kind:30023 è il precursore usuale a una pull request formale su nostr-protocol/nips.

NIP-44 v3 prende un secondo signer: Clave porta la spec

Il rollout di NIP-44 v3 di Amber v6.2.0 della scorsa settimana è arrivato prima di qualunque PR NIP mergiata, lasciando v3 come estensione specifica di Amber che altri client dovevano rispecchiare per interoperare. Quell’inquadratura a singola implementazione è cambiata questa settimana. Clave, il remote signer iOS NIP-46 basato su push, ha portato un porting indipendente di NIP-44 v3 il 3 e 4 giugno attraverso otto commit. Le primitive crittografiche sono rilasciate in tre commit: layer di chiavi HKDF + ECDH, l’algoritmo di padding v3 e un’API pubblica di alto livello più Context di cifratura. Sopra questi, la superficie NIP-46 segue in wiring del dispatch RPC dentro LightSigner e uno schema PendingRequest che porta il contesto v3 (kind più scope), così il signer può registrare per quale kind di evento e caso d’uso il payload v3 è stato approvato.

Clave diverge da Amber sulla superficie rivolta all’utente. Uno schema di grant di permesso con tier di sensibilità consente agli utenti di garantire la cifratura v3 per un particolare kind di evento e scope a un livello di sensibilità scelto. Al primo incontro, prompt di approvazione consapevoli del contesto v3 con una card di explainer una-tantum introducono v3 agli utenti. Il lavoro è in main ed è collegato al progetto Xcode ma non è rilasciato; la build taggata più recente è v0.2.0-build79 del 12 maggio.

Due implementazioni indipendenti portano NIP-44 v3 in percorsi di produzione prima che la PR NIPs sia mergiata, il che rafforza il caso per il wire format sottostante che la PR di protocollo formalizzerà. Il testing di interop cross-implementazione diventa ora il percorso alla convergenza della spec, con la superficie di approvazione Android di Amber e il modello di tier di sensibilità iOS di Clave come i due punti di riferimento. Altri remote signer che collegano v3 (il noauth di nsec.app è stato dormiente da maggio 2025, e altri bunker non hanno annunciato lavoro su v3) restringerebbero ulteriormente il consenso.

Attività NIP-34: Iris adotta lo stack con un nuovo trasporto hashtree

Iris ha pubblicato annunci di repo NIP-34 per hashtree l'8 giugno e iris-apps, iris-drive e iris-chat-rs il 9 giugno, pubblicizzando URL di clone sotto un nuovo schema htree:// servito da wss://temp.iris.to. Il trasporto hashtree è un’alternativa content-addressed ai clone instradati via GRASP, e questi quattro annunci sono i suoi primi usi pubblici. I repo portano descrizioni vuote e i dettagli architetturali stanno ancora emergendo, ma la scelta di pubblicare tramite annuncio NIP-34 (sopra un manifest Iris-interno custom) segnala che Iris si sta impegnando allo stack più ampio git-over-Nostr NIP-34.

NIP deep dive: NIP-67 (EOSE Completeness Hint)

NIP-67 chiude uno dei gap di correttezza più antichi di NIP-01. La spec originale definisce EOSE come il confine tra eventi memorizzati e eventi di sottoscrizione live per un REQ, ma non ha mai specificato se il relay avesse finito di consegnare tutti i match memorizzati o si fosse fermato a metà a causa di un cap interno. Ogni relay impone un cap per-sottoscrizione (comunemente da 300 a 1000 eventi) indipendente dal limit del client, e i client non hanno avuto modo di osservare quel cap.

Il workaround standard era confrontare il conteggio ricevuto con il limit richiesto. Se received < limit, trattare il risultato come completo; altrimenti paginare con until=<oldest_created_at>. Entrambi i branch sono rotti. Il branch received < limit tronca silenziosamente: un client che chiede 500 note contro un relay cappato a 300 vede 300 eventi, conclude che il risultato è completo perché 300 < 500, e non recupera mai il resto. Gli eventi trattenuti sul relay non possono segnalare “altro disponibile” attraverso alcun messaggio esistente. La paginazione come secondo branch è sprecona: un filtro che corrisponde esattamente al cap richiede un secondo REQ per confermare la completezza, restituendo zero eventi mentre consuma una scansione di filtro completa sul relay.

Il fix di NIP-67 è una stringa opzionale sul messaggio EOSE:

["EOSE", "<sub_id>", "finish"]   // esplicito: tutti gli eventi memorizzati consegnati
["EOSE", "<sub_id>"]              // nessuna dichiarazione di completezza

Un relay che pubblicizza NIP-67 nei supported_nips di NIP-11 ed emette un EOSE nudo sta dicendo al client che c’è di più. Un relay che omette la pubblicità mantiene il comportamento di oggi, e il client ricade sull’euristica esistente. I client legacy ignorano l’elemento finale dell’array. La compatibilità all’indietro tiene in entrambe le direzioni, senza nuovi verbi o kind di evento.

Ciò che rende NIP-67 degno di esame è lo scope che deliberatamente restringe. La spec non definisce cursore o token di paginazione, quindi la paginazione basata su until resta il meccanismo. I cap dei relay restano dove sono, e il NIP non richiede alcuna esposizione di essi. NIP-67 preserva il significato di EOSE come confine memorizzato-a-live e aggiunge solo un segnale sì-o-no al confine: “Ho di più per te” contro “questo è tutto”. Questa superficie minima è perché la PR è stata mergiata dopo un periodo di review relativamente breve per un’estensione di NIP-01, e perché mattn nota esplicitamente nella PR che è stata usata la traduzione AI per il testo inglese. Il cambiamento è abbastanza piccolo che l’incertezza della traduzione non conta.

Esempio di scambio consapevole di NIP-67 tra un client e un relay che impone il cap. Pubblicità NIP-11 dal relay:

{
  "id": "a5f87fe2d4c8b9a0e3f1c4d5e6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f",
  "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
  "created_at": 1781136000,
  "kind": 11,
  "tags": [],
  "content": "{\"supported_nips\":[1,11,50,67]}",
  "sig": "f1e2d3c4b5a6978869504132c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f80192a3b4c5d6e7f80192a3b4c5d6e7f80192a3b4c5d6e7f80192a3b4c5d6e7f80192a3b4c5"
}

Lo scambio a livello di wire che segue:

→ ["REQ", "abc", {"kinds":[1],"limit":500}]
← [...300 EVENT messages...]
← ["EOSE", "abc"]               // no "finish": cap raggiunto, altro disponibile
→ ["REQ", "def", {"kinds":[1],"limit":300,"until":1780900000}]
← [...178 EVENT messages...]
← ["EOSE", "def", "finish"]     // completo esplicito

La risposta di 178 eventi prima avrebbe innescato una terza REQ per confermare il completamento. Con NIP-67 il client si ferma lì.

NIP-67 è notabile anche come emendamento a NIP-01 che arriva con raro consenso. La maggior parte dei cambiamenti a NIP-01 attrae lunghi thread di dibattito perché la superficie minuscola del protocollo è portante per ogni implementazione. NIP-67 è stato mergiato dopo un periodo di review esteso (all’incirca sette settimane dall’apertura al merge), suggerendo che quando un cambio NIP-01 è abbastanza piccolo e la modalità di fallimento è abbastanza concreta (perdita silenziosa di dati, round trip sprecato obbligatorio), i manutentori del protocollo sono disposti a estendere il vocabolario dei messaggi core.

NIP deep dive: NIP-50 (Ricerca)

NIP-50 definisce il campo di filtro search nei messaggi REQ, consentendo ai client di chiedere a un relay di filtrare eventi tramite match full-text contro una stringa di query. La spec base mergiata è deliberatamente minima: il campo search è una stringa, ciascun relay decide la propria semantica di ricerca (quali campi sono indicizzati, come funziona lo scoring, se si applica lo stemming), e i relay pubblicizzano il supporto NIP-50 nel loro documento NIP-11. I client controllano l’algoritmo di ricerca solo tramite la stringa di query stessa.

Questo minimalismo è sia la forza sia il vincolo di NIP-50. La forza è che qualunque relay può implementare la ricerca a qualunque livello di qualità: una scansione di sottostringa di base soddisfa la spec, e un relay che esegue Elasticsearch o Meilisearch la soddisfa ugualmente. Il vincolo è che i client mancano di un modo per esprimere l’intento di ricerca. Una UI typeahead di mention di profilo vuole prefix matching contro i display name; una ricerca di contenuto full-text vuole scoring full-text tokenizzato attraverso il corpo della nota. Lo stesso campo search porta entrambi, e il relay deve indovinare dalla forma della query.

PR #2357 aggiunge il primo token di estensione NIP-50: autocomplete:true o autocomplete:false incorporato nella query di ricerca segnala quale modalità il client vuole. Il relay di Ditto implementa il token per follow pack, lista e qualunque evento con un tag title, passando al prefix matching quando autocomplete:true è presente. Il token vive inline nella query (i campi di filtro separati restano intoccati), così viaggia con la stringa di ricerca e non richiede alcun bump di wire protocol:

search: "fiat autocomplete:true"

Hint in forma di token come questo sono il modo in cui NIP-50 ha sempre gestito dialetti relay-specifici. I relay supportavano già token come language:en e domain:example.com. Ciascuno resta relay-specifico, con ciascun relay che documenta il proprio dialetto. La PR #2357 di NIP-50 eleva autocomplete da un token relay-privato a uno benedetto dalla spec, aprendo la strada a ricerca typeahead-aware attraverso i relay.

Esempio di REQ NIP-50 con il token autocomplete, mirato a un relay che indicizza i titoli di profilo di kind 0:

{
  "id": "b7c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081a2b3c4d5e6f70819a2b3c4d5",
  "pubkey": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
  "created_at": 1781136000,
  "kind": 1,
  "tags": [
    ["client", "example-mention-picker"]
  ],
  "content": "Sent search: kinds=[0], search=\"fiat autocomplete:true\", limit=10",
  "sig": "12d3e4f5061728394a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081a2b3c4d5e6f70819a2b3c4d5e6f7081a2b3c4d5e6f708192"
}

L’effettivo REQ a livello di wire:

["REQ", "mention-picker", {"kinds":[0],"search":"fiat autocomplete:true","limit":10}]

Un relay che non riconosce il token tratta autocomplete:true come parte della stringa di ricerca letterale e ricade sul matching full-text, restituendo risultati corretti (se classificati diversamente). La degradazione graziosa rende il token sicuro da includere incondizionatamente per client che preferiscono il prefix matching quando disponibile.

La prossima probabile estensione NIP-50 è il controllo di ranking per-kind: un hint che dice “classifica per created_at decrescente” contro il default relevance score. Diversi relay accettano già sort:newest come token relay-privato, e lo stesso percorso di elevazione che ha portato autocomplete nella spec si applica. La ricerca resta una delle poche primitive Nostr dove i relay competono sulla qualità del risultato; l’affidabilità della consegna è la stessa attraverso tutti i relay conformi. Token incrementali consentono ai client di sfruttare quella competizione di qualità senza forzare i relay a rilasciare una nuova spec pesante.