Skip to content
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

NIP-51 Lists #183

Merged
merged 18 commits into from
Mar 9, 2023
Merged

NIP-51 Lists #183

merged 18 commits into from
Mar 9, 2023

Conversation

monlovesmango
Copy link
Member

recreating previous lists nip that I inadvertently closed.

previous conversation here: #114

formatted: https://github.com/monlovesmango/nips/blob/lists/51.md

@monlovesmango monlovesmango changed the title Lists NIP-51 Lists Jan 23, 2023
Copy link
Member

@Giszmo Giszmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

Really love the simplicity of this nip. While I hope we get public blocking and keep follows public by default, people want private stuff.

51.md Outdated Show resolved Hide resolved
The parameter for the list event will comprised of `<type>:<name>`:
- `<type>` identifies the type of tags included in the list
- `<name>` identifies the list by name

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this part is needed. do we want to implicitly restrict list types here? I think that part should be handled in separate NIPs, and would allow to follow this model with lists that mix multiple kinds of tags by standardizing d tags.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the same spirit we could allow other structured types in the encrypted body - and we should. This leads me to question the purpose of this nip. Maybe it should be more prescriptive, not less? Maybe it should be exclusively about follow, mute and block as that might be something the OP could readily implement and experiment with.

The event pinning and bookmarks might belong into the profile and more structured encrypted data respectively.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

even if this NIP was only limited to follow, I would still want the type. I would want users to be able to create lists of hashtags, people, and events to follow. however putting those all into one event will be a mess for client implementation. there is no situation where hashtags and follows will be processed together, the client will always have to parse them out and handle them separately.

happy to drop pinned and bookmarks entirely. just threw them in bc seemed like people are itching for these.

- `follow` - a list of tags that the user wants to follow
- `pin` - a list of tags that the user wants to pin (for display on profile)
- `bookmark` - a list of tags that the user wants to bookmark

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for example, each of these ones (or multiple in batches) would be part of a NIP that references this one and NIP33 and standardizes the use of these names in d tags

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but how would the behavior change between the different lists?

Copy link
Member

@Giszmo Giszmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I changed my mind. This nip is not ready for being merged. We probably should not pack everything containing lists of pubkeys or events in the same kind no matter what.

I would appreciate if this nip was changed to simply covering mute/follow.

@monlovesmango
Copy link
Member Author

monlovesmango commented Jan 23, 2023

I think creating a nip for just mute/follow is fine. however, I think a nip for just mute/follow still should cover multiple event types. do we really want a nip for mute/follow of pubkeys, nip for mute/follow of events, nip for mute/follow of hashtags?

in my mind I would think we want a nip that is extensible and flexible, and can easily adapt as new use cases emerge.

@eskema
Copy link
Collaborator

eskema commented Jan 23, 2023

you always need to check each tag, you can't ever simply "trust" that it's any kind of tags in there, so specifying what each specific 'd' word means is I think something that belongs in it's own NIP. this NIP would simply introduce the concept of using the tags and encrypted content with the same type of tags inside, but one is private, the other is public. be that exclusively p tags or exclusively e tags or t tags or any combination that anyone seems fit to their purpose, which would then be a NIP and we can expect the same behaviour. you can of course introduce some of those wordings like mute and block and define what those would contain, like only p or only e in this NIP if you feel like that is needed, but I wouldn't use the p:mute logic as it would someday lead to e:p:t:g:likes:subject:mute instead of simply mute and we read the nip and know what to expect.. which is a totally fine thing to do. we can in fact choose that path of using p:follow, but what I'm saying is it doesn't need to be limiting in this NIP

@monlovesmango
Copy link
Member Author

I don't think it makes sense to introduce a new concept in one NIP and then list the standard/taken names in another NIP. its confusing. especially since the behavior is not changing at all, its just about organizing the documentation.

how would it ever lead to e:p:t:g:likes:subject:mute? this can only happen if we don't specify what format it should be in. if I explicitly say there are only two parts, tag type and name, it leaves very little room for people to make up their own.

I think mute should cover event, pubkeys and hashtag muting. I think follow should cover event, pubkeys and hashtag follows. why create confusion and potentially more variations by defining them all individually?

@monlovesmango
Copy link
Member Author

we can in fact choose that path of using p:follow, but what I'm saying is it doesn't need to be limiting in this NIP

yes but the use cases I want to enable by submitting this nip directly depend on this convention. this is central to the nip mechanics.

@eskema
Copy link
Collaborator

eskema commented Jan 23, 2023

then you can use it. you don't need to force it on everyone else. that's why I'm saying the option is needed, otherwise I'm not going to be using this NIP, I'd have to use NIP52 or something

@eskema
Copy link
Collaborator

eskema commented Jan 23, 2023

it's just an unnecessary friction point. NIPs should be like functions, and some build upon others to form more complex stuff. the simple concept of public / private with tags / encrypted content is what's actually needed. the wording on the d tag is a specific use case that levarages the concept in this NIP to do something specific. we should not be limiting the concept to that particular use case alone. and the concept should also work with simple lists that don't use a d tag

@monlovesmango
Copy link
Member Author

I'm curious what you have against using this option?

I decided to use this format for the following reasons:

  • to allow cross compatibility of lists between clients
  • to allow segmentation of common list names (like mute or follows) by tag type

I think both of these are needed in a lists nip. do you disagree with either of these objectives? do you think there is a better way of accomplishing these? I'm happy to change the design

I personally don't think its efficient to introduce a lists nip that doesn't allow for identifying the tag type for private lists (without requesting and decrypting first).

@eskema
Copy link
Collaborator

eskema commented Jan 23, 2023

I'm curious what you have against using this option?

I decided to use this format for the following reasons:

  • to allow cross compatibility of lists between clients
  • to allow segmentation of common list names (like mute or follows) by tag type

I think both of these are needed in a lists nip. do you disagree with either of these objectives? do you think there is a better way of accomplishing these? I'm happy to change the design

I personally don't think its efficient to introduce a lists nip that doesn't allow for identifying the tag type for private lists (without requesting and decrypting first).

I have nothing against your logic, I think it might be a good thing. and IF we all go along, then it may end up working like that in the end for everyone, but I don't think it belongs in the same nip, it discusses another specific thing.

@eskema
Copy link
Collaborator

eskema commented Jan 23, 2023

I personally don't think its efficient to introduce a lists nip that doesn't allow for identifying the tag type for private lists (without requesting and decrypting first).

you would know what to expect by reading that specific NIP. So maybe what you want here is changing the title to be more specific of what you want to achieve with your method and introduce to novel concept of using this logic. and so we dn't refer to this NIP as the one for public / private lists but to the mute / follow / ignore and whatever other thing you need NIP

@mikedilger
Copy link
Contributor

mikedilger commented Jan 23, 2023

If these lists are "to yourself", why not just encrypt them with your public key and decrypt with your private key? ECDH "to yourself" seems pointless to me.

edit: Or maybe this cryptosystem doesn't support that? I'm more familiar with RSA which does. I'll have to check. edit2: it is used for symmetric encryption so it would be encrypt and decrypt with your private key.

@monlovesmango
Copy link
Member Author

thats what I originally had in mind but on nostr @mmalmi had suggested just using the existing nip04 encrypt/decrypt functions for browser signing. otherwise we would have to implement new functions. I agree that reusing nip04 is much simpler for implementation. I can be convinced either way on this one.

@mikedilger
Copy link
Contributor

I guess it doesn't matter. You are not exposing the key you are encrypting/decrypting with so you aren't leaking information about the keypair. And NIP-04 has an IV which does a lot.

Carry on.

@jb55
Copy link
Contributor

jb55 commented Jan 24, 2023

thanks for getting this going!

@jb55
Copy link
Contributor

jb55 commented Jan 24, 2023

Sorry, I changed my mind. This nip is not ready for being merged. We probably should not pack everything containing lists of pubkeys or events in the same kind no matter what.

I would appreciate if this nip was changed to simply covering mute/follow.

I agree, there should be a different kind per list. this would allow clients to only pull the lists they need.

@jb55
Copy link
Contributor

jb55 commented Jan 24, 2023

ah nm I see you would just use nip33 for this

@jb55
Copy link
Contributor

jb55 commented Jan 24, 2023

I'm pretty happy with this general structure, but I don't think we need the type: thing. clients will probably have to know each d tag and know what to do with them, so perhaps those could be clarified in future nips if necessary. I would be happy with mute for the blocklist in damus, I don't see the point of having both mute and block. I would also be happy with bookmarks and pinned.

@jb55
Copy link
Contributor

jb55 commented Jan 25, 2023

damus currently implements mute lists using this + the "mute" nip33 param

@cameri
Copy link
Member

cameri commented Feb 16, 2023

Late to the party, but I want to add my 2 sats. I don't like that this is separated out into multiple kinds, because I think it makes sense to have different types in the same list. Background is that I am implementing "custom views", which aren't as simple as the mute/pin/whatever use cases described above. If I have to create a list for following either pubkeys or topics by publishing two events and merging them together, that seems unnecessarily complicated.

Here's an example of what I'm hoping to do:

{
  "tags": [
     ["d", "All about bagels"],
     ["t", "bagels"],
     ["r", "wss://bagel.zone"],
     ["p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],
  ],
}

This nip doesn't support this use case, but I don't see why it shouldn't.

I can see us having a kind for Mixed lists

@fiatjaf
Copy link
Member

fiatjaf commented Feb 16, 2023

I can see us having a kind for Mixed lists

I think you have the wrong idea of what these kinds were supposed to mean.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 16, 2023

@monlovesmango can we make these lists all have the same kind 30000 and be done with it?

@cameri
Copy link
Member

cameri commented Feb 16, 2023

I can see us having a kind for Mixed lists

I think you have the wrong idea of what these kinds were supposed to mean.

Naming things is hard. @staab wants a way to mix in multiple tags within the same list. We can call it custom views or user-defined filters or mixed.

@monlovesmango can we make these lists all have the same kind 30000 and be done with it?

Using event kind 30000 for any kind of list also works IMO. We would only need to agree on the d tag value for interoperability. It's not always easy to see the issue with an approach until you need it to scale.

I'm PRO ditching using different event kinds for types of lists and sticking with 30000.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 16, 2023

Naming things is hard. @staab wants a way to mix in multiple tags within the same list. We can call it custom views or user-defined filters or mixed.

I think it is simpler for everybody if we can just fetch a "mute" list and that includes everything I have muted, including profiles and events, and other stuff that can show up later. Having to think if the contents of the list are events or people or addresses or anything else is just an extra mental and implementation burden. Also if a list is on the kind reserved for pubkeys but it contains an "e" tag? Should clients ignore that? I think they would not, it would just complicate the logic.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 16, 2023

I'm PRO ditching using different event kinds for types of lists and sticking with 30000.

My preferred approach is for each kind of list have a different kind number, but since no one agrees with me I'm ok with this.

We would only need to agree on the d tag value for interoperability

This is the same requirement we would have for kind numbers, by the way, that's why I like kind numbers more.

@staab
Copy link
Member

staab commented Feb 16, 2023

I'm ok with using kinds to specify specific types of lists, but the default 30000 should be "whatever" or "user defined". Also, additional kinds should probably be specified by use case rather than tag type, e.g. "mute" not "all tags are pubkeys".

@staab
Copy link
Member

staab commented Feb 16, 2023

As a sidenote, coracle currently uses kind 12165 for mute lists, but adds an extra value at the end of each tag ranging from 0-1 to denote "how often" to mute someone. For example, it's common for me to unfollow someone because they post just too dang much, even though I like what they have to say. I'm not sure that use case makes sense for this nip, just commenting.

@melvincarvalho

This comment was marked as spam.

@monlovesmango
Copy link
Member Author

My preferred approach is for each kind of list have a different kind number, but since no one agrees with me I'm ok with this.

I think this is also a valid approach and happy to adapt this nip to this if others agree. If I am understanding correctly, this would mean 'mute' would be one kind, and 'bookmark' would be another kind, and each could contain any tag type right? If so it might make more sense to use replaceable events for these lists rather than parameterized replaceable events.

even if we went with this approach I would still want to have dedicated list kinds that only hold certain, predefined tag types.
this would enable letting users create custom named lists for various uses that applications could efficiently query and parse. for this, applications would need to be able to query for only lists that contain certain types of tags (depending on the use case) without knowing the 'd' parameter ahead of time (since the user can use a custom name). this is why I lean towards having list kinds be delineated by which tag types are included. @fiatjaf for these, yes I would expect clients to ignore non compliant tag types. what is everyone's thoughts on this use case?

right now this nip is delineating the list kind based on the tag type (in order to enable the custom list use case mentioned above). fiatjaf is suggesting delineating the list kind based on the list purpose ('mute', 'bookmark', 'pin'). I see 3 main options (the tables below are just examples of how list kinds could be broken out):

  1. use both purpose and tag type:
kind description NIP
10000 Mute 51a
10001 Bookmark 51b
10002 Pin 51c
30000 User Public Key List 51d
30001 Note Event List 51e
30002 Hashtag list 51f
30008 Badge list 51g
  1. use purpose only (doesn't leave flexibility for common custom lists):
kind description NIP
10000 Mute 51a
10001 Bookmark 51b
10002 Pin 51c
  1. use tag type only ('mute', 'bookmark', 'pin' lists would be spread out across different list kinds based on tag type):
kind description NIP
30000 User Public Key List 51d
30001 Note Event List 51e
30002 Hashtag list 51f
30008 Badge list 51g

anyone care to give an opinion on which option they think is best? or have alternative options to suggest? Personally I think I am leaning towards option #1.

do people agree that it make sense to use the 10000-19999 range for the purpose built lists?

@staab
Copy link
Member

staab commented Feb 17, 2023

Option #3 doesn't seem useful to me, it's not hard to parse tags and figure out what type they are. I'd like to hear your use case if you have one in mind. #1 seems infeasible from a speccing point of view, I don't think anyone wants to be merging new permutations of old use cases into this repo all the time. #2 all the way for me.

@verbiricha
Copy link
Member

Personally I think I am leaning towards option 1

I think this approach addresses the main criticisms of this PR by having separate kinds for each mute/follow/bookmark list and allowing heterogenous tags in these. It still allows users to define named (and typed) lists using paramemeterized replaceable events which option 2 doesn't give us. I lean towards 1 too.

@monlovesmango
Copy link
Member Author

@staab my usecase for #3 would mainly be to create custom feeds. for pubkey lists, a user could create lists for 'podcasters', 'devs', 'travel', 'artists' etc based on which list feed they want to look through. same for hashtags, events, long form posts, and relay lists.

for your concern with #1, can you expand on what you mean by 'new permutations of old use cases'? this nip is meant to be extended as new use cases arise, which is why I put it in the structure it is in now (where nip51 defines the list architecture and the sub nips define each kind of list). however once a list kind is defined (in a sub nip) it shouldn't need to updated regularly.

@staab
Copy link
Member

staab commented Feb 17, 2023

My permutations criticism I don't think is relevant, as we're not speccing the cross product of use cases and tag types. But I still don't see the use of homogenous lists absent of use case. Maybe we don't have the same working definition of "use case"? "User Public Key List" isn't a use case, "list of people I've muted" is. But then, "mutes" could include posts, topics, keywords, etc. as well.

@monlovesmango
Copy link
Member Author

use cases could be, but are not limited to:

  • list of people who talk about bitcoin
  • list of events about politics
  • list of articles about philosophy
  • list of hashtags about celebrities

the use case would be defined by the user, based on what type of event they are engaging with and whatever category they want to define. since the use case would be based on the type of event they are engaging with, different kinds are needed so that an hypothetical article app could easily query for all lists of articles a user has created.

I guess the use case would also be defined by the client as well, since the client implements the use of the lists. for pubkey lists specifically, a client could:

  • make a standard feed
  • create a list of trending events
  • suggest new users to follow

perhaps this is still a somewhat wishy washy answer for use case. I just think this would be really useful for clients to enable their users to personalize their content.

@staab
Copy link
Member

staab commented Feb 18, 2023

Here's another way to ask the question, what assumptions do homogenous tags enable, and how does that relate to concrete use cases? IOW, if I find a list called "cats" and it's a mix of pubkeys, events, and topics, it doesn't seem any less straightforward to load everything up than if it was a list of pubkeys. Editing such a list might be more complex, but that would have to be supported anyway since heterogenous lists will exist.

People are probably starting to mute this thread at this point, so I'll leave it at that unless anyone else wants to chime in.

@monlovesmango
Copy link
Member Author

an article app should be able to query for all the user's lists that contain tags of articles and only receive lists that have tags of articles. it shouldn't have to query, receive, decrypt, and parse all the user's lists to find which lists tag articles. I guess this would be what I want to enable with homogenous tags.

@staab
Copy link
Member

staab commented Feb 18, 2023

Again, that's use case specific, isn't it? So in that case you're not looking for lists that have all event tags, but specifically event tags of a particular kind. So even with this NIP as it currently stands you'd have to grab all homogenous event-tag lists, and then filter through to find the ones that are articles only.

@fiatjaf
Copy link
Member

fiatjaf commented Feb 18, 2023

Can we add use cases as they happen?

So far we have "mute" and "pin", which cannot be of multiple types, i.e. there is no "mute of type x" and "mute of type z". There is just "mute". We want interoperability between clients with regards to mute lists, so give those a 1000x kind number and everybody uses that. Same is valid for "pin". There is only one place to pin stuff, so that's another 1000x kind.

Then there are the more flexible "lists of things that I classify in some way", they can certainly be of many different types, so that's a 3000x kind.

That gives us:

kind description NIP
10001 Mute 51a
10002 Pin 51b
30001 Categorized Bookmarks 51c
30002 Categorized People 51d

kind 30001 and 30002 lists, for example, may have d tags like "football", "bitcoin", "music", each with set of pubkeys in them. Some clients may display 30002 as a custom feed, others may just display them as a list of the profiles, others may not even display them, but this is fine.

I can also see a 30003 list of URLs, for example, if someone wants to make a pinboard.in clone on Nostr -- that would comport the 3 kinds of lists above and perhaps others yet to be added to this NIP -- and would allow people to easily browse other people's lists and edit their own.


(I made up the numbers above without checking anything.)

@staab
Copy link
Member

staab commented Mar 9, 2023

@monlovesmango thanks for taking my comments into account, I like where this is going. I'd still like to see a kind for an open-ended "custom feed" kind which supports heterogenous tags.

Other than that, just minor comments from me now:

  • We should clarify what kind of tags are allowed in mute/pin Edit found it, "Any standarized tag can be included in a Pin List."
  • I'm not sure what "Bookmarks" are, are these event tags? Could be clarified.
  • I think the novelty of the 51a/b/c format isn't worth it, we should just roll those specifics into NIP 51 like other NIPs do

@staab
Copy link
Member

staab commented Mar 9, 2023

Oh, another thing is that 10002 is the relays list event from NIP65, so we might want to start counting from somewhere other than 10000.

@staab
Copy link
Member

staab commented Mar 9, 2023

Just implemented thread and person mutes coracle-social/coracle@c4c72ab

@alexgleason
Copy link
Member

How come Mutes (10000) and Pins (10001) are outside the NIP-33 range? That doesn't make sense to me.

@Giszmo
Copy link
Member

Giszmo commented Jun 29, 2023

@alexgleason these are nip-16 replaceable events without "parametrized".

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.