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

NIPs and kinds as "Design Patterns" for other Nostr specs. #1829

Open
vitorpamplona opened this issue Mar 6, 2025 · 3 comments
Open

NIPs and kinds as "Design Patterns" for other Nostr specs. #1829

vitorpamplona opened this issue Mar 6, 2025 · 3 comments

Comments

@vitorpamplona
Copy link
Collaborator

vitorpamplona commented Mar 6, 2025

I am now inexplicably and blatantly aware of the confusion between abstracted NIPs and design pattern NIPs, abstracted Kinds and design pattern Kinds.

Take NIP-22, for instance. It created a new tag structure to assemble a thread. That tag structure should be a design pattern that can be replicated in any other NIP without reusing kind 1111. For instance, when devs need Markdown or AsciiDoc in .content.

Take NIP-10 markers. Its "design pattern" spread to other NIPs and we placed new markers as needed, like on the Wiki's "fork".

When we were debating @arthurfranca's Event set #784, the n tag to put events in a set is just a design pattern for any NIP to reuse.

NIP-94 right now is moving away from implementation to become a design pattern for many NIPs: Pictures, Videos, Encrypted files on NIP-17 and even the #1356 PR. Software applications and podcasts might be following that design pattern into new NIPs. NIP-94 should have never defined a specific kind number, just provided the guidance to be extended by each use case.

I say "design pattern" because while the tag names are the same, their inclusion is selective and their format varies based on the NIP's needs.

Same for e, p, a tags. There are multiple variations of them in many NIPs. They establish a design pattern, not only on how to encode an kind:pubkey:dtag address, but how to work with hints as both URLs and pubkeys.

That is a design pattern. They should not be "defined" in NIP-1 with a given fixed format. Their design pattern should be defined, but not the tag itself. Each NIP then refines the tag for its own usage.

Same for GiftWraps. We made them take just one event kind. But we are now seeing other kinds that redo a GiftWrap to encode other things, like on #1813 .

Same for NIP-29. It defines a set of commands for group-based relays, but it has no given application in mind. It's just a pattern to be adopted by those who need moderation at the relay level.

Same for #1228, which is being used now on #1189, #357 and potentially #1665.

iMeta's variadic tags are now a design pattern that can be used in multiple tag names that are not imeta, like the #1674

Many devs that propose new PRs are actually just proposing a design pattern with an example application for it. But the application itself is irrelevant. They just want to propose the pattern, the way to use nostr to achieve a given technical result. The application is not relevant at all.

I think we will all benefit if we start formalizing the distinction between best practices on Nostr and design patterns for Nostr from actual, tangible NIPs and kinds.

@staab
Copy link
Member

staab commented Mar 10, 2025

The main concrete distinction is I think between tags defined for a specific NIP and tags that might be added to any event kind (e.g. q, t, g). Unfortunately, every tag defined in a given context becomes something that might get applied elsewhere, which means we can't really make that distinction anywhere. But then this results in an over-constrained system, where one tag is defined in different ways on multiple event kinds. When the use case for one applies to the other, it can't be copied over without collision, and a new tag has to be created, repeating the cycle.

I don't know how to fix this.

@vitorpamplona
Copy link
Collaborator Author

vitorpamplona commented Mar 10, 2025

tags that might be added to any event kind (e.g. q, t, g).

I am fully rewriting Quartz (the Kotlin lib for nostr) to not have any tag define itself as global. Because there isn't really such a thing in Nostr. Some tags just so happen to work, but there isn't a guarantee. The g tag doesn't work on NIP-22, for instance. You need to use an I tag that starts with geo:. Each kind must acknowledge that specific tags can be used with them and that does include q, t, and others. But that acknowledgment must be per kind.

I don't know how to fix this.

I don't know either. It might require us to redefine what things are in the NIP repo over time. Slowly migrating things that were defined as one thing into another realm.

Take the a tag for instance. There are a few things bundled in its definition:

  • The notion of an unique address, which should follow kind:pubkey:dtag
  • The notion of event findable coordinates (address + a relay hint)
  • The format of the a tag itself ["a", "kind:pubkey:dtag","<relay hint>"],
  • The semantics of what the a tag means in separate NIPs

On the e tag.

  • The notion of an unique id, which should follow <eventId> in lowercase hex
  • The notion of a direct event findable coordinate: (i) id + a relay hint
  • The notion of an indirect event findable coordinate: (ii) id + pubkey
  • The format of the e tag itself ["e", "<eventID>","<relay hint>", "<pubkey>"], which means different things in different NIPs and for kind 1 includes a marker in the middle: ["e", "<eventID>","<relay hint>", "<marker>", "<pubkey>"]
  • The semantics of what it means in each NIP.

To me, NIPs define a tag name and demark the array positions for each component of its definition. "a" tags can use any tag name and any position and still include the core components as an a tag. NIP writers can then "shop around" for which components/"notions" they want to implement.

The "issue" is that right now we are not naming individual tag components in the spec. There are no guidelines for writers to choose from. There are only design patterns hidden in every NIP

Becasuse each NIP can redefine every tag, we do not have a reliable (code once and run in every kind) event graph with just one tag, like an e tag. Even the "Notification" feed cannot be simply based on p tags anymore and must include P as well.

@vitorpamplona
Copy link
Collaborator Author

Of course, the trick is to clarify these things while not complicating the spec with multiple layers of abstractions

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

No branches or pull requests

2 participants