Public: anyone can read this; the crew can change it.
A board link does not end up in a search index: x-robots-tag, a robots.txt, and a sentence in the README #117
Check · Review · Land · Live done — Landed and live in production.
A board's id is its access control, so a board must not end up in a search index. New `src/robots.ts` holds the one list of paths crawlers are asked to stay out of — `/b/` and `/mcp` — and three places read it: `src/server.ts` sets `x-robots-tag: noindex, nofollow, noarchive` on every response under those paths, right beside the security floor (so the board page, its `/events` stream and its JSON…
shipped production is serving it deploy fc047f8
Sign in to join this conversation.
new above
offline
A board's id is its access control, so a board must not end up in a search index. New
src/robots.tsholds the one list of paths crawlers are asked to stay out of —/b/and/mcp— and three places read it:src/server.tssetsx-robots-tag: noindex, nofollow, noarchiveon every response under those paths, right beside the security floor (so the board page, its/eventsstream and its JSON all carry it, and a new route under/b/carries it the day it's written);src/routes.tsanswersGET /robots.txtfrom the same list astext/plainwith a day-long cache, prefixes only and never a board id;src/pages/board.tsrepeats it as<meta name="robots">for the crawler that reads HTML and not headers./and/static/*are left indexable on purpose — the front door names no board — and the comment next to the header says so.This is the accident closed, not the hole, and nothing in the code, comments or README pretends otherwise: a crawler that ignores the request, and anyone who has the link, still has the board. The stronger thing (a board that requires being signed in and named on it) would be a different app and is not half-built here. The README's "What's simulated" gains a paragraph saying exactly that.
Worth a look:
withFloorinsrc/server.tsnow takes the request path, which touched every call site including the 403/413 early returns and the error handler (which has no path and passes""). AndnewBoard()insrc/server.test.tsnow resets the process-wide creation bucket and retries once on a 429 — that file already created boards right up to the 30-a-minute limit, so the two tests added here tipped two unrelated ones over; the refusal itself is still tested insrc/limits.ts's own tests, untouched. New tests: a board page, its stream, a board JSON write and a/b/404 all carry the header;/and/static/*don't;/robots.txthas bothDisallowlines and no board id.bun test: 196 pass. No new dependencies. Try it in the preview withcurl -sI <preview>/b/<id>andcurl -s <preview>/robots.txt.🤖 Generated with Claude Code
Closes #58