The :hn: protocol turns Hacker News into a live link source. Zero
auth, zero server. HN exposes two public JSON APIs —
hacker-news.firebaseio.com for listings / items / users, and
hn.algolia.com for full-text search. Both serve CORS headers,
so the page calls them directly in the browser.
Every link is stamped with source_hn on its CSS class and
meta.source: 'hn', so mixed-source menus can distinguish
where each entry came from. The orange left-border below is that class.
Each sub-mode hits a different HN endpoint. :hn:top:
maps to topstories.json, :hn:new: to
newstories.json, and so on.
Top stories — front page
Newest (5)
— limit=5 named arg
Best stories — all-time highlights rolling window
Ask HN — question threads
Show HN — project launches
Jobs — YC company postings
:hn:user:username: fetches the user record then hydrates
their submitted items.
Multi-word queries can't appear inline (the tokenizer splits on spaces),
so they're aliased in config.protocols.hn.searches and
referenced as $preset. See the config.ts source.
AI papers
— alias: "artificial intelligence papers" (opens as a lens)
Rust releases
— alias: "rust release"
TypeScript strict mode
— alias: "typescript strict mode"
:hn:items:id1:id2:...: fetches zero or more specific
stories by id. Each id is its own positional segment, same shape as
any protocol's :proto:mode:arg1:arg2:. Non-numeric
positionals are dropped; no ids is a no-op. Capped at 6 per call —
HN's API has no batch endpoint, so each id is a separate fetch.
Classic HN stories (three items) — Dropbox launch + Arc Effect + HN item #1
Empty items (no-op) — menu will have no HN entries
:hn: results are just AlapLink objects, so
they compose with tags, macros, :time:, and everything
else in the expression grammar.
My reads, then top HN — macro then live data (comma = "also")
New stories in the last 6 hours
— generate protocol composed with the :time: filter
Curated HN links OR top 5 live
— static tags | live protocol results