node · 2026-06-04 documentation public
The surfaces

# Three Readers, One Vault

The vault on disk IS the state. Three programs read and write the same Markdown + HTML directly — none of them owns it, and there is no sync layer between them.

## The hub-and-spokes

Every spoke is two-way: each reader reads and writes the same bytes — no program owns the vault, no sync layer sits between them.
nodes/
plain Markdown + HTML on disk · the single source of truth
react surface
local-viewer

Zero-dep Node server on `:7373`. Renders `<slug>.html` in an iframe; 👍/👎/comment write `feedback.md`; + appends to `viewer-drain.md`; archive moves to `archive/`.

edit surface
Obsidian

Markdown editor + force-directed graph. `[[wikilinks]]` resolve by basename vault-wide — which is why every node's MD is self-titled.

history
GitHub

Durable lineage. Auto-commit backups give every node a `git` diff history alongside its provenance.

## The defining choice

No database. No backend state beyond the filesystem.

The viewer is a thin shell around `readFile` / `writeFile` / `readdir` / `rename` / `fs.watch`. So all three readers see the same bytes and any can change them. `fs.watch` + SSE at `/api/events` keep the browser live no matter who edited. The HTTP API mirrors the Cloudflare Worker shape so the same frontend works local and public.

## Tags are wikilinks; the graph is emergent

No separate tag namespace — a tag is just a `[[wikilink]]` on a `Tags:` line pointing at a node named after the tag. The graph force-directs every file by its links, so tag-nodes become hubs and clusters form without curation. One tag is load-bearing: [[public]] is the deploy filter — the Cloudflare worker behind `streetlight.jakesimonds.com` ships only nodes carrying it. Tagging is publishing.

Synthesizes the former `the-local-viewer` + `obsidian-and-graph` docs. Part of the 5-node public-doc synthesis (2026-06-04). · ← Overview