NIPs by PolleramaCommunity NIPs, surfaced by trustConnect
npub1manlnflyzyj...

TSM Ranking Services

Published Mar 2, 2026
kind 37573

TSM Ranking Services

tsm-ranking-services

draft

extends tsm-trust-service-machines

kind 37573 "TSM Ranked Result Set"


Web of Trust style ranking is the foundation on which most Nostr recommendation and discovery services are built. This NIP extends the tsm-trust-service-machines NIP with a standard for ranking services that can be implemented and extended by any provider. A ranking service is one that calculates a relative rank (0-100) for subjects, based on interactions discovered from the "point of view" of any other subject(s).

  • It maps subject interactions (published events) of any kind, starting from one or more unique subject POVs.
  • It ranks subjects (pubkeys, hashtags, urls, ect...) based on their influence within these interactions.
  • It outputs a list of ranked subjects as single letter tags (p, t, u, ect...) in a (set of) kind 37573 event(s).

Service Expectations

Service announcements SHOULD

  • Declare kind 37573 as a k tag
  • Declare ALL standard configs (type, pov, minrank) as config tags
  • Declare ALL of the V tags required for output events

Services providers SHOULD respond to Service Request (kind 37572) events by:

  • Publishing Service Feedback events (kind 7000) to inform on request status
  • Parsing the pov and type values to result in a set of subjects
  • Calculating rank values for ALL subjects using the configured algorithm
  • Sorting results in descending order by rank value
  • Filtering results by minrank threshold
  • Paginating results according to provider settings
  • Rendering results in a (paginated set of) kind 37573 output event(s)
  • Updating output events according to requested schedule (if supported)

Service Announcement Events

Providers implementing ranking services SHOULD publish a standard TSM Service Announcement event (kind 37570), with the following tags:

{
  "kind": 37570,
  "pubkey": "<service_pubkey>",
  "tags": [
    // ... OPTIONAL and REQUIRED tags as specified by TSM
    
    // REQUIRED output event kind
    ["k", "37573"], // Ranked Result Set

    // REQUIRED `type` config
    // A tag letter for the `pov` subject type AND the type to be ranked
    // (e.g., "p" for pubkeys, "e" for event ids, "u" for urls, etc.)
    ["config", "type", "tagletter", "<description?>", "<default?>", "<allowed?>"],
    
    // REQUIRED `pov` config
    // A point of view subject(s) from which to start the ranking.
    // This may be a single subject (any value from a tag of `type`)
    // or a `naddr` reference to any event with `type` tags.
    // If the referenced event has a `page` keyed `v` tag,
    // the provider SHOULD make sure to get ALL the subject tags
    // from ALL of the paginated events.
    ["config", "pov", "subject|naddr", "<description?>", "<default?>", "<allowed?>"],
    
    // REQUIRED `minrank` config
    // Minimum rank threshold for inclusion in output
    ["config", "minrank", "0-100", "<description?>", "0", "<allowed?>"],

    // OPTIONAL declare v tags for output events
    ["V", "type", "tagletter", "Type of subjects in output"],
    ["V", "pov", "subject|naddr", "Point of view reference"],
    ["V", "page", "integer", "Page number for paginated results"],
    
  ],
  "content": "<optional_service_details_markdown>"
}

Service Output Standards

The ranking service NIP does NOT make use of output standard events (kind 37571).

Service Request Events

Users may request ranking services from a provider by publishing a standard TSM Service Request event (kind 37572), with the following tags:

{
  "kind": 37572,
  "pubkey": "<request_author_pubkey>",
  "tags": [
    // ... OPTIONAL and REQUIRED tags as specified by service announcement
    
    // REQUIRED expected output kind
    ["k", "37573"], // want Ranked Result Set
    
    // CONDITIONAL config tags (as defined by provider)
    // Must match the allowed values from the service announcement
    ["config", "type", "<tagletter>"],
    ["config", "pov", "<subject> | <naddr>"],
    ["config", "minrank", "<0-100>"],
  ],
  "content": "" // empty or encrypted tags array
}

Ranked Result Set (kind 37573)

Ranking services SHOULD publish ranked result sets as one or more addressable events of kind 37573 in the following format:

{
  "kind": 37573,
  "pubkey": "<service_pubkey> | <subscription_pubkey> | <request_pubkey>",
  "tags": [
    // REQUIRED identifier
    // the `d` tag value SHOULD be equal to `request_id`
    // (the `d` tag value of the request event that triggered this output)
    ["d", "<request_id>"],

    // OPTIONAL `v` tags to help with discovery of request event
    ["v", "p:<request_author_pubkey>"],
    ["v", "d:<request_id>"],
    
    // REQUIRED ranked subjects (sorted by rank descending)
    // <type> is the tag letter (config `type`) for subjects in this output
    // <subject> is a unique identifier for each ranked subject
    // <rank> is the rank value from 0 to 100 assigned to this subject
    ["<type>", "<subject>", "<rank>"],
    // ... more ranked subjects
  ],
  "content": "" // empty or JSON with additional metadata
}

Appendix 2 : Example Implementations

The following are example ranking algorithm implementations that providers MAY offer. Each example shows a Service Announcement with the standard config inputs (for this ranking NIP) and some provider specific options. Each example also provides an example request and the expected algorithm behavior.

Example A: Baseline WoT Ranking

This example demonstrates a foundational web-of-trust ranking service that analyzes a user's social graph to rank other users based on follows, mutes, and reports. The service uses configurable weights for different interaction types and traverses the network to a specified depth, making it ideal for basic trust-based user discovery and filtering.

Algorithm Behavior:

  • Start from POV's follows (kind 3)
  • Iterate through network to specified depth
  • Weight by graph distance and mutual connections
  • Apply configured weights for follows, mutes, and reports
  • Output rank 0-100 based on influence score

Service Announcement:

{
  "kind": 37570,
  "pubkey": "provider123...",
  "tags": [
    ["d", "baseline_wot"],
    ["title", "Baseline Web of Trust Ranking"],
    ["summary", "Ranks users based on follows mutes and reports."],
    ["n", ".../tsm-ranking.md"],
    ["k", "37573"],
    ["r", "wss://relay.example.com"],
    // type is fixed at 'p' (it only ranks pubkeys)
    ["config", "type", "tagletter", "A tag letter for the subject type...", "p", "[\"p\"]"],
    // pov is required
    ["config", "pov", "subject|naddr", "A point of view subjects(s)..."],
    // minrank defaults to 0
    ["config", "minrank", "0-100", "Minimum rank threshold for inclusion in output...", "0"],

    // uppercase `V` tag is required to announce pagination support
    ["V", "page", "integer", "page number for this paginated event, along with a JSON array of d-tag values for all events in this set."],

    // provider specified configurable weights for interactions
    ["option", "depth_follows", "integer", "The network depth to analyze...", "6"],
    ["option", "weight_follows", "+-1", "Weight for follows...", "1"],
    ["option", "weight_mutes", "+-1", "Weight for mutes...", "0"],
    ["option", "weight_report_illegal", "+-1", "Weight for illegal reports...", "-1"],
    ["option", "weight_report_impersonation", "+-1", "Weight for impersonation reports...", "-1"],
    ["option", "weight_report_other", "+-1", "Weight for other reports...", "-1"],

    // additional info on ranking algo
    ["info", "pagesize", "1000", "Maximum subjects per output event"],
    ["info", "algorithm", "graperank", "Name of the algorithm implemented by this service"],
    ["info", "version", "1.1.0", "Version of the algorithm implemented by this service"],
    ["info", "source", "https://gitlab.com/...", "Source code repository for this service"],
  ]
}

Service Request:

{
  "kind": 37572,
  "pubkey": "alice123...",
  "tags": [
    ["d", "alice_wot"],
    ["k", "37573"],
    ["p", "provider123..."],
    ["a", "37570:provider123...:baseline_wot"],
    ["r", "wss://myrelay.example.com"],
    ["config", "pov", "alice123..."],
    ["option", "depth_follows", "4"],
    ["option", "weight_mutes", "-0.5"]
  ]
}

Output Event:

{
  "kind": 37573,
  "pubkey": "provider123...",
  "tags": [
    ["d", "alice_wot"],
    ["v", "p:alice123..."],
    ["v", "page:1", "[\"alice_wot\", \"alice_wot:2\", \"alice_wot:3\"]"],
    ["v", "total:2100"],
    ["p", "bob_pubkey...", "95"],
    ["p", "carol_pubkey...", "87"],
    ["p", "dave_pubkey...", "76"]
    // ... 997 more ranked users (1000 per paginated event)
  ]
}

Example B: WoT + Engagement Ranking

This example shows how to compose ranking services by using the output of one service as input to another. It takes a baseline WoT ranking (via naddr reference) and re-ranks those users based on engagement metrics (zaps, replies, reactions). This demonstrates the power of service composition, allowing users to layer multiple ranking algorithms to create sophisticated, personalized discovery feeds.

Algorithm Behavior:

  • Load subjects from POV naddr (baseline_wot output event)
  • Analyze interactions (zaps sent, replies, reactions) for those subjects since the specified timestamp
  • Weight different interaction types according to configured weights
  • Calculate engagement score per user based on weighted interactions
  • Output rank 0-100 normalized across all ranked subjects from POV

Service Announcement:

{
  "kind": 37570,
  "pubkey": "provider456...",
  "tags": [
    ["d", "wot_plus_engagement"],
    ["title", "Web of Trust + Engagement"],
    ["summary", "Ranks users based on engagement (zaps, replies, reactions)"],
    ["n", "./tsm-ranking.md"],
    ["k", "37573"],
    ["r", "wss://relay.example.com"],
    
    // type is fixed at 'p' (it only ranks pubkeys)
    ["config", "type", "tagletter", "Subject type to rank (fixed at 'p' for users)", "p", "[\"p\"]"],
    // pov is required
    ["config", "pov", "subject|naddr", "Point of view subject(s) for ranking"],
    // minrank defaults to 0
    ["config", "minrank", "0-100", "Minimum rank threshold for inclusion in output", "0"],
    // since is required for engagement analysis
    ["config", "since", "timestamp", "Consider events after this timestamp"],
    
    // uppercase `V` tag is required to announce pagination support
    ["V", "page", "integer", "page number for this paginated event, along with a JSON array of d-tag values for all events in this set."],

    // provider-specific configurable weights for interaction types
    ["option", "weight_zaps", "0-1", "Weight for zap interactions in engagement score", "0.5"],
    ["option", "weight_replies", "0-1", "Weight for reply interactions in engagement score", "0.3"],
    ["option", "weight_reactions", "0-1", "Weight for reaction interactions in engagement score", "0.2"],
    
    // additional info on ranking algorithm
    ["info", "pagesize", "1000", "Maximum subjects per output event"],
    ["info", "algorithm", "engagement", "Name of the algorithm implemented by this service"],
    ["info", "version", "1.0.0", "Version of the algorithm implemented by this service"],
    ["info", "source", "https://github.com/example/engagement-ranker", "Source code repository for this service"]
  ]
}

Service Request:

{
  "kind": 37572,
  "pubkey": "alice123...",
  "tags": [
    ["d", "alice_engagement"],
    ["k", "37573"],
    ["p", "provider456..."],
    ["a", "37570:provider456...:wot_plus_engagement"],
    ["r", "wss://myrelay.example.com"],
    // Using the naddr of alice's baseline_wot output as POV
    ["config", "pov", "naddr1qqxnzd3cxqmrzv3exgmr2wfexyuewdehhxarjxq6nwden..."],
    ["config", "since", "1704067200"],
    ["option", "weight_zaps", "0.6"],
    ["option", "weight_replies", "0.3"],
    ["option", "weight_reactions", "0.1"]
  ]
}

Output Event:

{
  "kind": 37573,
  "pubkey": "provider456...",
  "tags": [
    ["d", "alice_engagement"],
    ["v", "p:alice123..."],
    ["v", "page:1", "[\"alice_engagement\", \"alice_engagement:2\", \"alice_engagement:3\"]"],
    ["v", "total:2100"],
    ["p", "bob_pubkey...", "92"],
    ["p", "eve_pubkey...", "88"],
    ["p", "frank_pubkey...", "81"]
    // ... 997 more ranked users (1000 per paginated event)
    // ... of 2100 total ranked users from baseline_wot output
  ]
}

Example C: Content Quality Ranking

This example illustrates an AI-powered ranking service that evaluates the quality of kind 1 notes (content) from a set of authors. The service accepts a list of pubkeys (either directly or via naddr reference to an event with p tags) as the POV, fetches recent notes from those authors, and ranks the individual notes by quality. This makes it useful for creating a feed of high-quality ranked content from a specific set of authors.

Algorithm Behavior:

  • Load pubkeys from POV (either a single pubkey or naddr to an event with p tags)
  • Fetch recent kind 1 notes from those authors (up to notesperauthor per author)
  • Analyze each note with configured AI model for quality signals
  • Consider optional topic context if provided
  • Rank individual notes (events) by quality score
  • Output rank 0-100 for each note, normalized across all analyzed content

Service Announcement:

{
  "kind": 37570,
  "pubkey": "provider789...",
  "tags": [
    ["d", "quality_ranker"],
    ["title", "Content Quality Ranker"],
    ["summary", "AI-powered content quality ranking based on note analysis from specified authors"],
    ["n", "./tsm-ranking.md"],
    ["k", "37573"],
    ["r", "wss://relay.example.com"],
    
    // type is fixed at 'e' (ranks events by their content quality)
    // but POV should contain pubkeys (authors whose content will be ranked)
    ["config", "type", "tagletter", "Subject type to rank (fixed at 'e' for events)", "e", "[\"e\"]"],
    // pov should be pubkey(s) or naddr to event with p tags (the authors)
    ["config", "pov", "subject|naddr", "Pubkey(s) of authors whose content will be analyzed and ranked"],
    // minrank defaults to 0
    ["config", "minrank", "0-100", "Minimum rank threshold for inclusion in output", "0"],

    // uppercase `V` tag is required to announce pagination support
    ["V", "page", "integer", "page number for this paginated event, along with a JSON array of d-tag values for all events in this set."],

    
    // provider-specific options for AI analysis
    ["option", "kind", "integer", "Event kind to analyze", "1"],
    ["option", "prompt", "string", "Topic on which to rank notes (e.g., 'bitcoin OGs and influencers', 'chicago DJs and musicians')", ""],
    ["option", "notes_per_author", "integer", "Number of recent notes per author to fetch", "10"],
    ["option", "since", "timestamp", "Only analyze notes after this timestamp", "0"],
    
    // additional info on ranking algorithm
    ["info", "pagesize", "500", "Maximum subjects per output event"],
    ["info", "algorithm", "content_quality", "Name of the algorithm implemented by this service"],
    ["info", "version", "2.0.0", "Version of the algorithm implemented by this service"],
    ["info", "source", "https://github.com/example/quality-ranker", "Source code repository for this service"]
  ]
}

Service Request:

{
  "kind": 37572,
  "pubkey": "alice123...",
  "tags": [
    ["d", "chicago_djs_musicians"],
    ["title", "Chicago DJs and Musicians"],
    ["summary", "YO! Check it! Da bomb list of my closest friends!"],
    ["k", "37573"],
    ["p", "provider789..."],
    ["a", "37570:provider789...:quality_ranker"],
    ["r", "wss://myrelay.example.com"],
    // Using the output naddr from alice's baseline_wot as POV
    // (this references a kind 37573 event with ranked pubkeys as p tags)
    ["config", "pov", "naddr1qqxnzd3cxqmrzv3exgmr2wfe..."],
    ["option", "prompt", "chicago's top DJs and musicians"],
    ["option", "notes_per_author", "5"],
    ["option", "since", "1704067200"]
  ]
}

Output Event (page 2)

{
  "kind": 37573,
  "pubkey": "provider789...",
  "tags": [
    ["d", "chicago_djs_musicians:2"],
    ["v", "p:alice123..."],
    ["v", "d:chicago_djs_musicians"],
    ["v", "total:150"],
    ["v", "page:2", "[\"chicago_djs_musicians\", \"chicago_djs_musicians:2\"]"],
    // Ranked kind 1 events by quality score
    ["e", "note_event_id_1...", "98"],
    ["e", "note_event_id_2...", "94"],
    ["e", "note_event_id_3...", "89"],
    ["e", "note_event_id_4...", "85"]
    // ... more ranked notes
  ]
}