Oddbean new post about | logout
 I think there's been an inflection point recently in NIPs that are being proposed. Some examples: 

- Products with pubkeys: https://github.com/nostr-protocol/nips/pull/1225
- Shared-ownership events: https://github.com/nostr-protocol/nips/pull/1192 and https://github.com/nostr-protocol/nips/pull/1015
- Spreadsheets: https://github.com/nostr-protocol/nips/pull/1189
- Relational databases: https://github.com/nostr-protocol/nips/pull/1168
- Relay-specific notes: https://github.com/nostr-protocol/nips/pull/1146
- Editable notes: https://github.com/nostr-protocol/nips/pull/1090
- Restricted events: https://github.com/nostr-protocol/nips/pull/1083
- Relay-based access control: https://github.com/nostr-protocol/nips/pull/1030
- Protected events: https://github.com/nostr-protocol/nips/pull/1029
- Closed groups: https://github.com/nostr-protocol/nips/pull/875

Some of these I like, some I don't. But most of them go beyond adding new features to nostr (for example audio, video, speedruns, resumes, etc), and begin to change how nostr actually works.

Nostr can be an everything app, but I think that means something very specific. Nostr can represent data types from pretty much any domain, but it can't actually support all the semantics needed to build any arbitrary system.

I would suggest conservatism in what we build on nostr, but of course anyone can build whatever they want. But I do think it's possible to identify things that nostr is good at, and things it's bad at, and play to nostr's strengths.

Nostr's strengths:

- Being able to model any data type orthogonally to the rest
- Single-owner, self-authenticating, atomic data types
- Potential for robust content dispersal and retrieval if we can flesh out NIP 65 etc.

Nostr's weaknesses:

- Mutable state, non-atomic state
- Shared ownership, key delegation/rotation
- Privacy — metadata will always leak, lack of consistency makes key rotation harder
- Consistency — not everyone has the same view of the world
- Transactionality — nostr isn't good for updating multiple pieces of data in lockstep

It happens that the original use case of nostr — public broadcast social media — benefits greatly from nostr's strengths, and isn't bothered by any of nostr's weaknesses. Blob storage like what blossom is building also works well in this paradigm. A lot of the use cases @PABLOF7z​ has identified work beautifully well because of the single-owner public-read nature of nostr, which makes forks easy to model.

But things like access control, relational data, collaborative document creation, heavier datasets, or anything that requires a solution to the double-spend problem become very awkward (or impossible) to model on pure nostr. A simple example of this is lists. Not only is it common for a single user to mess up his follow lists because of a lack of consistency between clients or devices, but commonly requested features like shared ownership lists immediately result in a huge increase of complexity, either on the key management side or on the data structure side. Both of these problems are difficult to solve on nostr due to lack of consistency — keys can't always be reliably or safely shared, and linked data structures spanning multiple events by different authors can be hard to assemble reliably.

I think the danger here is that if we as a developer community fail to realize the limitations of nostr and try to adapt the protocol to fit every possible use case, on an ad-hoc basis, we're going to end up with a tragedy of the commons, where no developer can comprehend what must be done to get his work done, and all kinds of weird artifacts appear for end users that no one can explain.

Here are some suggestions I have for preventing this from happening. I realize no one is going to follow them. But maybe they can be helpful for avoidance of wasted time.

- Don't overload event kinds. Many people (including myself) have tried to extend kind 0 with attributes for forms, products, and groups, but that leads to madness. Instead, create a new metadata event signifying a different kind of agent.
- Don't model things as replaceable events if you can avoid it. This creates the problem of shared mutable state, which nostr doesn't have a good story for resolving. They also have a hard limit on how big they can be.
- Use different keys for different things. For domains where some kind of access control needs to be implemented, not tying everything to your main pubkey makes it possible to create and burn keys as needed. Incidentally, this can help users maintain better privacy. An example of this is private groups, which have a dedicated key separate from the group creator's own key.
- Event ownership should always be (is) single-key. If you need shared ownership, figure out a way to share keys. More work needs to go into key invalidation and rotation for this to really work.
- Explore the fork model — this is "my" version of the same thing, and coexists with rather than supersedes the original. This has potential not just for groups or wiki entries.
- Distinguish between different ways to use relays. Relays may be used as indexers (holding specific event types or supporting different features like search/count), repositories (holding many diverse events, to be used with filters), or curated feeds (to be used without filters, or with only a few filters).

These are just suggestions, and many of them may be wrong. Nostr development is hard, and getting harder. Keep it simple. 
 Originally I tried to treat Nostr events as my app's database. Now, I only add tags (or would proose a new NIP) if that data needs to be shared with other apps. 
 Yeah, this is a good example of what I mean. Apps can just have a regular database, and create events when there's a compelling reason for them to be read by other apps. 
 I fully agree with not overloading event kinds! I’ve been trying to evangelize one event kind for https://webxdc.org to handle a wide range of interactivity needed.  
 Nah... it's just feels like "square peg, round hole" because we are so early and we haven't figured out ways to do these more interesting things yet. But they will come. 

I don't understand the beef some devs have with replaceable events. They are awesome for what they are: storing the latest status of a given event. You can have an entire game state that keeps changing every 100ms and still don't overload relays with the complete history of every run through the game. 
 Mutation is just inherently more complicated than storing immutable events. If someone is storing a new immutable event every 100ms they’re easy to spot as a potential spammer/abuse.

If they’re replacing an event every 100ms and a server naively just deletes old versions, now you don’t have a record of how much they’re (ab)using your resources.

Plus, a big benefit of signed events is holding people (or at least, pubkeys) accountable for what they’ve posted. If they can just edit it out of history, that is lost.

For that reason, my FeoBlog system disallowed mutability. But, that was super frustrating when I would inevitably discover a typo in what I just posted. So, while it’s more complicated, I’m glad that Nostr has a solution there.

But in my Nostr relay implementation, I keep older versions of mutable events so that you can see previous versions that a user posted. I’m keeping the receipts. 😉  
 > Mutation is just inherently more complicated than storing immutable events.

Not really. This blog post is mutable. There is nothing more complicated to it than to an immutable event. 

> If they can just edit it out of history, that is lost.

It's not an edit. It's a new signature. You are free to keep all versions if you want to audit people. Also, almost all relays delete regular events. So, I would argue that auditing is exactly the same between replaceable a non-replaceable events. As we move along, relays won't be able to keep more than a few weeks of data for all their users. So, every event will disappear in time. 

> For that reason, my FeoBlog system disallowed mutability.

You are free to force yourself to do this. But you are not free to force that decision on everybody else. If people want replacements, they will have replacements. 
 Have you ever listened to Rich Hickey? He makes a strong case for the complexity involved in conflating names with data.

https://www.infoq.com/presentations/Value-Values/ 
 > the danger here is that if we as a developer community fail to realize the limitations of nostr and try to adapt the protocol to fit every possible use case, on an ad-hoc basis, we're going to end up with a tragedy of the commons,

Thank you, a really inspiring read.

> Don't overload event kinds.

I promise I will think about that! :) 
 Heh, you know it was a subtweet 
 If a group uses a different key, is it possible to set up a profile for each group? 
 You could in theory, but it wouldn't work the way people would expect. 
 okay🙆‍♂返答ありがとう🫂 
 It's a good question, but after a year of thinking about it I think it's probably not the best idea. It seems to be catching on though, so we'll see what happens 
 👍 
 This is an important perspective; we have infinite numbers and the simplicity of the `.kind` is often overlooked, specially by newcomers who seem to be skeptical about "claiming" a space in the (again, infinite) numeric field.

It's ok, no one can "claim" a number, in the same way you can't take ownership of the letter "i" (regardless of what silly laws might say).


nostr:note1t83vpz7st5586hjz9fs3sjycmjjxwv4pcya2l0t3hgn0wgvs289stup7nf 
 event ownership can actually be multiple, schnorr signatures can be aggregated... just that there is only one pubkey field, it would just be a special variant of the p tag to add cosigners, though i'm not sure what the point of such is, corporate accounts? 
 even for non technical guy like this was an interesting read!.

I'll take the opportunity to ask if you plan to have a wallet connect in Coracle?... wasn't one been available and then it disappeared? 
 It's sort of still there, but only available if you don't already have webln. Going to bring it back in the future. 
 thanks I wait for it. makes zapping so much easier. 
 While I agree with this, it needs more discussion; I don't think we are at a good point where relays can specialize their functionality in an intuitive way without a combinatory explosion increasing implementation complexity.