Die Marmot-Protocol-Organisation öffnet drei neue Repos für einen v2-Protokollentwurf und eine native Client-Linie: ein Rust-Workspace namens darkmatter, eine SwiftUI iOS-App darkmatter-ios und eine Kotlin/Compose Android-App darkmatter-android. Das ursprüngliche Flutter-Whitenoise wird archiviert. Chama komprimiert siebzehn Releases in eine Woche und überschreitet bei v3.0.0 die Standalone-App-Linie, bevor v3.1.0 eine vollständige Trade-Room-UI-Neugestaltung und Per-Verkäufer-Storefronts liefert, aufbauend auf Holder-only Shamir-Shares, Arbiter-Substitution, weltweitem Community-Routing und End-to-End-Trade-Benachrichtigungen. Coracle startet einen kostenpflichtigen Hosted-Relay-Dienst, gestützt auf den Open-Source-Caravel- und zooid-Stack, mit tiefer Flotilla-Integration in Planung. Angor stellt in v0.2.30 standardmäßig auf mainnet um und landet einen 3-User-UAT-Funding-Test in v0.2.29. Amethyst landet 41 unveröffentlichte PRs, die die NIP-32-/NIP-F4-/Tor-Arbeit der letzten Woche fortsetzen. NIP-67 (EOSE Completeness Hint) und NIP-50 Autocomplete werden gemerged und schließen zwei langbestehende Korrektheitslücken im Kern-Relay-Protokoll. NIP-GART schlägt ein datenschutzfreundliches Wire-Format für Notfallwarnungen vor, und NIP-46 erhält eine Logout-Methode.

Top-Stories

Marmot v2 (Dark Matter): Protokoll-Neuentwurf, native Clients, archivierte Flutter-App

Drei neue Repos tauchten diese Woche unter der marmot-protocol GitHub-Organisation auf und bilden zusammen die frühe Fortschrittsform eines Marmot-v2-Protokollentwurfs und einer nativen Client-Linie, die die Flutter-App-Linie ablöst. darkmatter (Rust, erstellt am 13. Mai, vierunddreißig Commits in den letzten sieben Tagen) hält den v2-Protokollentwurf in spec/, eine OpenMLS-basierte CGKA-Engine in crates/cgka-engine, einen Konformanz-Simulator mit Property-Tests und ein formales Tamarin-Modell für Konvergenzbeweise. darkmatter-ios (Swift, erstellt am 25. Mai) ist ein SwiftUI-Client, gestützt auf ein aus dem Rust-Workspace generiertes MarmotKit-UniFFI-xcframework. darkmatter-android (Kotlin/Jetpack Compose, erstellt am 25. Mai) sitzt auf denselben Rust-Bindings. Das ursprüngliche Flutter-Whitenoise wurde als whitenoise-archive markiert (“ARCHIVED: This was the original White Noise Flutter app”); ein neues whitenoise Dart-Repo trägt die aktive Flutter-Linie parallel weiter.

Lies das als frühen Fortschritt in Richtung eines zuverlässigeren Marmot, nicht als abgeschlossenen Pivot. Das darkmatter-README bezeichnet sich selbst als “Candidate Marmot v2 protocol draft, CGKA engine, and conformance workspace” und sagt direkt: “MDK remains the deployed Rust protocol implementation until this draft and engine are adopted.” Innerhalb des Workspaces ist der cgka-engine-Crate mit 0.1.0 getaggt, “single internal consumer, not semver-stable.” Jede Spec-Seite trägt “Status: draft for internal review”. Drei Sterne auf dem Workspace-Repo und null auf den iOS- und Android-Apps bestätigen, dass die Arbeit vor der Ankündigung steht. Richtung, Umfang und Disziplin sind hier das Signal; Produktionsreife ist nicht der Anspruch.

Der Protokollentwurf macht die v1-zu-v2-Deltas konkret. MIP-01s monolithische marmot_group_data MLS-Erweiterung, die seit Beginn von Marmot Gruppenname, Beschreibung, Admin-pubkeys, Nostr-Group-Routing-ID, Relay-Liste, Gruppenbilddaten und Disappearing-Message-Einstellungen unter einem Dach getragen hat, wird in versionierte App-Komponenten aufgeteilt: marmot.group.profile.v1 für Name und Beschreibung, marmot.group.admin-policy.v1 für Admin-pubkeys, marmot.transport.nostr.routing.v1 für die zufällige nostr_group_id und die kanonische Relay-Liste, marmot.group.blossom.image.v1 für Bild-Hash, Verschlüsselungsschlüssel, Nonce und Upload-Schlüssel und marmot.group.message-retention.v1 für Disappearing-Message-Sekunden. Jede Komponente besitzt ihre exakten Bytes und ihren eigenen Versionierungspfad, sodass ein zukünftiges Feature eine Komponente überarbeiten kann, ohne den Rest des Gruppenzustands zu zwingen, MLS-Extension-Konsens noch einmal zu durchlaufen. MIP-00-Credentials erhalten außerdem ein neues Foundation-Dokument account-identity-proof-v1.md, hervorgehoben als “new in v2 and breaking”. Der Identitätsbeweis lebt jetzt auf seiner eigenen Oberfläche, getrennt von der KeyPackage-Konstruktion.

Die Bibliotheks-Deltas stützen die Spec-Überarbeitung. cgka-engine ist die neue lokale Gruppen-State-Machine: sie wrappt OpenMLS, besitzt die Epoch-Zustände Stable, PendingPublish, Merging und Recovering, übersetzt Absichten in MLS-Commits, gibt typisierte IngestOutcome- und GroupEvent-Werte für jede eingehende Transport-Hülle zurück und liefert explizit keinen Transport und keine Persistenz. Ein TransportPeeler-Trait trennt Nostr von der Engine, und ein StorageProvider-Trait trennt SQLite (über storage-sqlite, SQLCipher-basiert) von der Engine. Heutiges MDK packt all das zusammen; das Aufteilen der Schichten lässt eine Engine jetzt unter einem Nostr-Relay-Transport sitzen und später auch unter den ebenfalls ausgelieferten QUIC-Stream- und Broker-Transports, ohne Neufassung des Konvergenzmodells. Die Konvergenz selbst ist als distributed-convergence.md dokumentiert und in einem Tamarin-Modell bewiesen, das deterministische Branch-Auswahl, policy-gated Eligibility, Retained-Anchor-Replay, Stale-Branch-Rejection, Delivery-Reordering, Duplikation, App-Output-Invalidation, Welcome/Commit-Handoff, Proposal-Konsum und Outbound-Gating während Sync abdeckt. Rust-Property-Tests prüfen dann, dass die Engine dieselben Regeln mit echten OpenMLS-Objekten und dem Simulator-Harness einhält. Formal-Methods-Zuverlässigkeitsarbeit dieses Umfangs fehlt im aktuellen Marmot-Stack.

Beide nativen Clients verwerfen Flutter zugunsten plattformnativer UI-Toolkits. darkmatter-ios ist reines SwiftUI mit einer Notification Service Extension, die MIP-05-Push-Wakes auf dem Gerät entschlüsselt, vendort ein generiertes MarmotKit Swift-Paket, das aus dem Rust-Workspace gebaut wurde, und registriert sich unter der dev.ipf.darkmatter Bundle-ID und App-Gruppe. darkmatter-android ist Kotlin und Jetpack Compose, mit einem just-getriebenen Build, der ein signiertes arm64-v8a APK erzeugt und Telemetrie-Endpunkte aus local.properties liest. Das Android-README formuliert das architektonische Prinzip direkt: “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.” Das spiegelt die Grenz-Disziplin, die das cgka-engine-README in der Rust-Schicht durchsetzt, angewendet auf die UI-Schicht.

Native Clients sind für Marmot wichtig, weil die meistgenannte Schwäche des Protokolls die mobile Zuverlässigkeit unter ungleichmäßigen Zustellbedingungen war: verpasste Deadline-Notification-Wakes, MLS-Commit-Races während Netzwerk-Flaps, Background-Fetch-Limits, die Epoch-Fortschritte stranden lassen. SwiftUI und Compose geben den Clients direkten Zugriff auf plattformnahe Hintergrundverarbeitungs-Primitive, die Flutter durch eine Plugin-Brücke erreicht, und der UniFFI-Binding-Pfad hält Protokoll-Logik in einem Rust-Workspace, der auf beiden Plattformen als statische Bibliothek ausgeliefert wird. Die Flutter-Whitenoise-Linie setzt sich im nicht archivierten whitenoise-Repo fort, sodass die Ankündigung additiv ist: eine neue native Client-Linie läuft parallel zur Flutter-App, während die v2-Spec konvergiert. Der Produktions-Cutover von MDK oder der aktuellen Whitenoise-App wartet, bis Entwurf, Engine und Clients produktionsreife Releases erreichen.

Chama v2.0.0 bis v3.1.0: Standalone-P2P-Escrow in einer Woche

Der in Newsletter #25 bei v1.3.0 eingeführte Nostr-native P2P-Escrow-Client hat in den letzten sieben Tagen siebzehn getaggte Releases ausgeliefert und endete am 9. Juni bei v3.1.0 mit einer Trade-Room-UI-Neugestaltung und Per-Verkäufer-Storefronts. Die Versionsspur erzählt die Geschichte: v2.0.0 ist die BREAKING-Basis, dann schließen v2.0.1, v2.0.2 und v2.0.3 Fedi-WebView-Funding-Rail-Lücken; v2.1.0, v2.2.0, v2.3.0 und v2.3.1 härten die Arbiter-Schicht; v2.4.0, v2.5.0 und v2.6.0 fügen Self-Custody-Oberflächen und weltweites Community-Routing hinzu; v2.7.0, v2.8.0, v2.9.0 und v2.10.0 schichten Plain-English-Key-Copy, Gruppen-Anwendungen, Dispute-Deadline-Arbitrierung und Reputation ein. v3.0.0 verbindet das Paket mit End-to-End-Trade-Benachrichtigungen, und v3.1.0 am 9. Juni zeichnet den Trade-Screen rund um ein Reserved → Locked → Settled Fortschritts-Rückgrat, rollen-farbige Aktions-Karten und eine Per-Verkäufer-Storefront-Listing-Klasse (kuratierte Swaps, Loanbooks und Rechnungen) neu.

Der architektonische Pivot lebt in v2.0.0. Das Escrow-LOCK-Format hat sich geändert, sodass jeder Share eines 2-von-3 Shamir-Splits nur an seinen Holder verschlüsselt wird (sharePolicy holder-only-v1). Das Bearer-Ecash der Föderation lässt sich nicht mehr von einem einzelnen Teilnehmer allein rekonstruieren, was einen Pfad schließt, auf dem eine böswillige Partei mit ihrem eigenen Share und einem Föderations-gehaltenen Share den Trade ohne Zustimmung abschließen konnte. Pre-2.0-Clients scheitern laut mit “can’t find your share”; der Trade kann auf einem veralteten Client nicht abgeschlossen werden, und im Prozess gehen keine Gelder verloren. Ein v2.0-Lock erfordert, dass jede Partei auf v2.x abwickelt. v2.0.0 fügte außerdem Multi-Unit-Storefronts und eine Sats-only Market-Ansicht hinzu.

v2.1.0 führte die Arbiter-Substitution ein: der Arbiter-Share bei Shamir-Index 2 wird jetzt an eine deterministische Prioritätsordnung über den Community-Arbiter-Pool verschlüsselt, sodass ein abwesender Arbiter ersetzt werden kann, ohne den Trade zu stranden. v2.2.0 bewies, dass die Substitution in freier Wildbahn bei einem ₿121-Trade funktioniert, und fügte Healing-Substitution-Backups hinzu. v2.3.0 schloss die letzte Arbiter-Front-Running-Lücke, indem die Listing-Arbiter-Community-Mitgliedschaft zur Lock-Zeit geprüft wird, und v2.3.1 schloss den Geschwister-Race, bei dem ein automatisch zugewiesener Arbiter-Slot eine Vorschau war, bis der Lock ihn einsetzte.

Die Self-Custody-Oberflächen kamen in v2.4.0 (BIP-39 Recovery-Phrase für die Fedimint-Ecash-Wallet, verschlüsselt auf Nostr gespeichert) und v2.5.0 (Master-nsec-Backup, das die Nostr-Identität und den Wallet-Seed besitzt). v2.6.0 überarbeitete das Onboarding rund um einen globalen Community-Picker, sodass Nutzer in Ländern ohne lokales Chama zur nächstgelegenen Föderation geleitet werden; frühere Builds warfen den Nutzer ohne Fallback zurück. v2.7.0 schrieb den Recovery-Key-Screen in Plain English um (“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 fügte Gruppen-Anwendungen, Dark/Light-Theming und zwei neue Event-kinds hinzu (38120 Roster, 38121 Application). v2.9.0 änderte die Dispute-Auflösung bei Deadline: umkämpfte Trades, die ihren Ablauf erreichen, werden jetzt per Arbiter-Urteil aufgelöst; vorheriges Verhalten war Auto-Refund. Das Release ist als COORDINATED markiert, sodass alle Parteien in einer Auseinandersetzung updaten müssen. v2.10.0 fügte Per-Trade Daumen-hoch/Daumen-runter-Bewertungen als neues Event-kind 38123 hinzu.

v3.0.0 ist der Meilenstein, ab dem die App keine koordinierende Community mehr zum Betrieb braucht. End-to-End-Trade-Benachrichtigungen pingen den Nutzer nur bei handlungsrelevanten Zustandsübergängen: die Gegenpartei hat die Sats gesperrt, Auszahlung bereit zur Beanspruchung, Streit erfordert das Urteil des Nutzers als Arbiter, oder Trade abgeschlossen oder abgelaufen. Ein Toggle im Me-Screen schaltet Benachrichtigungen an oder aus, und der Berechtigungs-Prompt feuert nur, wenn der Toggle aktiviert ist. Die Fire-once-Dedup verhindert, dass ein Zustandsreload einen Alert-Sturm auslöst. Ein Wrong-Chama-Guardrail-Bug wurde ebenfalls in PR #103 geschlossen, wo frühere Versionen ein Listing mit dem Label eines Chamas, aber der Föderation eines anderen Chamas stempeln konnten. Windows- und Linux-Desktop-Bundles werden mit dem Release ausgeliefert; das macOS-dmg wird zurückgehalten, bis Signierung und Notarisierung landen.

Chama gesellt sich jetzt zu Mostro und Shopstr als Nostr-nativer Marktplatz, unterschieden durch serverlose Architektur, Fedimint-gestützten 2-von-3 Shamir-Escrow, Holder-only-Share-Verschlüsselung und als einziger der drei, der einen self-contained Desktop- und Mobile-Client ohne koordinierende Community ausliefert.

Coracle Hosting: kostenpflichtiger Relay-Dienst plus Open-Source-Caravel-Stack

Am 3. Juni kündigte Hodlbod Coracle Hosting an unter hosting.coracle.social, einen gehosteten Community-Relay-Dienst, der wiederkehrende Lightning-Zahlungen per NWC oder Karte akzeptiert. Der Dienst wird von Caravel angetrieben, Coracles Abrechnungs- und Provisionierungs-Frontend, und zooid, einer Relay-Runtime, die viele virtuelle Relays auf einer einzigen Maschine hostet. Beide sind Open Source auf Coracles selbstgehostetem gitea. Caravel wird mit optionaler livekit- und Blossom-Integration ausgeliefert, die Betreiber pro Relay umschalten können. Ein Free-Tier mit Mitglieder-Limits lässt Betreiber den Dienst evaluieren, bevor sie Zahlungsdetails hinterlegen.

Hodlbod ist offen zum Geschäftsmodell: Open Source monetarisieren, indem eine gehostete Version eines Stacks verkauft wird, den jeder andere ebenfalls betreiben kann. Der Wettbewerbsvorteil ist die Flotilla-Integration, der nächste geplante Schritt. Flotilla besitzt die Nutzeroberfläche, sodass die aus Flotilla heraus servierte Hosted-Option zum Standard-Pfad für jeden Nutzer wird, der verwaltete Infrastruktur bevorzugt. Hodlbod bot an, andere Caravel-Betreiber zu Flotillas Alternative-Hosting-Picker hinzuzufügen, wenn sie sich melden, und hält die Tür zu einem föderierten Hosting-Markt offen.

Caravel gesellt sich zu relay.tools als öffentliche Nostr-Relay-Provisionierungs-Plattform mit kostenpflichtigen Mitglieder-Tiers. relay.tools ist älter als Caravel und liefert heute als dominanter Relay-Ersteller-Dienst aus, mit einem eigenen Verzeichnis von Community-Relays und Paid-Member- oder Moderator-Join-Flows. Caravels Unterscheidungsmerkmal ist der koordinierte Stack: die Relay-Runtime (zooid), das Abrechnungs- und Provisionierungs-Frontend (Caravel selbst) und der clientseitige Picker (Flotilla-Integration, noch in Arbeit) werden als ein Design ausgeliefert. Das andere Unterscheidungsmerkmal ist zooids Many-Relays-per-Process-Dichte, bei der Kunden-Relays einen einzigen Host-Prozess teilen, sodass der Betreiber Hosting-Kosten über viele kleine Communities amortisiert. Das ist dasselbe Dichte-Argument, das gemeinsames Web-Hosting Anfang der 2000er tragfähig machte, angewendet auf Nostrs Relay-Schicht.

Releases

Angor v0.2.29 und v0.2.30: mainnet-Standard und 3-User-UAT-Funding-Test

Angor v0.2.29 am 4. Juni und v0.2.30 am 8. Juni sind die zwei Releases dieser Woche für das dezentrale Bitcoin-und-Nostr-Funding-Protokoll. Die Schlagzeilen-Änderung von v0.2.30 ist PR #893, der das Standard-Netzwerk auf mainnet umstellt. Angor wird immer noch als instabiles Alpha-Release ausgeliefert, aber der Default-mainnet-Wechsel signalisiert, dass das Protokoll die testnet-only-Phase für die Desktop- und Mobile-Clients hinter sich gelassen hat. v0.2.30 landet außerdem einen One-Tap-Mobile-Create-Project-Flow mit Bild-Upload und Scroll-Reset (PR #889) und löst eine Race-Condition, bei der der Lightning-Invoice-Spinner hängen konnte (PR #890).

v0.2.29 fügte in PR #881 einen End-to-End-UAT-Test hinzu, der 3-User-Send-Funds über 10 Runden mit unbestätigten Ausgaben abdeckt, den ersten Multi-User-Funding-Flow-Test in der Angor-Test-Suite. Das Release fügte außerdem einen Implementierungsplan für eine Angor-CLI und einen MCP-Server hinzu (PR #792), mit CLI-Verbesserungen für den MCP-Test-Workflow in PR #880. PR #885 von DavidGershony behob eine Boltz-Lightning-Invoice, die nach einem Runtime-Netzwerk-Switch das falsche Netzwerk verwendete, ein Bug, der nach dem v0.2.30-mainnet-Standard in der Produktion aufgetreten wäre. Die Einstellungen bieten jetzt einen optionalen Recovery-Wallet-Datei-Purge während des Data-Wipe (PR #883).

Sprout v0.3.15: TTL-Refresh für ephemere Kanäle und ACP-Slash-Commands

Sprout v0.3.15, veröffentlicht am 10. Juni, ist das achte Release in einem Lauf, der am 2. Juni mit v0.3.7 begann. Newsletter #25 behandelte den Lauf v0.3.1 bis v0.3.6 mit der mesh-llm-Integration und der Kanalabschnitt-Arbeit; v0.3.7 bis v0.3.15 sind downstream davon, fokussiert auf Politur und einige nutzerorientierte Ergänzungen. Die für Nutzer sichtbarste Änderung ist ein TTL-Refresh für ephemere Kanäle in PR #902: wenn ein Nutzer einen ephemeren Kanal wieder aktiviert, verlängert Sprout die Time-to-Live des Kanals, sodass das Unarchive nicht sofort unter dem ursprünglichen Ablauf-Timer wieder archiviert wird. Mobile Custom Emojis kommen in PR #906 neben einem Settings-Redesign an, und Reaktionszähler animieren jetzt bei Änderung (PR #904).

PR #905 behebt eine langbestehende Lücke, in der Multi-Word-Display-Namen brachen und die NIP-27 nostr:npub-Mention-Extraktion still fallen ließ. Eine verzeichnis-gestützte Team-UI für Desktop kommt in PR #912 mit Install-, Sync- und Reveal-Commands. Slash-Commands werden jetzt an ACP-Konnektoren in PR #919 durchgereicht, sodass Sprout /help-artige Commands direkt an Agent-Runtimes weiterleitet, während die Sprout-UI aus dem Pfad bleibt.

Wisp v1.1.1: Spark-Wallet-Integration und nsec-Paste-Guard

Wisp v1.1.1, veröffentlicht am 5. Juni, landet einen zweistufigen Wallet-Connect-Screen mit Spark-Sub-Screen in PR #548 und Dashboard-Parität mit der iOS-Wallet-UI in PR #549. Das Release enthält einen systemweiten nsec-Paste-Guard, der einen nsec1-präfigierten Paste-Vorgang irgendwo in der App erkennt und das Feld blockiert, es zu akzeptieren, was eines der meistzitierten Footguns in der Nostr-UX schließt. QR-Scan-Login plus ein Watch-only-Modus für npub und nprofile kommt in PR #552 und lässt einen Nutzer ein Profil nur zum Lesen durchsuchen. Zap-Nachrichten rendern jetzt als Mini-Posts im Engagement-Drawer (PR #559), sodass Zap-Notes ihren Text zusammen mit dem Sat-Betrag tragen. Ein Web-of-Trust-Filter für Thread-Antworten kommt in PR #583 und lässt Nutzer Reply-Spam von Konten außerhalb ihres Follow-Graphen ausblenden.

Nostria v3.1.46 und nospeak 1.1.3: Notification-Überarbeitung und ICE-Restart

Nostria v3.1.46 am 7. Juni beendet einen Drei-Release-Lauf, der den Notification-Counter so überarbeitete, dass nur neue Benachrichtigungen seit der letzten Ansicht gezählt werden, was eine langbestehende Inflation beseitigt, bei der das Scrollen zu älteren Benachrichtigungen den Badge-Zähler nach oben trieb. Nostria v3.1.45 behob einen Split-Payment-Bug, der Lightning- und QR-Code-Zahlungen betraf, und verwarf ein zuvor geplantes transluzentes UI als auf Androids Compositor nicht umsetzbar.

nospeak v1.1.3 am 4. Juni fügt ICE-Restart im FAILED-Zustand für 1-zu-1-Sprachanrufe hinzu. Standard-WebRTC-Verhalten wirft einen Anruf, wenn ICE-Kandidaten ohne alternativen Pfad zeitüberschreiten; der ICE-Restart-Pfad verhandelt Kandidaten neu, sodass der Anruf sich von vorübergehenden NAT- oder Netzwerkänderungen erholt. Android-Anrufe halten jetzt den Bildschirm während Videoanrufen an.

Unveröffentlichte Änderungen

Amethyst: 41 PRs setzen die NIP-32 / NIP-F4 / Tor-Spur fort

Amethyst mergte diese Woche 41 PRs ohne einen Release-Tag zu schneiden, zusätzlich zu den 52 PRs der letzten Woche und der NIP-32 Hashtag-Labeling- und NIP-F4 Podcast-Arbeit, die in Newsletter #25 behandelt wurde. Der aktive Branch sammelt weiterhin Features für das nächste getaggte Release und schichtet Politur auf die Schlagzeilen-Ergänzungen der letzten Woche: Hashtag-Labeler-Discovery, Podcast-Screen, Musiktracks und Playlists, Tor-Self-Heal-Watchdog, ephemere Signer für anonyme Uploads und Onchain-Zaps mit NIP-05-Filterung. Amethysts PR-Durchsatz bleibt der höchste jedes Nostr-Clients, und die unveröffentlichte Warteschlange ist die de-facto-Roadmap dafür, was andere Android-Nostr-Clients erreichen müssen.

Damus: Relay-Tracking aus OK-Nachrichten und v1.17-Changelog

Damus PR #3786, gemerged am 3. Juni, fügt erfolgreiche OK-Nachrichten von einem Relay zur Post-Relay-Liste hinzu. Frühere Damus-Builds befüllten die Seen-Relays-Liste nur beim Empfang einer generischen Nachricht vom Relay, was bedeutete, dass ein Relay, das den Post bestätigte, aber keine Events zurücklieferte, für den Nutzer unsichtbar war. Die Änderung ist wichtig für Nutzer, die bestätigen möchten, dass ihr Post auf ihrem bevorzugten Outbox-Relay landete. PR #3796 behebt einen AttributeGraph-Zyklus auf der Profile-Ansicht, und PR #3725 landet den v1.17-Changelog vor dem nächsten getaggten Release.

Shopstr: NIP-34 Dual-Publishing

Shopstrs shopstr-Repo auf ngit wurde diese Woche auf Nostr als NIP-34 Git-Repo angekündigt und tritt ngits getrackten Repos bei. Das GitHub-Repo des Shop-Clients bleibt die primäre Entwicklungsoberfläche; die NIP-34-Ankündigung macht einen parallelen Git-über-Nostr-Kollaborationspfad verfügbar. Dies ist das zweite große Nostr-Marketplace-Projekt, das nach Mostro doppelt zu NIP-34 veröffentlicht, und setzt die schrittweise Migration von Projekt-Metadaten auf Nostrs Git-Transport fort.

Hermes-Marmot: KI-Agent-Gateway über MLS

hermes-marmot, ein Plugin für den Hermes Agent, verbindet die Messaging-Oberfläche eines KI-Agenten mit Marmot (MLS-über-Nostr) Gruppen unter Verwendung von mdk-python, den Python-Bindings zum Rust-Marmot-Development-Kit. Das Plugin lässt einen Nutzer einem KI-Agenten aus jedem Nostr-Client, der kind 445 MLS-Nachrichten spricht, eine DM schicken, einschließlich Whitenoise. Eingehende DMs verwenden NIP-59 Gift-Wrap-Unwrapping über nostr-sdk Python-Bindings, und eingehende Welcomes fließen durch UnwrappedGift.from_gift_wrap zu mdk.process_welcome und mdk.accept_welcome. Die Zugriffskontrolle läuft über MARMOT_ALLOWED_USERS (eine kommagetrennte npub-Allowlist) oder MARMOT_ALLOW_ALL_USERS=true für offenen Entwicklungszugriff.

Das Repo ist neu (letzte Aktualisierung am 27. Mai) und klein. Seine Bedeutung ist architektonisch: es ist die erste öffentliche Brücke zwischen einer LLM-Agent-Runtime und einem MLS-verschlüsselten Nostr-Messaging-Kanal und der erste Produktions-Einsatz von mdk-python über Whitenoise selbst hinaus. Das Muster deutet auf Agent-zu-Agent-Kommunikation hin, bei der beide Endpunkte MLS-Schlüssel halten und das Relay nur Chiffretext sieht.

NIP-Updates und Protokoll-Spec-Arbeit

NIP-67 EOSE Completeness Hint (PR #2317) gemerged

PR #2317 von mattn wurde am 6. Juni gemerged und fügt NIP-67 dem Protokoll hinzu. Das NIP erweitert die EOSE-Relay-Nachricht um ein optionales drittes Element: ["EOSE", <subscription_id>, "finish"] signalisiert, dass jedes zum Filter passende gespeicherte Event ausgeliefert wurde, während ein blankes ["EOSE", <subscription_id>] keinen Vollständigkeitsanspruch trägt. Ein Relay, das den Hinweis auslässt, sagt dem Client, dass möglicherweise mehr da ist; ein Relay, das die NIP-67-Ankündigung in NIP-11 auslässt, behält das heutige Verhalten unter der bestehenden Legacy-Heuristik. Die Änderung ist in beide Richtungen abwärtskompatibel: Legacy-Clients ignorieren das nachfolgende Array-Element, und Legacy-Relays lassen es weg.

Die Motivation in der gemergten Spec ist zweifach. Erstens, stiller Datenverlust: ein Client fragt die letzten 500 Notes gegen ein Relay mit einer 300-Event-Internal-Cap ab, das Relay gibt 300 Events zurück, und der Client (unter Verwendung der Standard-received < limit-Heuristik) schlussfolgert, dass das Ergebnis vollständig ist. Die 201sten bis Nsten ältesten passenden Notes bleiben auf dem Relay ungelesen, wobei der Client blind für diese Tatsache ist. Zweitens, obligatorische verschwendete Round-Trips: wenn ein Relay Antworten auf 300 Events deckelt, erfordert jede Subskription, die den Cap ausschöpft, ein zweites REQ mit until=<oldest_created_at> rein zur Bestätigung des Abschlusses, selbst wenn der Filter zufällig genau 300 Events matcht. Beide Fehlermodi werden von jedem Client bei jeder cap-erschöpften Subskription bezahlt. Der "finish"-Hinweis ist ein optionaler String auf einer bestehenden Nachricht und eliminiert beide Kosten.

NIP-50 Autocomplete-Erweiterung (PR #2357) gemerged

PR #2357 von Alex Gleason wurde am 6. Juni gemerged und fügt ein autocomplete:true/false-Token zur NIP-50 Suche hinzu. Die Erweiterung lässt einen Client eine Anfrage als Typeahead-Lookup markieren, sodass das Relay Prefix-Matching verwendet, mit Volltext-Suche als Standard für Anfragen ohne das Token. Dittos Relay implementiert es für Follow Packs, Listen und jedes Event mit einem title-Tag und gibt Matches gegen den Titel-Präfix zurück; der Standard-Suchpfad läuft mit Volltext-Scoring. Ohne dieses Token hatten Autocomplete-artige UIs keine Möglichkeit, die Prefix-Search-Absicht zu kommunizieren, und Relays mussten aus der Anfrageform raten. Das Token ist ein Per-Search-Hinweis, keine relay-weite Capability, sodass ein Relay es für eine Event-Klasse (Titel) implementieren kann, ohne allgemeine Autocomplete-Unterstützung zu beanspruchen.

NIP-GART Notfallwarnungen und Location-Broadcasts (PR #2374)

PR #2374 von disinqa, geöffnet am 9. Juni, definiert ein datenschutzfreundliches Wire-Format auf Nostr für Notfallwarnungen und Location-Broadcasts, die an eine Gruppe vertrauenswürdiger Empfänger adressiert sind. Das angegebene Designziel ist, Sender-Identität, Gruppenmitgliedschaft und Payload vor Relay-Betreibern zu verbergen, während die Events end-to-end replay-safe und signatur-verifizierbar bleiben. Die NIP-Nummer steht noch aus, der Vorschlag ist Frühentwurf. Der Use Case ist das Standard-Notfallwarn-Muster: ein Nutzer unter Bedrohung broadcastet einen Location-Ping, den nur eine vorab geteilte Gruppe vertrauenswürdiger Kontakte entschlüsseln kann, wobei das Relay blind für Sender, Empfänger-Set und Payload ist. Wire-Format-Details leben im PR und werden sich wahrscheinlich weiterentwickeln, während Maintainer prüfen.

NIP-46 Logout-Methode (PR #2373)

PR #2373 von hzrd149, geöffnet am 8. Juni, fügt eine logout-Methode zu NIP-46 hinzu, sodass ein Client einem Bunker explizit sagen kann, dass die Session beendet ist. Bis jetzt war die einzige Möglichkeit, eine Bunker-Session zu beenden, auf den Session-Timeout zu warten oder aufzuhören, die Verbindung zu nutzen, wobei beides den Bunker mit Session-State für einen Client zurücklässt, der weg ist. Der Vorschlag ist kurz (eine neue Methode) und die Art von Housekeeping-Änderung, die langlebige Bunker-Integrationen sauberer macht.

NIP-95 Hybrid-Relay-P2P-Vorschlag als Long-Form zirkuliert

Eine Long-Form-NIP-95-Spezifikation zirkulierte als kind:30023-Post von npub 91bea5cd9361504c409aaf459516988f68a2fcd482762fd969a7cdc71df4451c am 4. Juni unter dem Titel Protocolo Híbrido Relay-P2P via WebRTC. Das portugiesischsprachige Dokument definiert ein hybrides Peer-to-Peer-Relay-Protokoll, bei dem Nostr-Clients sich für Live-Messaging direkt über WebRTC verbinden, während sie weiterhin Relays für Stored-Event-Retrieval und Offline-Zustellung verwenden. Der Autor formulierte die Spec explizit als “LLM-ready”, und lieferte Nachrichten-Definitionen, logische Flows, Datenschemata und Zustandsregeln in einem Detailgrad, der einem KI-Modell erlaubt, funktionierenden Client- oder Server-Code zu generieren. Der Vorschlag ist noch nicht als NIP-PR gelandet; die Zirkulation über kind:30023 ist der übliche Vorläufer eines formalen nostr-protocol/nips Pull Requests.

NIP-44 v3 gewinnt einen zweiten Signer: Clave portiert die Spec

Ambers v6.2.0-NIP-44-v3-Rollout von letzter Woche wurde vor jedem gemergten NIPs-PR ausgeliefert und ließ v3 als Amber-spezifische Erweiterung zurück, die andere Clients spiegeln mussten, um zu interoperieren. Dieses Single-Implementation-Framing änderte sich diese Woche. Clave, der push-basierte iOS-NIP-46-Remote-Signer, landete am 3. und 4. Juni über acht Commits einen unabhängigen NIP-44-v3-Port. Kryptografische Primitive kommen in drei Commits: HKDF + ECDH keys layer, der v3-Padding-Algorithmus und eine Top-Level-Public-API plus Verschlüsselungs-Context. Darauf folgt die NIP-46-Oberfläche in RPC-Dispatch-Verdrahtung innerhalb LightSigner und einem PendingRequest-Schema, das den v3-Kontext (kind plus scope) trägt, sodass der Signer aufzeichnen kann, für welches Event-kind und welchen Anwendungsfall die v3-Payload genehmigt wurde.

Clave weicht auf der nutzerorientierten Oberfläche von Amber ab. Ein Berechtigungserteilungs-Schema mit Sensitivity-Tiers lässt Nutzer v3-Verschlüsselung für ein bestimmtes Event-kind und einen bestimmten Scope auf einer gewählten Sensitivity-Stufe erteilen. Bei erster Begegnung führen v3-context-aware Approval-Prompts mit einer einmaligen Explainer-Card v3 den Nutzern vor. Die Arbeit ist in main und ist in das Xcode-Projekt verdrahtet, aber unveröffentlicht; der jüngste getaggte Build ist v0.2.0-build79 vom 12. Mai.

Zwei unabhängige Implementierungen landen NIP-44 v3 in Produktionspfaden, bevor der NIPs-PR merged, was den Fall für das zugrunde liegende Wire-Format stärkt, das der Protokoll-PR formalisieren wird. Cross-Implementation-Interop-Tests werden jetzt der Pfad zur Spec-Konvergenz, mit Ambers Android-Approval-Oberfläche und Claves iOS-Sensitivity-Tier-Modell als den zwei Referenzpunkten. Weitere Remote-Signer, die v3 verdrahten (nsec.apps noauth ist seit Mai 2025 dormant, und andere Bunker haben keine v3-Arbeit angekündigt), würden den Konsens weiter festigen.

NIP-34-Aktivität: Iris übernimmt den Stack mit einem neuen Hashtree-Transport

Iris veröffentlichte NIP-34 Repo-Ankündigungen für hashtree am 8. Juni und für iris-apps, iris-drive und iris-chat-rs am 9. Juni, und wirbt für Clone-URLs unter einem neuen htree://-Schema, das von wss://temp.iris.to bedient wird. Der Hashtree-Transport ist eine content-adressierte Alternative zu GRASP-gerouteten Clones, und diese vier Ankündigungen sind seine ersten öffentlichen Verwendungen. Die Repos tragen leere Beschreibungen und die architektonischen Details entstehen noch, aber die Wahl, über NIP-34-Ankündigung zu veröffentlichen (statt einem benutzerdefinierten Iris-internen Manifest), signalisiert, dass Iris sich zum breiteren NIP-34-Git-über-Nostr-Stack bekennt.

NIP Deep Dive: NIP-67 (EOSE Completeness Hint)

NIP-67 schließt eine der langbestehenden Korrektheitslücken in NIP-01. Die ursprüngliche Spec definiert EOSE als die Grenze zwischen gespeicherten Events und Live-Subscription-Events für ein REQ, aber sie spezifizierte nie, ob das Relay die Auslieferung aller gespeicherten Matches beendet oder wegen einer internen Deckelung auf halbem Weg gestoppt hatte. Jedes Relay erzwingt eine Per-Subscription-Deckelung (üblicherweise 300 bis 1000 Events) unabhängig vom limit des Clients, und Clients hatten keine Möglichkeit, diese Deckelung zu beobachten.

Der Standard-Workaround war, den empfangenen Count gegen das angeforderte limit zu vergleichen. Wenn received < limit, behandle das Ergebnis als vollständig; sonst paginiere mit until=<oldest_created_at>. Beide Branches sind kaputt. Der received < limit-Branch trunkiert still: ein Client, der 500 Notes gegen ein auf 300 gedeckeltes Relay abfragt, sieht 300 Events, schlussfolgert, dass das Ergebnis vollständig ist, weil 300 < 500, und holt den Rest nie ab. Auf dem Relay gehaltene Events können “mehr verfügbar” durch keine bestehende Nachricht signalisieren. Paginierung als zweiter Branch ist verschwenderisch: ein Filter, der genau die Deckelung matcht, erfordert ein zweites REQ zur Bestätigung der Vollständigkeit, das null Events zurückgibt, während ein voller Filter-Scan auf dem Relay konsumiert wird.

NIP-67s Fix ist ein optionaler String auf der EOSE-Nachricht:

["EOSE", "<sub_id>", "finish"]   // explicit: all stored events delivered
["EOSE", "<sub_id>"]              // no completeness claim

Ein Relay, das NIP-67 in NIP-11 supported_nips bewirbt und ein blankes EOSE aussendet, sagt dem Client, dass es mehr gibt. Ein Relay, das die Ankündigung auslässt, behält das heutige Verhalten, und der Client fällt auf die bestehende Heuristik zurück. Legacy-Clients ignorieren das nachfolgende Array-Element. Abwärtskompatibilität hält in beide Richtungen, ohne neue Verben oder Event-kinds.

Was NIP-67 der Untersuchung wert macht, ist der Umfang, den es bewusst einschränkt. Die Spec definiert keinen Cursor oder Paginations-Token, sodass until-basierte Paginierung der Mechanismus bleibt. Relay-Deckelungen bleiben, wo sie sind, und das NIP verlangt keine Offenlegung davon. NIP-67 bewahrt die Bedeutung von EOSE als die Stored-to-Live-Grenze und fügt nur ein Yes-or-No-Signal an der Grenze hinzu: “Ich habe mehr für dich” gegen “das ist alles.” Diese minimale Oberfläche ist der Grund, warum der PR nach einem relativ kurzen Review-Zeitraum für eine NIP-01-Erweiterung merged, und warum mattn im PR explizit anmerkt, dass KI-Übersetzung für den englischen Text verwendet wurde. Die Änderung ist klein genug, dass die Übersetzungs-Unsicherheit keine Rolle spielt.

Beispiel eines NIP-67-bewussten Austauschs zwischen einem Client und einem cap-erzwingenden Relay. NIP-11-Ankündigung vom Relay:

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

Der Wire-Level-Austausch, der folgt:

→ ["REQ", "abc", {"kinds":[1],"limit":500}]
← [...300 EVENT messages...]
← ["EOSE", "abc"]               // no "finish": cap hit, more available
→ ["REQ", "def", {"kinds":[1],"limit":300,"until":1780900000}]
← [...178 EVENT messages...]
← ["EOSE", "def", "finish"]     // explicit complete

Die 178-Event-Antwort hätte zuvor ein drittes REQ zur Bestätigung des Abschlusses ausgelöst. Mit NIP-67 stoppt der Client dort.

NIP-67 ist auch bemerkenswert als NIP-01-Änderung, die mit seltenem Konsens landet. Die meisten NIP-01-Änderungen ziehen lange Debatten-Threads an, weil die winzige Oberfläche des Protokolls für jede Implementierung tragend ist. NIP-67 wurde nach einem erweiterten Review-Zeitraum gemerged (etwa sieben Wochen von Öffnung bis Merge), was nahelegt, dass wenn eine NIP-01-Änderung klein genug ist und der Fehlermodus konkret genug ist (stiller Datenverlust, obligatorischer verschwendeter Round-Trip), die Maintainer des Protokolls bereit sind, das Kern-Nachrichten-Vokabular zu erweitern.

NIP Deep Dive: NIP-50 (Suche)

NIP-50 definiert das search-Filterfeld in REQ-Nachrichten, wodurch Clients ein Relay bitten können, Events per Volltext-Match gegen einen Query-String zu filtern. Die gemergte Basis-Spec ist bewusst minimal: das search-Feld ist ein String, jedes Relay entscheidet seine eigene Such-Semantik (welche Felder indexiert werden, wie Scoring funktioniert, ob Stemming angewendet wird), und Relays bewerben NIP-50-Unterstützung in ihrem NIP-11-Dokument. Clients kontrollieren den Suchalgorithmus nur durch den Query-String selbst.

Dieser Minimalismus ist sowohl NIP-50s Stärke als auch seine Einschränkung. Die Stärke ist, dass jedes Relay Suche auf jeder Qualitätsstufe implementieren kann: ein einfacher Substring-Scan erfüllt die Spec, und ein Relay, das Elasticsearch oder Meilisearch betreibt, erfüllt sie gleichermaßen. Die Einschränkung ist, dass Clients keine Möglichkeit haben, Suchabsicht auszudrücken. Eine Profile-Mention-Typeahead-UI möchte Prefix-Matching gegen Display-Namen; eine Volltext-Content-Suche möchte tokenisiertes Volltext-Scoring über den Note-Body. Dasselbe search-Feld trägt beides, und das Relay muss aus der Anfrageform raten.

PR #2357 fügt das erste NIP-50-Erweiterungs-Token hinzu: autocomplete:true oder autocomplete:false, eingebettet in die Such-Anfrage, signalisiert, welchen Modus der Client möchte. Dittos Relay implementiert das Token für Follow Packs, Listen und jedes Event mit einem title-Tag und wechselt zu Prefix-Matching, wenn autocomplete:true vorhanden ist. Das Token lebt inline in der Anfrage (separate Filter-Felder bleiben unberührt), sodass es mit dem Such-String reist und keinen Wire-Protokoll-Bump erfordert:

search: "fiat autocomplete:true"

Token-förmige Hinweise wie dieser sind, wie NIP-50 immer schon relay-spezifische Dialekte gehandhabt hat. Relays unterstützten bereits Tokens wie language:en und domain:example.com. Jedes bleibt relay-spezifisch, wobei jedes Relay seinen eigenen Dialekt dokumentiert. NIP-50s PR #2357 hebt autocomplete von einem relay-privaten Token zu einem spec-gesegneten und ebnet den Weg für Typeahead-bewusste Suche über Relays hinweg.

Beispiel eines NIP-50 REQ mit dem Autocomplete-Token, gerichtet auf ein Relay, das kind 0 Profil-Titel indexiert:

{
  "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"
}

Der tatsächliche Wire-Level-REQ:

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

Ein Relay, das das Token nicht erkennt, behandelt autocomplete:true als Teil des wörtlichen Such-Strings und fällt auf Volltext-Matching zurück und gibt korrekte (wenn auch anders gerankte) Ergebnisse zurück. Die grazile Degradation macht das Token sicher, es bedingungslos einzuschließen für Clients, die Prefix-Matching bevorzugen, wenn verfügbar.

Die nächste wahrscheinliche NIP-50-Erweiterung ist Per-kind-Ranking-Kontrolle: ein Hinweis, der sagt “rank by created_at descending” gegen den Standard-Relevance-Score. Mehrere Relays akzeptieren bereits sort:newest als relay-privates Token, und derselbe Aufwertungspfad, der autocomplete in die Spec brachte, gilt. Suche bleibt eines der wenigen Nostr-Primitive, bei denen Relays um Ergebnisqualität konkurrieren; die Zuverlässigkeit der Zustellung ist bei allen konformen Relays gleich. Inkrementelle Tokens lassen Clients diese Qualitätskonkurrenz nutzen, ohne Relays zu zwingen, eine schwergewichtige neue Spec auszuliefern.