← directory

kind 35128 · 2026-10-12 22:46 UTC

BBSNostr — a dial-up bulletin board for Nostr, in one nostr napplet

What it is BBSNostr is a single-file Nostr client that looks and feels like a 1990s bulletin board system. Relays are phone lines. Your key is your callsign. Posts are kind:1 events. Boards are t-tagged feeds. Doors are sandboxed mini-apps. There is no build step, no server, no install, no dependency manager. You open index.html and you are on the BBS. How to run it Save the file as index.html and open it from file:// or drop it on any static host. The only network call is a single pinned import of nostr-tools from esm.sh at first paint. After that the browser caches it. Everything else — CSS, JS, doors, terminal chrome — is inline. First boot You will be asked to set a callsign. Three ways: generate a fresh keypair (recommended), import an existing nsec, or attach a NIP-07 browser extension if one is installed. Generated keys are encrypted with your passphrase using PBKDF2-SHA-256 at 200k iterations and AES-GCM before they touch localStorage. If you skip the passphrase, you write the nsec down and the plaintext key is never persisted. The relay pool BBSNostr ships a candidate registry of 72 public relays. At any moment exactly six are dialed and open. The pool scores every relay by successful reads, successful writes, rate-limit rejections, blocks, invalid events, and timeouts. Every 60 seconds it decays scores, fills empty slots with the best available candidate, and swaps out the worst active relay when a better one beats it by 15 points. A rejection that drops a relay below -15 triggers an immediate forced swap. Subscriptions are replayed against any relay that comes online mid-session, so a rotation never drops a board. Health persists to localStorage so the next session starts smarter than the last. Phone Book The Phone Book screen is the pool dashboard. The top table lists the six active relays with their state, score, and OK-to-error ratio. You can hang up on any of them. The second table lists the top 30 inactive room candidates sorted by score; DIAL promotes one immediately and. dem Youotes the can worst active relay to make add your own relay URL, force a rotation, or reset every score to zero. Boards and posts Eight curated boards are registered by default: #nostr, #bitcoin, #art, #dev, #music, #food, #retro, #help. You can add up to eight more. Opening a board fires a REQ for kind:1 events tagged with that slug against every active read relay. Each post card shows MSG# (first four characters of the event id), the board, a time-ago stamp, the author's display name if their kind:0 profile has been seen, the subject line if one was set, and the content. Quote lines beginning with > render dim. nostr: URIs are clickable and copy to clipboard. Composing Press C on a board to compose. Optional NIP-14 subject. Live character counter that turns amber at 3500 and red at 3950. When you hit post, the client signs the event locally, verifies the signature with the same library, and only then publishes to every active write relay. Each relay reports back with an OK frame and you see per-relay receipts inline. A relay that times out is marked as such. Nothing is sent unverified. Replies, reactions, reposts, deletes Replies use proper NIP-10 tags: a root marker, a reply marker, and a p tag on the parent author. Reactions are kind:7 events with the heart button; the count is live. Reposts are kind:6 events with the boost button. Your own posts carry a DELETE button that publishes a kind:5 request; relays may or may not honor it, which the UI acknowledges before you send. Profiles Click any author name to open a profile screen. If a kind:0 event for that pubkey is in the store, its name, about text, and nip05 appear. Their npub and hex pubkey are both copyable. Their recent posts across every board you have visited show up below. Doors Doors are sandboxed mini-apps that run inside a srcdoc iframe. Only one is alive at a time. The iframe is sandboxed with allow-scripts only — no same-origin, no forms, no top navigation. It talks to the parent through a strict postMessage envelope that checks both the source window and a per-instance UUID. Three doors ship: ASCII PAINT (draws a 40x20 canvas and exports it as an #art post), GUESTBOOK (reads the current board and signs a message), and NOSTR DICE (commit-reveal randomness across two signed events). Doors never see your nsec. They can only ask the parent to sign a template, and the parent prompts you before doing it. Command palette Ctrl+K opens a fuzzy command palette. Type to filter. Press a number to jump. Enter runs the first match. It covers every navigation command, refresh, compose, and forced relay rotation. Keyboard 1-9 jump to numbered items. Enter selects. Esc goes back. ? toggles help. / focuses the board search. C composes. R refreshes. Ctrl+K opens the palette. Ctrl+L opens the sysop log. Ctrl+Enter posts from the composer. Q on the main menu logs off and clears your identity from the device. Storage Every key is namespaced under bbsnostr:v1:. Identity, relays, boards, relay health, and unread markers each have their own validator. A corrupt value is dropped and the slice resets to defaults rather than crashing. When the whole namespace approaches 800 KB, the least important slice is evicted first, and identity is never a candidate. What it deliberately does not do It does not use eval, new Function, or document.write. It does not use inline event handlers. It does not pass untrusted strings to innerHTML. It does not open more than six sockets. It does not store your raw private key when you chose a passphrase. It does not send telemetry anywhere; the sysop log is an in-memory ring buffer of 200 entries, visible only to you. It does not accept an event whose signature fails verification. Attribution The protocol belongs to the NIP authors. BBSNostr is a client, and a nostalgic one at that. Everything it does on the wire is a NIP or a convention the network already speaks.

yellow npub1ctc6knn22a7a3xqt2ls4nphdj2psh9dffum5ry3r2434x26u4ssq8hx62x

2 files in the manifest · size billed from the file band until the blobs are here. up to 20 files, 10 MB included.

up to 20 files, 10 MB included
21,000 sats/year
30 days
2,100 sats (one tenth)

Card 21,000/year (20 files, 10 MB). Site 42,000 (200 files, 100 MB). App 84,000 (2,000 files, 1 GB). Past that, 42,000 per extra 1,000 files and 5,000 per extra 100 MB, per year. 30 days is one tenth. Check the domain box only if you will point DNS at this gateway. Opens a Lightning invoice. Copies the files onto https://nsitepin.com/blossom and assigns a hostname.

Missing files

These files were checked. They were not on the hosts listed here.

pathsha256missing on
/__MACOSX/._index.html 00955c70e38aafd2f20efca49ba95c1c3c5641f00b6eb868184bae27d5ada165
https://nostr.download · missing

Manifest

event id
7d57b1dc3176a3a524590eb84c0963cd6edc99b5eb63126b8bd94d1cd9f56b5a
aggregate x
None
d tag
bbs-nostr

Paths

pathsha256hosts
/index.html f6e7a486c7415a60b61c04278ff5e1d11e579f191b49ac2878cf0513f4f3e7e8
https://nsite.run · degraded
https://nostr.download · degraded
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
preview
/__MACOSX/._index.html 00955c70e38aafd2f20efca49ba95c1c3c5641f00b6eb868184bae27d5ada165
https://nsite.run · degraded
https://nostr.download · missing
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
preview
/404.html f6e7a486c7415a60b61c04278ff5e1d11e579f191b49ac2878cf0513f4f3e7e8
https://nsite.run · degraded
https://nostr.download · degraded
https://blssm.us · degraded
https://blossom.yakihonne.com · degraded
https://zencrown.relay2aeon.quest/ · degraded
preview