| Setting | Value |
|---|---|
| Algorithm | Filter decomposition via bitflags |
| Connection cap | None |
| Per-pubkey target | 3 write + 3 read + 1 hint + 1 most-used |
| Fallback relays | Client's configured READ relays |
| Health tracking | Per-pubkey freshness semaphore (Missing/Outdated/Updated) |
| NIP-17 DM inbox | Yes (kind 10050, PRIVATE_MESSAGE bitflag) |
| Configurable | No (compile-time limits) |
rust-nostr stores bitflags per (pubkey, relay) pair: READ, WRITE, PRIVATE_MESSAGE, HINT, RECEIVED. The break_down_filter() function decomposes nostr filters based on these flags: authors-only filters use WRITE + HINT + RECEIVED relays, #p-only filters use READ + HINT + RECEIVED, both uses the union, neither falls back to client READ relays. Per-flag limits (3 write, 3 read, 1 hint, 1 most-used) are applied per pubkey. Supports negentropy (NIP-77) sync for bandwidth-efficient updates.
- Five independent relay association types per (pubkey, relay) pair via bitflags. Most granular relay classification of any analyzed implementation.
- Freshness checking via per-pubkey tokio semaphores, stress-tested to 10k concurrent requests.
- SQLite backend persists the gossip graph across restarts (received_events count, last_received_event timestamp).
rust-nostr's per-author Filter Decomposition can be upgraded to FD+Thompson by replacing lexicographic relay ordering with sampleBeta(α, β) scoring from delivery history. Same per-author structure, same write limits — just learned relay ranking instead of static. After 5 learning sessions (cap@20, NIP-66 filtered): FD+Thompson reaches ~37% event recall at 1yr vs baseline FD's ~25% (10-run 6-profile validated, ±2.8 SE) — converging within 2-3 sessions. Welshman+Thompson leads by ~2pp (~39%) in the 10-run study due to popularity weighting; a 30-run use-case comparison confirms the algorithms are effectively tied excluding fiatjaf's small-graph anomaly (§8.15: 0.7pp gap across 5 profiles). FD+Thompson requires no structural changes to existing rust-nostr code. See README.md § FD+Thompson for implementation code.
| Setting | Value |
|---|---|
| Algorithm | Multi-phase greedy (NIP-65 + event-relay tracking) |
| Connection cap | 25 (MAX_AUTOPILOT_RELAYS) |
| Per-pubkey target | 2 (MAX_RELAYS_PER_PUBKEY, publish only) |
| Fallback relays | READ relays + already-selected relays |
| Health tracking | Spam relay flagging |
| NIP-17 DM inbox | No |
| Configurable | No |
Voyage's "autopilot" runs four phases: (1) map followed users' NIP-65 write relays, sorted by not-spam/has-event-data/connected/not-disconnected, take top 25; (2) fill coverage gaps using EventRelayAuthorView (tracks which relay delivered events from which author); (3) assign uncovered pubkeys to READ + selected relays; (4) pubkeys with only 1 relay get added to READ relays for redundancy.
- Unique dual-source relay selection: combines NIP-65 declarations with empirical event-relay tracking (which relays actually delivered events from each author).
- Room (SQLite) persistent storage for NIP-65 data with
createdAtfor upsert deduplication. lazySubNip65s()identifies friends with missing NIP-65 data and fetches kind 10002 lazily on demand.
| Setting | Value |
|---|---|
| Algorithm | RxJS observable pipeline with event-count ranking |
| Connection cap | None |
| Per-pubkey target | 3 (configurable slider 1–14) |
| Fallback relays | FALLBACK_RELAYS env var |
| Health tracking | Relay stats DB (event count, connect count) |
| NIP-17 DM inbox | No |
| Configurable | Yes (max relays per user slider 1–14) |
Nosotros splits nostr filters by field type using RxJS observables. For authors fields, it fetches each author's relay list via tanstack-query (with batching), selects WRITE relays sorted by relay stats event count descending, and slices to maxRelaysPerUser. Subscriptions merge three sources: outbox-resolved relay-filter pairs, a static relay list, and relay hints (capped at 4). Filters blacklisted relays, ignored relays, and non-wss:// URLs.
- Per-author relay resolution via tanstack-query with batching — each author's relay list resolves independently as an observable.
- SQLite (OPFS)
seentable tracks(eventId, relay, created_at)for event delivery tracking. - Subscription merges outbox results + static relays + hints into a unified stream. Max 4 hint relay connections per subscription.
| Setting | Value |
|---|---|
| Algorithm | Greedy set-cover (RelayScoreBoard) |
| Connection cap | 75 (MAX_SCORED_RELAYS) |
| Per-pubkey target | No per-pubkey limit |
| Fallback relays | relay.damus.io, relay.primal.net (onboarding only) |
| Health tracking | None explicit |
| NIP-17 DM inbox | No |
| Configurable | No |
Wisp's RelayScoreBoard builds a relay-to-followed-authors map from kind 10002 write relays, then runs greedy set-cover: pick the relay covering the most uncovered authors, remove them, repeat until all covered or 75-relay cap reached. Authors without relay lists get sendToAll (broadcast to all general relays). The scoreboard recomputes after relay list EOSE.
- Unique onboarding relay prober: harvests 500 kind 10002 events from bootstrap relays, drops top 5 mega-relays, requires frequency ≥3, probes 15 middle-tier candidates with NIP-11 + ephemeral write test (kind 20242), selects top 8 by latency.
- Only project that tests relay health and latency before adding relays during onboarding.
- LRU(500) relay list cache backed by SharedPreferences for persistence.
| Setting | Value |
|---|---|
| Algorithm | None (static relay list) |
| Connection cap | N/A |
| Per-pubkey target | N/A |
| Fallback relays | relay.damus.io, nos.lol, purplepag.es, relay.primal.net, relay.nostr.band |
| Health tracking | None |
| NIP-17 DM inbox | No |
| Configurable | No |
Shopstr is a Next.js marketplace using nostr-tools' SimplePool. It reads kind 10002 for the user's own relay config only, not for other users. All events publish to the user's own write relays + general relays + sendit.nosflare.com (blastr). No per-recipient routing.
- Marketplace-focused: relay routing is not a priority since listings are broadcast broadly.
- Adds sendit.nosflare.com (blastr) to all writes for maximum event propagation.
- Relays stored in localStorage with three separate lists: relays, readRelays, writeRelays.