JoeRuelle on Nostr: Potentially unpopular opinion: Nostr should adopt ATProtocol-style lexicons. ...
Potentially unpopular opinion: Nostr should adopt ATProtocol-style lexicons.
ATProtocol lexicons are good because they encourage more detailed Kind schemas.
Let's take the example of NIP-29 chat groups and how the same group can look very different when viewed in 0xchat versus when viewed in Chachi. Want one thing to look right? Open the group in 0xchat. Want another thing to look right? Open the group in Chachi.
In ATProtocol it would be like this. Chachi comes into existence. When it does, 0xchat already has a hyper-detailed lexicon schema (com.0xchat.message) and this lexicon leaves little grey area—maybe some cosmetic grey area and that's about it.
On day one Chachi has to make a choice. Follow this hyper-detailed existing 0xchat lexicon or create a new Chachi lexicon. If going the first route, Chachi declares the 0xchat lexicon in each event that Chachi sends ("$type": "com.0xchat.message”) and by doing so Chachi is saying “I agree with everything in this very detailed schema of theirs and if something isn’t right then I’m the one that’s out of line, it’s me.”
If going the second route, Chachi will not be interoperable with 0xchat.
That's just the choice Chachi has to make. Is it worth it to forge a new path? Or is it better to piggy-back off 0xchat's success? Maybe there are other clients also using 0xchat's lexicon; does Chachi want to be on that bigger team? Or maybe Chachi has a super feature idea and it’s totally fine to go it alone, the users will come for that feature. Either way, Chachi has to make a choice, and it has to make that choice on day one.
You could say that the Nostr way is pretty much the same as the flow I just described above, with only minor semantic differences. Chachi has to choose to follow a NIP (and a Kind) on day one, or to go it alone. Like Flotilla went it alone at the start. But no. It’s not the same in substance. Of course Chachi does have to choose a NIP and a Kind on day one—but Nostr Kinds are like laws in countries where the authorities have left themselves a *lot* of room for interpretation. Singapore this is not. Rather this is more like [insert name of murky country here]. Did you break the law? Maybe you did, maybe you didn’t, depends on who’s asking who and why.
The current Nostr way allows devs to procrastinate, put off the “tidying up” until some undetermined point in the future. And the one who pays for that procrastination is always the user.
In short ATProtocol lexicons both allow for and encourage a significantly higher level of detail and expressiveness—and in doing so they tend to force tidiness from the start. If you take Nostr’s Kind1 schema and compare it to app.bsky.feed.post (their Kind1), and not only that but all the lexicons that app.bsky.feed.post references (such as app.bsky.richtext.facet and app.bsky.embed.images and app.bsky.embed.record ...) it's quite clear we’re looking at an order of magnitude difference in detail. And at the end of the day this is all about detail. That’s where the devil is. And the devil is having a lot of fun on Nostr these days.
If you're an ATProtocol developer and you've got a cool idea for, say, a VR client, and you decide you're going to re-use the app.bsky.feed.post lexicon and all its mandatory entourage—well there's very little wiggle room for you. Either you state outright that this is your lexicon in each event and you stick with the program—or you don't and you make a new lexicon and you declare that new lexicon explicitly in each event. And that’s good. Because over there devs can't just say to users "you know what guys, you figure it out". The devs have to figure it out themselves. And beforehand.
So why the lower level of detail for Nostr?
One reason Nostr Kinds are less opinionated is to increase the chance of being merged on Github. Meaning much of this is psychological (as opposed to technical, given that in theory there is no limit to how detailed a Nostr Kind can be, though there are also technical differences that give ATProtocol lexicons more expressive power). Nostr kinds are discussed—and discussed, and discussed some more. This has a watering down effect.
ATProtocol lexicons are discussed too, but in fewer situations, and the discussions end sooner. Part of this is because there is no two-tier system of “merged” and “un-merged”. (On Nostr an un-merged spec is a little like a second-class citizen, and devs feel a lot of pressure to get their specs merged and first-class-ified). ATProtocol lexicons also start off with devs and their unique ideas—but they aren’t ever merged. You can have a much-copied lexicon, one that say five or six other clients make use of. And you can have a solo lexicon, one used by your client alone. That’s where the difference is. This means that on ATProtocol it’s all about traction. Not traction in order to make the case that your PR should be merged. Just good old traction.
Of course the downside to lexicons is that devs with clients that have good traction gain a lot of lexicon power. If I make an ATProtocol client for publishing serialised fiction called CheeseRead, and my chapter publishing lexicon is com.cheeseread.chapter, and I get a lot of users, and a few other serialised fiction clients emerge (maybe for other operating systems), and they use my com.cheeseread.chapter lexicon too—then I’m in a pretty strong position. And bonus: I get to feel proud of myself because all these other clients have my brand showing up in their event json.
This doesn’t mean I can screw with the lexicon and break things on their end. Under the rules all old data must still be valid under an updated lexicon, and new data must be valid under the old lexicon, so new fields must be optional, non-optional fields cannot be removed, etc. (or a fresh lexicon is needed). But it does mean that it’s harder for other clients to pull users from me because my client is going to be very optimised for this lexicon. (Mind you this can also be a good thing because it means others in the space have to think beyond copy-paste.)
All in all though, there’s something to be learned here. ATProtocol lexicons are more decentralised—due to there being no “PR & merge” concept—and more practical—due to how much grey area they usually remove.
The lesson for Nostr: there is no point in getting everyone on the same page if that page doesn’t have enough words on it.
The ATProtocol lexicon concept is a smart concept that can be borrowed. It encourages what I call “fearless detail”. At any rate Nostr has to move off Github sooner or later, so why not dump both the platform and the flow at the same time? And jump on the lexicon train.
Published at
2025-03-27 17:26:32Event JSON
{
"id": "366fe02bd10911c59b7eb9e6adc4c96e17e7c0b44f23b30fa8f72ed3cd067334",
"pubkey": "b90c3cb71d66343e01104d5c9adf7db05d36653b17601ff9b2eebaa81be67823",
"created_at": 1743096392,
"kind": 1,
"tags": [],
"content": "Potentially unpopular opinion: Nostr should adopt ATProtocol-style lexicons.\n\nATProtocol lexicons are good because they encourage more detailed Kind schemas.\n\nLet's take the example of NIP-29 chat groups and how the same group can look very different when viewed in 0xchat versus when viewed in Chachi. Want one thing to look right? Open the group in 0xchat. Want another thing to look right? Open the group in Chachi. \n\nIn ATProtocol it would be like this. Chachi comes into existence. When it does, 0xchat already has a hyper-detailed lexicon schema (com.0xchat.message) and this lexicon leaves little grey area—maybe some cosmetic grey area and that's about it. \n\nOn day one Chachi has to make a choice. Follow this hyper-detailed existing 0xchat lexicon or create a new Chachi lexicon. If going the first route, Chachi declares the 0xchat lexicon in each event that Chachi sends (\"$type\": \"com.0xchat.message”) and by doing so Chachi is saying “I agree with everything in this very detailed schema of theirs and if something isn’t right then I’m the one that’s out of line, it’s me.”\n\nIf going the second route, Chachi will not be interoperable with 0xchat. \n\nThat's just the choice Chachi has to make. Is it worth it to forge a new path? Or is it better to piggy-back off 0xchat's success? Maybe there are other clients also using 0xchat's lexicon; does Chachi want to be on that bigger team? Or maybe Chachi has a super feature idea and it’s totally fine to go it alone, the users will come for that feature. Either way, Chachi has to make a choice, and it has to make that choice on day one. \n\nYou could say that the Nostr way is pretty much the same as the flow I just described above, with only minor semantic differences. Chachi has to choose to follow a NIP (and a Kind) on day one, or to go it alone. Like Flotilla went it alone at the start. But no. It’s not the same in substance. Of course Chachi does have to choose a NIP and a Kind on day one—but Nostr Kinds are like laws in countries where the authorities have left themselves a *lot* of room for interpretation. Singapore this is not. Rather this is more like [insert name of murky country here]. Did you break the law? Maybe you did, maybe you didn’t, depends on who’s asking who and why. \n\nThe current Nostr way allows devs to procrastinate, put off the “tidying up” until some undetermined point in the future. And the one who pays for that procrastination is always the user.\n\nIn short ATProtocol lexicons both allow for and encourage a significantly higher level of detail and expressiveness—and in doing so they tend to force tidiness from the start. If you take Nostr’s Kind1 schema and compare it to app.bsky.feed.post (their Kind1), and not only that but all the lexicons that app.bsky.feed.post references (such as app.bsky.richtext.facet and app.bsky.embed.images and app.bsky.embed.record ...) it's quite clear we’re looking at an order of magnitude difference in detail. And at the end of the day this is all about detail. That’s where the devil is. And the devil is having a lot of fun on Nostr these days.\n\nIf you're an ATProtocol developer and you've got a cool idea for, say, a VR client, and you decide you're going to re-use the app.bsky.feed.post lexicon and all its mandatory entourage—well there's very little wiggle room for you. Either you state outright that this is your lexicon in each event and you stick with the program—or you don't and you make a new lexicon and you declare that new lexicon explicitly in each event. And that’s good. Because over there devs can't just say to users \"you know what guys, you figure it out\". The devs have to figure it out themselves. And beforehand. \n\nSo why the lower level of detail for Nostr? \n\nOne reason Nostr Kinds are less opinionated is to increase the chance of being merged on Github. Meaning much of this is psychological (as opposed to technical, given that in theory there is no limit to how detailed a Nostr Kind can be, though there are also technical differences that give ATProtocol lexicons more expressive power). Nostr kinds are discussed—and discussed, and discussed some more. This has a watering down effect. \n\nATProtocol lexicons are discussed too, but in fewer situations, and the discussions end sooner. Part of this is because there is no two-tier system of “merged” and “un-merged”. (On Nostr an un-merged spec is a little like a second-class citizen, and devs feel a lot of pressure to get their specs merged and first-class-ified). ATProtocol lexicons also start off with devs and their unique ideas—but they aren’t ever merged. You can have a much-copied lexicon, one that say five or six other clients make use of. And you can have a solo lexicon, one used by your client alone. That’s where the difference is. This means that on ATProtocol it’s all about traction. Not traction in order to make the case that your PR should be merged. Just good old traction. \n\nOf course the downside to lexicons is that devs with clients that have good traction gain a lot of lexicon power. If I make an ATProtocol client for publishing serialised fiction called CheeseRead, and my chapter publishing lexicon is com.cheeseread.chapter, and I get a lot of users, and a few other serialised fiction clients emerge (maybe for other operating systems), and they use my com.cheeseread.chapter lexicon too—then I’m in a pretty strong position. And bonus: I get to feel proud of myself because all these other clients have my brand showing up in their event json.\n\nThis doesn’t mean I can screw with the lexicon and break things on their end. Under the rules all old data must still be valid under an updated lexicon, and new data must be valid under the old lexicon, so new fields must be optional, non-optional fields cannot be removed, etc. (or a fresh lexicon is needed). But it does mean that it’s harder for other clients to pull users from me because my client is going to be very optimised for this lexicon. (Mind you this can also be a good thing because it means others in the space have to think beyond copy-paste.)\n\nAll in all though, there’s something to be learned here. ATProtocol lexicons are more decentralised—due to there being no “PR \u0026 merge” concept—and more practical—due to how much grey area they usually remove.\n\nThe lesson for Nostr: there is no point in getting everyone on the same page if that page doesn’t have enough words on it.\n\nThe ATProtocol lexicon concept is a smart concept that can be borrowed. It encourages what I call “fearless detail”. At any rate Nostr has to move off Github sooner or later, so why not dump both the platform and the flow at the same time? And jump on the lexicon train.",
"sig": "b248efd71f96d701d6e0f98f30b7a9a6e899598967093a9ec28c5da92c7f2ae65e60985f535db2844b60f35c342ae0155d2a6e73f5bc85bf72c5077338d84cfa"
}