Building the terminal HN
p2pbuilders shipped as a terminal app: pear run Legacy app — migration required: pear://… drops you at
a › prompt on a live P2P board. This article is how it is built and the
decisions that got it out the door.
Architecture
Two halves, cleanly split:
- Backend (
src/backend/): the Node class (Corestore + one Hypercore
per identity), the op schema, PoW minting/checking, the Hyperbee indexer
that folds every tracked core into hot/new/top views, reputation, rate
limits, and a Hyperswarm layer with a protomux announce channel. All
runtime-portable via one _rt.js shim (Bare walkthrough).
- Terminal UI (
src/terminal/main.js): a single readline loop over a
tiny state machine — feed view, thread view, compose mode. Commands are
first-word dispatch (submit, open 3, up 2, reply, …). ANSI
colors and a screen-clear redraw; a debounce coalesces peer-driven
refreshes so gossip storms do not flicker the screen.
Everything crosses one JSON-RPC dispatch layer — the same method surface the
dev HTTP/WS server and the (parked) iOS pipe use. The UI cannot reach into
internals; every transport gets the same API.
Decisions that shipped it
- Reddit-shaped → HN-shaped. Boards + browsable lists were most of the UI
scope. One front feed cut it to a screen and a half of rendering; the
data model kept the board field, so the pivot cost nothing on-chain.
- TUI first. The desktop GUI stack fought us (install-time timeouts), so
the terminal became the product. A readline loop has no build step, runs
identically under Bare and Node, and made the P2P parts — the actual hard
parts — the whole job.
- Compose mode over flags. Multi-line posts arrive as a tiny modal state:
type lines, . submits, :q cancels. The whole editor is ~60 lines.
- Constants over admin systems. Moderation is one
ADMIN_PUBKEY
constant enforced by the indexer (admin tombstones are honored for any
target; everyone else, own ops only). Pinned posts are a hardcoded opId
list. Governance-by-recompile is honest for the current scale — the
enforcement point (indexer, not UI) is what makes it real.
What it proved
41 tests cover every layer; the same backend booted under raw Bare (the iOS
milestone) without changes. The bet that "the app is the log + the fold, the
UI is whatever is cheapest today" — the whole premise of the
foundations track — held.