Roadmap
zig-nostr is a protocol library in Zig, the native apps that prove it on real product surfaces, and the docs around both. This is what has shipped, and the order of what comes next.
No dates. The order is a commitment; a calendar would not be.
Shipped
- Library core: secp256k1 keys and BIP-340 Schnorr signatures (bitcoin-core’s libsecp256k1), the NIP-01 event model, NIP-19/21 encoding, NIP-06 derivation, and NIP-49 key storage. Passes the full official BIP-340 test-vector suite.
- Transport and outbox: RFC 6455 WebSocket, a relay connection state machine with NIP-01 subscriptions, a live TCP/TLS dialer, and NIP-65 relay lists (kind 10002), the routing people call the outbox model, with zero hardcoded relays.
- Local-first store: a zero-copy, memory-mapped LMDB event store with a bounded, newest-first planner for NIP-01 filters. Sub-millisecond feeds that stay flat as the store grows.
- Signer protocol: NIP-44 v2 encryption, the NIP-46 remote-signing (“bunker”) protocol over kind 24133, and NIP-42 client authentication.
- Notary, the native remote signer. Your key lives in a local daemon, it hands
you a
bunker://URL, and nothing gets signed quietly. A downloadable macOS app. - Plaza, the flagship client. Browse as a guest, sign in three ways (including a NIP-46 bunker), and read a follow feed (your kind 3 list) that renders from disk before the network answers.
- Places: a link opens somebody’s corner of Nostr, their relays and what they serve, and while you are in one you see it rather than your own feed. Visit, enter to keep it on a rail, or leave. A community can carry several feeds and switch between them, and one that states a colour is drawn in it. The format is fiatjaf’s Hallway universe object, and the field names are his exactly, so a document written for one is read the same way by the other.
- Docs and benchmarks: this site, the NIP-support table, and reproducible performance numbers.
- Reach: following somebody means seeing them. Plaza reads the NIP-65 relay lists (kind 10002) of the people you follow, works out which relays reach the most of them, connects to the ones you are not already on, and asks each relay only about the people who write there. Anybody no chosen relay carries is asked of your own relays, so nobody falls through. What you post goes where your own list says it should, and scrolling past what is on disk asks the relays for older notes.
What comes next, in order
Everything you do on the first day
Four things are already built and do not work. Reposts by people you follow never reach the feed: Plaza publishes them and counts other people’s, but nothing asks a relay for kind 6. Relay hints are decoded and dropped, so a quoted note from outside your relays renders dead even though its author said where it lives. Hashtags are drawn like every other link and carry no target. The bookmark button does nothing.
Then the ordinary parts. Pictures, which is one absence with three symptoms: no posting a
photo, no avatar, no banner. Uploading is Blossom
rather than a NIP: BUD-02 PUT /upload, authorised by a signed kind 24242 event (BUD-11),
aimed at the servers in your kind 10063 list (BUD-03), with a NIP-92 imeta tag so they
render elsewhere. A profile with more than three fields, because Plaza reads nine out of a
kind 0 and lets you edit three, and lud16 is not one of them, so an account set up only in
Plaza cannot receive a zap at all. Zaps you can send, not only verify. Finding a person, both
locally over the profiles already on your disk and through NIP-50 where a relay supports it.
Deleting your own note, NIP-36 content warnings, and something drawn in place of a kind Plaza
cannot render.
An app worth leaving open
Nothing Plaza knows leaves the window today: no notification reaches you, and once the people you follow run dry there is nothing else to read.
Notifications at the level of the system, which a native app holding live relay connections can do with no server in the middle. Feeds with more than one shape: a hashtag, a single relay, a saved relay set, follow packs as real events rather than a hardcoded list. A store you can see and reclaim, because Plaza keeps everything it has ever ingested and gives you no way to see how large that has grown. Muting a word, a hashtag or a thread, and for an afternoon rather than forever. An update path, so people who installed are not stranded on whatever version they downloaded. Operable without a mouse, a light theme, and type that scales.
Places go further: the entered list as an encrypted event so it follows you between machines, notifications labelled with which place they came from, a way to find a place that is not somebody handing you a link, and a publishing path the two clients share rather than a document somebody has to republish by hand. A place link does nothing on a machine without Plaza, so getplaza.social will resolve the same address in a browser.
And a NIP-47 wallet connection, with an approval surface in Notary so a payment is something you agree to rather than something that happens.
What the local store was for
Everything Plaza does reads from a database on your own disk, and none of it can be searched. Finding a note you read last week, by words you remember, with the network off, is the thing a client without a local store cannot offer.
Private messages: NIP-17, gift wrapped per NIP-59 (a kind 13 seal inside a kind 1059 wrap), on the local store, signing through Notary, published only to the recipient’s kind 10050 DM relays. The seal’s conversation key derives from the identity key, so the signer has to do the NIP-44 work; Notary and the library already do, and it is Plaza’s own NIP-46 client that has to learn to ask for it.
NIP-23 long-form, which is a large part of what people write here and which Plaza cannot display. NIP-71 video that actually plays, which in a renderer with no browser means platform decode and compositing rather than an embed. And NIP-60 wallets with NIP-61 nutzaps, Cashu ecash sent to a pubkey: a Lightning zap needs an LNURL provider the recipient signed up for in advance, and an account four clicks old has none, so this is what makes a new person payable at all.
Groups, other machines, and the library at 1.0
Groups: NIP-29, on relays that support it. Every event carries an h tag with the group id,
joining is a kind 9021 request, and the relay hosting the group is the authority on who is in
it. Gated on what a relay declares in its NIP-11 document.
Other platforms. Linux builds and passes the full suite in CI on every change and there is
still no package, because off macOS the toolkit renders through a software rasteriser with no
platform text provider, which is upstream work as much as mine. Windows is not in CI at all:
the relay transport resolves hostnames through libc getaddrinfo, which Zig’s standard
library does not declare for Windows.
And the library at 1.0. It has been pre-1.0 on purpose while the API moved underneath it. Everything above lands there first, so by the time the rest of this is done the parts worth freezing have stopped moving.
What this deliberately does not do
Naming these is half of a roadmap, because each looks obviously worth doing until you price it.
- A packaged Windows release, for now. The relay transport resolves hostnames through
libc
getaddrinfo, which Zig’s standard library does not declare for Windows, so nothing depending on the library links there. That is a gap in the protocol library rather than in any app, and Windows joins the matrix as soon as it closes. - Multi-account. It taxes every feature after it: per-account stores, relay pools, notification state, and switching without a reconnect storm. A read-only “view as” answers most of the real demand.
- Set-reconciliation sync (NIP-77). Relay support is thin and the protocol is easy to get subtly wrong. Per-relay cursors capture most of the benefit against a store that already answers a feed query in under a millisecond.
- C-ABI bindings, WASM, and mobile. Real work for a set of consumers that is currently empty. Each becomes worth doing the day somebody names a project that needs it.
- A proof of work difficulty slider (NIP-13). Reading proof of work is cheap: count the
leading zero bits of the event id and honour the target committed in the
noncetag. A slider is not, and none of the mainstream relays I checked ask for any difficulty, so the setting would buy background mining, a cancel path and per-kind policy for nothing. Mining when a relay actually asks, throughmin_pow_difficultyin its NIP-11 document or anOKrejection that startspow:, needs no setting at all. - NIP-96 HTTP file storage. Supporting both upload paths looks like broader
compatibility. NIP-96 carries an
unrecommendedbanner in its own spec and the NIPs index strikes it through as replaced by Blossom, so uploads go to Blossom (item 6) and nowhere else. - Web-of-trust distance filtering. Computed over a store that holds only what you happened to sync, the graph is wrong in a way that changes between launches, so the same reply appears and disappears for reasons nobody can explain.