Description
Background
-
Nostr events already allow tags to be either strings or numbers, lovely bit of flexibility that lets people innovate without filing github issues.
-
Kinds, on the other hand, are hard-wired to integers. If you want a new one, you pull a random number (hope it doesn’t collide) or wait for the registry gnomes to bless a low integer.
Why this asymmetry is weird
-
Developers have to keep two mental models.
One field is permissive (tags), the other is a numeric straight-jacket (kinds). That’s cognitive load for no real win. -
Strings already proved their worth.
We’ve watched ActivityPub, ATProto, Matrix, etc. scale just fine with straings as identifiers. Interop is easier because the intent is encoded in the string. -
Integers don’t buy much performance in JSON.
A couple of bytes here and there aren’t going to sink relay throughput. Meanwhile, constant look-ups to translate31923
→CalendarEventTime
definitely burn cycles (both CPU and human). -
Permissionless innovation matters.
Want to prototype a new feature this weekend? With numbers you’re either (a) camping on someone else’s provisional value or (b) rolling the collision dice. Strings fix that.
Proposed tweak
Let kind
accept a string or an integer:
type Kind = number | string; // e.g., 1 OR Note"
- Low, well-known integers keep working forever — no migration panic.
- New work can mint strings today, ship tomorrow.
- Relays treat the field as an opaque token; clients decide what they care about.
Impact
- Backward-compatible. Old clients ignore unknown string kinds; new clients recognise both.
- Zero additional registry overhead. Anybody can innovate; the global NIP table keeps curating the canonical ints.
- Easier debugging & AI tooling. Logs (and LLMs!) understand readable strings without a cheat sheet.