You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
New feature — nothing WoT-related exists in grain today. There is currently no WoT config, no graph builder, no permission groups, and no "whitelist-by-WoT" toggle in the codebase. This issue is the proposal for the shape WoT should take when it lands.
Wanted before 1.0, but not top priority right now — the tracker issues it depends on (#55, #56, #57) and the existing whitelist/blacklist cleanup come first.
Promote Web of Trust from a single-toggle whitelist into its own configuration set. The real primitive isn't "WoT yes/no" — it's a set of permission groups that the admin composes from any combination of (explicit whitelist, WoT membership, WoT score thresholds, AUTH state, admin pubkey). Each group then has its own access, retention, and rate-limit policy (see #57).
Identity root
The relay acts as a first-class Nostr actor with its own pubkey (depends on #55). That pubkey is:
advertised in the NIP-11 document as the relay operator identity
the seed of the WoT graph — the admin's own follow list is the root set
WoT construction
Built by the client library (#56 outbox-model pool) which fetches follow lists via indexer relays.
Strict — only the admin's direct follows
Normal — follows-of-follows
Exclude large lists — drop follow lists over N entries from graph building (prevents a single mega-follower from inflating the set)
Score — edges/occurrences counted toward a per-pubkey score; exposed as a numeric value groups can threshold on
WoT is a signal, not a permission by itself. Groups decide how to use it.
Permission groups
A group is a rule: "does this pubkey belong?" plus the policy attached to belonging. Admins define any number of groups. At connection time, the relay walks the group list in order; the first match assigns that connection's policy.
Group membership can be built from any combination of:
Unmatched connections fall through to the implicit public group at the bottom, which the admin can configure or leave as a deny-all default.
Access + retention are decoupled
A group can be allowed to write but have a short TTL, or denied write but be allowed to read, independently. "Who's allowed" and "whose events survive" are separate axes.
Example configurations
The point of the group model: all of these — and combinations the admin invents — are expressible.
Private archive. Only WoT + explicit list can do anything, kept forever.
wot:
enabled: truebuild:
mode: normal # strict | normalmax_follow_list: 1000# exclude larger follow lists from graphrefresh_interval: 6h# scoring is exposed to groups via wot_score_min/max; no global threshold hereexplicit_whitelist:
# existing whitelist.yml continues to be the source of truthfile: whitelist.ymlgroups:
# Evaluated in order, first match wins.# Each group: name, match (any/all/negate over predicates), access, retention, rate_limit
- name: adminmatch: { any: [admin] }access: { read: allow, write: allow }retention: { ttl: 0 }rate_limit: { tier: admin }# ... user-defined groups ...public:
# Implicit fallback for unmatched connectionsaccess: { read: allow, write: allow }retention: { ttl: 24h }rate_limit: { tier: public }
Migration note
Because no WoT config exists yet, this is a greenfield design — no backward-compat shim needed. The existing whitelist.pubkey_whitelist continues to work as-is; groups layer on top rather than replacing it. Admins who don't opt into groups get today's behavior.
Status
New feature — nothing WoT-related exists in grain today. There is currently no WoT config, no graph builder, no permission groups, and no "whitelist-by-WoT" toggle in the codebase. This issue is the proposal for the shape WoT should take when it lands.
Wanted before 1.0, but not top priority right now — the tracker issues it depends on (#55, #56, #57) and the existing whitelist/blacklist cleanup come first.
Promote Web of Trust from a single-toggle whitelist into its own configuration set. The real primitive isn't "WoT yes/no" — it's a set of permission groups that the admin composes from any combination of (explicit whitelist, WoT membership, WoT score thresholds, AUTH state, admin pubkey). Each group then has its own access, retention, and rate-limit policy (see #57).
Identity root
The relay acts as a first-class Nostr actor with its own pubkey (depends on #55). That pubkey is:
WoT construction
Built by the client library (#56 outbox-model pool) which fetches follow lists via indexer relays.
WoT is a signal, not a permission by itself. Groups decide how to use it.
Permission groups
A group is a rule: "does this pubkey belong?" plus the policy attached to belonging. Admins define any number of groups. At connection time, the relay walks the group list in order; the first match assigns that connection's policy.
Group membership can be built from any combination of:
admin— relay's own pubkey (from Implement NIP-29 (Relay-based Groups) #55)explicit_whitelist: [pubkeys]— hand-picked list (existing whitelist file)in_wot: true— any non-zero WoT scorewot_score_min: N/wot_score_max: M— score bandsauthenticated: true— passed NIP-42negate: true— inverts any of the above (useful for "everyone not in WoT")Policy attached to a group:
access.read/access.write—allow|denyretention.ttl— how long their events live (0= keep forever,ephemeral= never persist)rate_limit— see Rate limits: per-permission-group tiers (WoT + whitelist combinations) #57 for the per-group rate-limit shapeUnmatched connections fall through to the implicit
publicgroup at the bottom, which the admin can configure or leave as a deny-all default.Access + retention are decoupled
A group can be allowed to write but have a short TTL, or denied write but be allowed to read, independently. "Who's allowed" and "whose events survive" are separate axes.
Example configurations
The point of the group model: all of these — and combinations the admin invents — are expressible.
Private archive. Only WoT + explicit list can do anything, kept forever.
Public relay, trust-weighted retention. Everyone can read/write, but only WoT and explicit keys survive past 24h.
Purge everyone ephemerally, except explicit whitelist.
Purge everyone but WoT and explicit whitelist combined.
Pure score-driven, no explicit list. Keep events from anyone the graph reached with score ≥ 5; purge everyone else after an hour.
Explicit-only, WoT ignored. Disable WoT entirely; only the explicit whitelist counts.
Config shape (top-level)
Migration note
Because no WoT config exists yet, this is a greenfield design — no backward-compat shim needed. The existing
whitelist.pubkey_whitelistcontinues to work as-is; groups layer on top rather than replacing it. Admins who don't opt into groups get today's behavior.Out of scope for this issue