Curated Feeds: A Simpler Alternative to DVM Feeds

Max

npub1klkk3vrzme455yh9rl2jshq7rc8dpegj3ndf82c3ks2sk40dxt7qulx3vt

hex

09529667147e100a90f534b8ca7ed9ec3d96dbd86b20cf10873ecd21ab9cc3cf

nevent

nevent1qqsqj55kvu28uyq2jr6nfwx20mv7c0vkm0vxkgx0zzrnanfp4wwv8ncprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgst0mtgkp3du662ztj3l4fgts0purksu5fgek5n4vgmg9gt2hkn9lq4sngnm

naddr

naddr1qqgxyvf4v3jrqve3893xgwrzvvcnzqgcwaehxw309aex2mrp0yhxwatvw4nh2mr49ekk7egzyzm7669svt0xkjsju50a22zurc0qa589z2xd4yatzx6p2z64a5e0cqcyqqq823cxws30h

Kind-30023 (Article)

2025-11-28T18:35:02Z

DVMs were designed as a general-purpose compute marketplace, and while they work for feeds, the request/response model is overkill when all you need is a list of event IDs.

The problem with DVM feeds

When a client wants a feed from a DVM, it publishes a kind 5300 job request, waits for the request to propagate through relays, then waits again for the DVM to detect it, compute results, and publish a kind 6300 response. Every request exposes your pubkey and follows to the provider, and if you want fresh results, you repeat the entire flow.

Curated feeds: invert the model

The core idea: publishers maintain a replaceable event containing an ordered list of recommended content, and clients subscribe to it directly using standard Nostr filters.

{
  "kind": 30405,
  "tags": [
    ["d", "bitcoin-daily"],
    ["title", "Bitcoin Daily"],
    ["k", "1"],
    ["e", "<event-id>", "<relay-hint>"],
    ["e", "<event-id>", "<relay-hint>"]
  ]
}

The k tag indicates what kind of events the feed contains, so a microblogging client can filter out long-form article feeds without fetching everything first. The publisher updates this event whenever they want, updated as needed, and clients receive updates automatically through their existing websocket subscription, publishing nothing themselves.

Personalization

For users who want a feed tailored to their interests, the negotiation happens out of band. The user contacts the provider, agrees on terms, pays if required, and the provider creates a new feed with a unique d tag for that user. The user then subscribes to their personalized feed like any other curated feed, keeping the protocol simple while allowing arbitrary business models on top.

Comparison

| | DVM Feeds | Custom Feeds NIP | NIP-32 Labels | NIP-51 Curation Sets | Curated Feeds | |---|---|---|---|---|---| | Purpose | On-demand compute | Feed recipes | Content tagging | User bookmarks | Live feed publishing | | Latency | Request/response round trip | Depends on source | Requires relay support | Instant | Instant | | Privacy | Request reveals user interests | Varies | Label queries may leak interests | Private to user | Zero metadata exposed | | Complexity | Multiple event kinds, status flows, payment negotiation | Complex recipe format with set operators | Separate labeling events | Not designed for third-party feeds | One replaceable event | | Live updates | Must re-request | Must re-evaluate | Must re-query labels | Manual refresh | Automatic via subscription | | Use case | Personalized computation | Composable feed definitions | Distributed moderation, categorization | Personal collections | Editorial curation |

Full spec below.


NIP-XX: Curated feeds

draft optional

This NIP defines a simple mechanism for publishing curated feeds of Nostr events. Unlike DVM-based feeds (NIP-90), curated feeds require no request/response flow. Publishers maintain replaceable events containing ordered lists of recommended content that clients subscribe to directly.

Event format

A curated feed is a parameterized replaceable event of kind 30405:

{
  "kind": 30405,
  "tags": [
    ["d", "<feed-identifier>"],
    ["title", "<human-readable name>"],
    ["description", "<what this feed contains>"],
    ["k", "<kind of events in feed>"],
    ["e", "<event-id>", "<relay-hint>"],
    ["e", "<event-id>", "<relay-hint>"],
    ["a", "<kind>:<pubkey>:<d-tag>", "<relay-hint>"]
  ],
  "content": ""
}

Tags

  • d - Required. Unique identifier for this feed.
  • title - Optional. Human-readable feed name.
  • description - Optional. Description of the feed's purpose or algorithm.
  • k - Optional. The kind of events this feed contains (e.g., "1" for notes, "30023" for articles). Clients MAY use this to filter feeds by content type.
  • e - Event references. Order is significant: first tag is the top recommendation.
  • a - Addressable event references (articles, etc). Order is significant.

Publishers SHOULD limit feeds to a reasonable size (e.g., 50-200 items). Clients SHOULD treat tag order as the intended display order.

Client behavior

Clients subscribe to feeds using standard filters:

{"kinds": [30405], "authors": ["<publisher-pubkey>"], "#d": ["<feed-id>"]}

When the publisher updates the feed, clients receive the new version automatically via their existing subscription. Clients MAY cache previous versions to highlight new additions.

Discovery

Content curators MAY publish a curator profile event of kind 10405 to advertise themselves and list their available feeds:

{
  "kind": 10405,
  "tags": [
    ["name", "<curator name>"],
    ["about", "<description of curation focus>"],
    ["a", "30405:<pubkey>:<feed-d-tag>", "<relay-hint>"],
    ["a", "30405:<pubkey>:<feed-d-tag>", "<relay-hint>"]
  ],
  "content": ""
}

Clients can discover curators by querying for kind 10405 events and display their available feeds to users.

Custom feeds

Publishers MAY offer personalized feeds on request. The negotiation, payment, and delivery mechanism is out of scope for this NIP. A typical flow:

  1. User requests a custom feed from a publisher (out of band)
  2. Publisher creates a new feed with a unique d tag for that user
  3. Publisher communicates the d tag to the user
  4. User subscribes to their personalized feed

Why not DVMs?

NIP-90 DVMs require clients to publish job requests and wait for responses. The round-trip creates latency and exposes user interests to providers. Curated feeds invert the model: publishers proactively maintain feed state, clients subscribe.

Raw JSON

{
  "kind": 30023,
  "id": "09529667147e100a90f534b8ca7ed9ec3d96dbd86b20cf10873ecd21ab9cc3cf",
  "pubkey": "b7ed68b062de6b4a12e51fd5285c1e1e0ed0e5128cda93ab11b4150b55ed32fc",
  "created_at": 1777543606,
  "tags": [
    [
      "d",
      "b15dd0319bd8bc11"
    ],
    [
      "image",
      "https://image.nostr.build/bbb0e250c2e1aa6428ccaf49081c7e8601e0d027ee1d99c4fb3ff149003bc6b5.jpg"
    ],
    [
      "title",
      "Curated Feeds: A Simpler Alternative to DVM Feeds"
    ],
    [
      "summary",
      "Replace DVM request/response overhead with simple replaceable events. Publishers maintain feed lists, clients just subscribe. No round trips, no privacy leakage"
    ],
    [
      "published_at",
      "1764354902"
    ],
    [
      "t",
      "austrian-economics"
    ],
    [
      "t",
      "freedom-tech"
    ],
    [
      "t",
      "nostr"
    ],
    [
      "t",
      "nip"
    ],
    [
      "t",
      "dvm"
    ],
    [
      "t",
      "decentralization"
    ],
    [
      "t",
      "relay"
    ],
    [
      "t",
      "privacy"
    ],
    [
      "t",
      "custom-feeds"
    ],
    [
      "t",
      "feed-algorithm"
    ],
    [
      "t",
      "d"
    ]
  ],
  "content": "DVMs were designed as a general-purpose compute marketplace, and while they work for feeds, the request/response model is overkill when all you need is a list of event IDs.\n\n## The problem with DVM feeds\n\nWhen a client wants a feed from a DVM, it publishes a kind 5300 job request, waits for the request to propagate through relays, then waits again for the DVM to detect it, compute results, and publish a kind 6300 response. Every request exposes your pubkey and follows to the provider, and if you want fresh results, you repeat the entire flow.\n\n## Curated feeds: invert the model\n\nThe core idea: publishers maintain a replaceable event containing an ordered list of recommended content, and clients subscribe to it directly using standard Nostr filters.\n\n```json\n{\n  \"kind\": 30405,\n  \"tags\": [\n    [\"d\", \"bitcoin-daily\"],\n    [\"title\", \"Bitcoin Daily\"],\n    [\"k\", \"1\"],\n    [\"e\", \"\u003cevent-id\u003e\", \"\u003crelay-hint\u003e\"],\n    [\"e\", \"\u003cevent-id\u003e\", \"\u003crelay-hint\u003e\"]\n  ]\n}\n```\n\nThe `k` tag indicates what kind of events the feed contains, so a microblogging client can filter out long-form article feeds without fetching everything first. The publisher updates this event whenever they want, updated as needed, and clients receive updates automatically through their existing websocket subscription, publishing nothing themselves.\n\n## Personalization\n\nFor users who want a feed tailored to their interests, the negotiation happens out of band. The user contacts the provider, agrees on terms, pays if required, and the provider creates a new feed with a unique `d` tag for that user. The user then subscribes to their personalized feed like any other curated feed, keeping the protocol simple while allowing arbitrary business models on top.\n\n## Comparison\n\n| | DVM Feeds | Custom Feeds NIP | NIP-32 Labels | NIP-51 Curation Sets | Curated Feeds |\n|---|---|---|---|---|---|\n| Purpose | On-demand compute | Feed recipes | Content tagging | User bookmarks | Live feed publishing |\n| Latency | Request/response round trip | Depends on source | Requires relay support | Instant | Instant |\n| Privacy | Request reveals user interests | Varies | Label queries may leak interests | Private to user | Zero metadata exposed |\n| Complexity | Multiple event kinds, status flows, payment negotiation | Complex recipe format with set operators | Separate labeling events | Not designed for third-party feeds | One replaceable event |\n| Live updates | Must re-request | Must re-evaluate | Must re-query labels | Manual refresh | Automatic via subscription |\n| Use case | Personalized computation | Composable feed definitions | Distributed moderation, categorization | Personal collections | Editorial curation |\n\nFull spec below.\n\n---\n\n# NIP-XX: Curated feeds\n\n`draft` `optional`\n\nThis NIP defines a simple mechanism for publishing curated feeds of Nostr events. Unlike DVM-based feeds (NIP-90), curated feeds require no request/response flow. Publishers maintain replaceable events containing ordered lists of recommended content that clients subscribe to directly.\n\n## Event format\n\nA curated feed is a parameterized replaceable event of kind `30405`:\n\n```json\n{\n  \"kind\": 30405,\n  \"tags\": [\n    [\"d\", \"\u003cfeed-identifier\u003e\"],\n    [\"title\", \"\u003chuman-readable name\u003e\"],\n    [\"description\", \"\u003cwhat this feed contains\u003e\"],\n    [\"k\", \"\u003ckind of events in feed\u003e\"],\n    [\"e\", \"\u003cevent-id\u003e\", \"\u003crelay-hint\u003e\"],\n    [\"e\", \"\u003cevent-id\u003e\", \"\u003crelay-hint\u003e\"],\n    [\"a\", \"\u003ckind\u003e:\u003cpubkey\u003e:\u003cd-tag\u003e\", \"\u003crelay-hint\u003e\"]\n  ],\n  \"content\": \"\"\n}\n```\n\n## Tags\n\n- `d` - Required. Unique identifier for this feed.\n- `title` - Optional. Human-readable feed name.\n- `description` - Optional. Description of the feed's purpose or algorithm.\n- `k` - Optional. The kind of events this feed contains (e.g., \"1\" for notes, \"30023\" for articles). Clients MAY use this to filter feeds by content type.\n- `e` - Event references. Order is significant: first tag is the top recommendation.\n- `a` - Addressable event references (articles, etc). Order is significant.\n\nPublishers SHOULD limit feeds to a reasonable size (e.g., 50-200 items). Clients SHOULD treat tag order as the intended display order.\n\n## Client behavior\n\nClients subscribe to feeds using standard filters:\n\n```json\n{\"kinds\": [30405], \"authors\": [\"\u003cpublisher-pubkey\u003e\"], \"#d\": [\"\u003cfeed-id\u003e\"]}\n```\n\nWhen the publisher updates the feed, clients receive the new version automatically via their existing subscription. Clients MAY cache previous versions to highlight new additions.\n\n## Discovery\n\nContent curators MAY publish a curator profile event of kind `10405` to advertise themselves and list their available feeds:\n\n```json\n{\n  \"kind\": 10405,\n  \"tags\": [\n    [\"name\", \"\u003ccurator name\u003e\"],\n    [\"about\", \"\u003cdescription of curation focus\u003e\"],\n    [\"a\", \"30405:\u003cpubkey\u003e:\u003cfeed-d-tag\u003e\", \"\u003crelay-hint\u003e\"],\n    [\"a\", \"30405:\u003cpubkey\u003e:\u003cfeed-d-tag\u003e\", \"\u003crelay-hint\u003e\"]\n  ],\n  \"content\": \"\"\n}\n```\n\nClients can discover curators by querying for kind `10405` events and display their available feeds to users.\n\n## Custom feeds\n\nPublishers MAY offer personalized feeds on request. The negotiation, payment, and delivery mechanism is out of scope for this NIP. A typical flow:\n\n1. User requests a custom feed from a publisher (out of band)\n2. Publisher creates a new feed with a unique `d` tag for that user\n3. Publisher communicates the `d` tag to the user\n4. User subscribes to their personalized feed\n\n## Why not DVMs?\n\nNIP-90 DVMs require clients to publish job requests and wait for responses. The round-trip creates latency and exposes user interests to providers. Curated feeds invert the model: publishers proactively maintain feed state, clients subscribe.",
  "sig": "fdc28ab16db2dd04f173f00cef84d26bbdcfea70b382ca7b4c24f8d668a5ee2309275a8596e0be7fc0a4df4f281f91900550ac6cfbb3ed042095f77371ccdd18"
}