Skip to content

NIP-90 version 2.0 #1941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

NIP-90 version 2.0 #1941

wants to merge 1 commit into from

Conversation

dtdannen
Copy link

This new DVM spec is the result of a collaborative effort from @believethehype, @gzuuus, @pippellia-btc, and others. We have reached a general consensus and believe it addresses many of the issues from this thread #1903

The major changes are:

  • moving from kinds 5000-7000 to ephemeral kinds 20000-29999
  • moving from NIP-89 to a new announcement scheme that includes support for providers who run multiple DVMs
  • the response kind can be set by a DVM to be anything, although we give a strong recommendation that this should be an ephemeral event equal to 1 + request kind (instead of the previous 1000+request kind)
  • we added guidance sections for DVM developers, Client developers, and Relay operators
  • we added an introduction that compares DVMs to APIs, and providers broader context about DVMs in general
  • concrete examples of all types of events
  • added a FAQ

@dtdannen dtdannen mentioned this pull request May 29, 2025
@dtdannen
Copy link
Author

In addition, this PR is based on suggestions from other existing PRs, including:

@vitorpamplona
Copy link
Collaborator

Why is the range even needed? Why can't DVMs choose whatever request and response kinds they want?

@dtdannen
Copy link
Author

dtdannen commented May 29, 2025

Can you describe an example where a request shouldn't be ephemeral?

@dtdannen
Copy link
Author

dtdannen commented May 29, 2025

To be clear, the request kind is defined to be ephemeral and the response theoretically can be anything, but in the common use cases where the results are just for the user to use immediately, the response kind should also be ephemeral and use the convention of a response kind number = request kind + 1

@vitorpamplona
Copy link
Collaborator

Can you describe an example where a request shouldn't be ephemeral?

The point is that the range doesnt do anything. If most DVMs are ephemeral, great. They will choose those kinds. We don't need to define it here. It's not really adding anything.

Same for the +1. If that is what DVMs do, great. If not, that's ok as well. Following the rule doesn't really do anything.

@fiatjaf
Copy link
Member

fiatjaf commented May 29, 2025

This seems to be better than the first spec in some ways (although it doesn't fix most of my issues with that, and adds a few new ones), but I thought you were going to fix the existing spec to make it match the behavior of the existing DVMs and that was why my proposal of resetting the spec was so bad: because it broke everything that existed. Now you come up with a new proposal that also breaks everything?

@pippellia-btc
Copy link

Why is the range even needed? Why can't DVMs choose whatever request and response kinds they want?

DVM providers don't have to run a relay, in which case they would simply connects to other relays, which will be used to facilitate the request-response flow with their customers. Using ephemeral events for the requests is a way to respect the relays for their service. In fact, requests are cheap to make, and storing them indefinitely is almost never useful.

Responses on the contrary can have any kind (e.g. a code review DVM responses with a PR event or a wiki event), as they are not cheap to make.

@pippellia-btc
Copy link

although it doesn't fix most of my issues with that, and adds a few new ones

which ones @fiatjaf ?

Now you come up with a new proposal that also breaks everything?

Yes, who cares. Nostr in general but DVMs in particular are new and the is not point in ossifying the spec just because 3 users are using it. I say this as someone that will change its own service to follow the new spec.

@vitorpamplona
Copy link
Collaborator

Why is the range even needed? Why can't DVMs choose whatever request and response kinds they want?

DVM providers don't have to run a relay, in which case they would simply connects to other relays, which will be used to facilitate the request-response flow with their customers. Using ephemeral events for the requests is a way to respect the relays for their service. In fact, requests are cheap to make, and storing them indefinitely is almost never useful.

Sure, but why are we forcing it? People that have their own relays don't need to use ephemeral kinds. If some DVMs use cases can be enhanced by keeping and showing a history of requests to the user, they should not be ephemeral.

Since this is just a design pattern NIP for DVMs, these types of choices should be made by each DVM type. Especially because they don't produce any specific interoperable outcome.

@pablof7z
Copy link
Member

I haven't finished reading, but a few comments from skimming through:

  • drop LN payments; it's a bug part of what kills the UX, it's so much slower and introduces latency at the most critical stage of usage; just do cashu: if the DVM doesn't trust anyone it can run its own mint which is trivial to run on top of their LN node already.

Remove alternative payments like zaps, almost no one implemented those and they were a terrible idea.

Add streaming results: the dvm can send a bunch of ephemeral events, for example for text generation dvms that'd be very useful.

1 similar comment
@pablof7z
Copy link
Member

I haven't finished reading, but a few comments from skimming through:

  • drop LN payments; it's a bug part of what kills the UX, it's so much slower and introduces latency at the most critical stage of usage; just do cashu: if the DVM doesn't trust anyone it can run its own mint which is trivial to run on top of their LN node already.

Remove alternative payments like zaps, almost no one implemented those and they were a terrible idea.

Add streaming results: the dvm can send a bunch of ephemeral events, for example for text generation dvms that'd be very useful.

@pippellia-btc
Copy link

Since this is just a design pattern NIP for DVMs, these types of choices should be made by each DVM type. Especially because they don't produce any specific interoperable outcome.

I would not be against what you are saying in principle, I just think that strongly suggesting the use of ephemeral requests should be part of the spec.

@pippellia-btc
Copy link

@pablof7z these payments are just suggestions/examples of how to monetize a DVM, not mandatory ofc.

Add streaming results: the dvm can send a bunch of ephemeral events, for example for text generation dvms that'd be very useful.

I don't think there is something in this spec that prevents a DVM from sending multiple responses to the same request.

Also, a DVM can respond with a single event that mentions several event IDs

@staab
Copy link
Member

staab commented May 29, 2025

There are some good things about this, in particular 31999 events, which is a huge improvement over nip 89. But I think it also fails to address the main problem with the original DVM spec, which is that any monolithic spec is going to be over-prescriptive.

Instead of schemas/kinds, I think dvm announcements should probably specify some other identifier (the DVM equivalent of a NIP number) which describes a flow. The DVM spec should be entirely agnostic of request formats and response formats. The feedback event I'm less sure of, since it would be useful to have a re-usable specification for brokering payments and such, but that should probably be defined in the sub-spec as well, or as an independent flow that can be looped in as needed.

I've mentioned this before, but take #1796 as an example. It's designed for asynchronous, long-term use, so kind 3xxxx events are used instead of ephemeral events. This gives us a "subscription request", "subscription response" flow that might be maintained over a period of months or years. I'd like to be able to use 31999 to announce notifiers as relay-based services, but that's not possible with this PR.

This illustrates the original problem with the DVM spec (regardless of whether you like the notifiers nip): the essence of DVMs is that they are services that have zero or more side effects (whether nostr events, emails, or mail courier dispatches, etc) in a predictable way in response to one or more nostr events. The breadth of this definition is a good thing; I want to advertise a flow — any flow. It's up to implementations to choose whether or not to support them. There's no way around actual implementation. Schemas feel magical, but they only work insofar as there are driving assumptions built in.

Some plausible flows, just to illustrate the range of possibilities DVMs might cover:

  • Manually fulfilled requests. If a request comes with a payment, it could fund mechanical-turk type flows. Ephemeral events wouldn't be sufficient for this, since response times might be measured in days and both parties would have to be online to receive events.
  • Long-standing relationships (see Add notifiers nip #1796 again for an example). The requester publishes a request for an ongoing service using a kind 3xxxx event, and the service publishes a kind 3xxxx response with information about the service status. Either party may change their "contract" at any time, forcing the other party to confirm, cancel, or change how the service is fulfilled. This could be useful for any consumer-type relationship (like the guys who winterize my sprinklers every year).
  • Multi-step flows: I publish an intent to consign a t-shirt at a local store. They respond by saying they want more information. I respond by providing more information. They respond by saying they'll take it. I respond by bringing the actual item in. They respond by saying they took it, here's when it expires, here's how much you'll get, etc. 30 days later, the item expires and they respond by saying I need to pick it up. I pick it up. The contract is closed. This could be the same as the previous example using 3xxxx events, or it could be a series of regular events that establish an audit log.
  • Reverse flows: instead of the user requesting something, the service starts by publishing something (for example gated content that unlocks after a certain amount of zaps, or a request for survey takers). The user then responds to the service as specified in the flow, for example by zapping the content, or by taking a survey. The service then unlocks the content, or pays the user for their survey response.
  • Flows involving 3+ parties — e.g. multi-sig bunker providers, notaries, bids for contracts, etc.

These different cases can't be supported by a single infinitely-flexible NIP, because that's just a quest for the universal language (which we already have, it's called computation). But all of them would benefit from the service provider being able to 1. specify the flow, 2. publish a listing advertising their service. The specifications for these flows might be DIPs, NUDs, URLs, or NIPs, it doesn't really matter on what level they're defined.

Since I've spent my morning writing this post, I've gone ahead and opened a PR with my version of the re-write here: #1942

@staab
Copy link
Member

staab commented May 29, 2025

I should add that the key thing about DVMs seems to be that service providers can advertise adherence to a spec. This encourages interoperability by offering free advertising, just like NIP 89 does for clients. What the actual implementation looks like is only secondary to the fact that users can discover multiple interoperable service providers, which transfers the redundancy characteristics we get from relays/clients to any real-world service, reducing censorship and vendor lock-in. This is the entire "new internet"/"other stuff" part of nostr.

@fiatjaf
Copy link
Member

fiatjaf commented May 29, 2025

Yes, who cares.

Maybe you never cared, but I have the impression that this was the main complaint against my other PR coming from @vitorpamplona and @believethehype.

which ones @fiatjaf ?

  • the fact that it makes no sense for a standard to not define a standard but allows anyone to create their own standard (although having a clear schema at least makes that more explicit, which is good)
  • the fact that the Nostr-RPC interface isn't always the best, the fact that we're using a bunch of different kinds for no reason since nothing is interoperable anyway
  • the fact that the spec excludes other forms of communication and of the services that can be provided by circumscribing them to this often inefficient request-response interface and limits the imagination of new developers (I've listed many examples in my PR comments), it also excludes services that could be provided without a request, or services that wouldn't need a response in the form of an event, prepaid services etc
  • the fact that DVMs should probably have a kind:10002 (which would solve the problem of to what relays these requests should be sent, for example)

Anyway, I think #1942 solves it best.

@pippellia-btc
Copy link

Instead of schemas/kinds, I think dvm announcements should probably specify some other identifier (the DVM equivalent of a NIP number) which describes a flow.

IMO this indirection would hinder convergence of flows/schemas, which is something very desirable, and the main drawback of APIs @staab (and the current DVMs).

I also don't think it's desirable for the usecases you mentioned to be within the definition of a DVM. After all, if anything can be a DVM, then what's the point of a spec? Specifically:

Manually fulfilled requests...

The user looking to perform manual work just needs a client/relay that stores these ephemeral events. After doing the work he publishes the response, which can be any kind. The customer doesn't even have to store the request, only its ID.

Long-standing relationships...

I think this is sufficiently different from the request/response flow that should be handled separately.

Multi-step flows...

Very distance from what this spec has in mind for a DVM, but can actually be done by a succession of request, feedback event, request, feedback event... response. It would certainly be a hacky way.

Flows involving 3+ parties...

Most likely all interested parties can be part of some form of multisig. If the quorum is reached, then the request is made, which will be followed by the response.

The current schema can even allow for multiple requests and multiple responses, by simply using a list of event IDs in the response/request event.

@dtdannen
Copy link
Author

I think dvm announcements should probably specify some other identifier (the DVM equivalent of a NIP number) which describes a flow.

This is already done - the DVM picks a request kind that is the specific flow they adhere to. A DVM announcement will have a documentation tag describing the specific flow.

Then once there are 1 or more DVMs running on a new kind, someone (or an AI) can come along and write a kind spec for that specific request kind.

@dtdannen
Copy link
Author

I'd like to remind everyone that many people want to run DVMs in a common pattern, which is the goal of this NIP. For example, the new kind 5050 nip about LLMs is compatible with this new NIP-90 spec.

If people really want to change the request kind to be anything, that's pretty minor IMO. The DVMs already announce whatever kind they want to use and they could pick a non ephemeral one if they wanted. The only change would be to the table in the beginning.

It does feel like a lot of commenters here didn't read the intro or the guidance section for devs at the bottom. We explain the benefits of DVMs, the inherent flexibility, and recommended ways of doing things. This is compatible with at least 20+ DVMs that people are already running.

Can it be okay that NIP-90 gets updated to this design pattern where the only hard requirement on kinds is the announcement kinds? And everything else is a recommendation?

From a practical point of view, this new spec seems to solve actual problems people have had.

@dtdannen
Copy link
Author

@vitorpamplona besides the request kinds being defined in a range, is there any other big issue you have with this new version?

@staab
Copy link
Member

staab commented May 29, 2025

I won't die on the request/response vs other flows hill. If we want an announcement event that is coupled to the more common DVM flow, that's fine (and would allow 31999s to define schemas for additional parameters). We can just make another announcement event for each DVM-like NIP.

The important thing is that NIPs should be primarily descriptive, not prescriptive. This document is fine as a "collection of recommendations for people who want to create a new DVM", but it's not a "spec", because it really doesn't describe very much about actual DVM flows — because there's very little we can say about DVMs that is generally true.

Whatever in this spec is actionable across all DVMs in a backwards-compatible way can stay. The rest should be moved to a very large "recommendations for people creating a new dvm" section, or a separate web page. The only thing that qualifies in my mind is 31999 events.

@vitorpamplona
Copy link
Collaborator

@vitorpamplona besides the request kinds being defined in a range, is there any other big issue you have with this new version?

After reading it again and comparing it with other proposals, it feels like we are trying to make many different ideas into just one NIP:

  • DVMs with just one announcement are 1 type
  • DVMs with Provider Announcements are a second thing and could be a separate NIP.
  • Free DVMs are one NIP
  • Paid DVMs can be multiple NIPs, one for each payment flow type.

Heartbeats are good since we already have way too many old DVMs that are not active anymore. We need to find a way to get rid of those if the operator just walks away.

General Job status flows are good.

Error handling flows are tricky. I fear that each type of DVM would have to re-specify/clarify/add information in them for their own needs, which defeats the purpose of a general approach for error handling. It's similar to how each NIP re-defines every tag name, even those that we call "global tags". There is no such thing as a "global tag" that works on all NIPs without any changes.

Payment flow: If there is really just one for every possible DVM, then it should be defined here. If not, then we will need to move it to each DVM type specification. I don't think we should have so many different types of payments in the general NIP, since clients will never implement all of them at the same time, and thus will need to filter DVMs by the supported payment flows in each app.

The input_schema and output_schema will never be used. So, I would just remove them.

On a larger note, I am not a fan of having multiple DVMs running as the same key. We don't do that for users in any other NIP. There are no subtopics for users. They have to create new npubs if they want to have a separate audience. To me this flow should be followed by the DVMs and if that is the case, the announcement should not have the info that is already on the NPUB's metadata event (name, about, etc). This is especially significant after http://following.space, where you can easily do a "Pack of DVMs" from the same provider.

@pippellia-btc
Copy link

pippellia-btc commented Jun 1, 2025

After reading it again and comparing it with other proposals, it feels like we are trying to make many different ideas into just one NIP:

  • DVMs with just one announcement are 1 type
  • DVMs with Provider Announcements are a second thing and could be a separate NIP.
  • Free DVMs are one NIP
  • Paid DVMs can be multiple NIPs, one for each payment flow type

I disagree with the first two points because in my mind they are really complementary. DVMs are trusted relationships/computation, so knowing the entity behind them can be very important (e.g. Vertex WoT DVMs).

Provider announcements are a convenient way for the service provider to show its offering, to signal support for a new DVM or drop support for an existing one.

Similar for the last two points. What starts as a free DVM can't remain free forever, so it will have to migrate to the paid spec.

@vitorpamplona
Copy link
Collaborator

I disagree with the first two points because in my mind they are really complementary.

It will be virtually impossible to support this entire NIP, with all payments and all modes. That's why separating is important. In that way, clients can declare full compliance with parts of this, making it easier to develop and creating better expectations for users.

@pippellia-btc
Copy link

It will be virtually impossible to support this entire NIP, with all payments and all modes.

Yes totally. I think payments were supposed to be example, am I right @dtdannen ?

The way I see it is that clients will integrate only the DVM kinds they are interested in (e.g. search DVMs, DVM feeds...). Each kind will have its own top-down or emergent spec, while all will follow the discovery, request and error handling patterns here described.

@vitorpamplona
Copy link
Collaborator

vitorpamplona commented Jun 1, 2025

Here's a different approach: Instead of redefining NIP-90, why don't we keep NIP-90 as is (so there is some documentation for current DVMs) and create NIP-9A DVMs without any need to support old models?

The concept of a DVM doesn't need to be defined in a single NIP. We don't need to rug-pull current NIP-90 implementations by redefining it. Having versions established in separate NIPs (e.g. NIP-04 and NIP-44 encryptions) allows the community to slowly migrate to the new one if it is actually better instead of forcing these new concepts into the "old guard". If NIP-9A is in fact better, its usage will be bigger than NIP-90 and you have proven your point.

Because of that, nothing here needs to pay attention in supporting old DVM models/flows. You could just start fresh with a brand new flow for DVMs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants