5.1 KiB
The Booth — ephemeral media board + operator decisions
URL: http://10.100.10.50:8090/ · CLI: booth (on PATH on nh3-dev)
Storage: a booth is just a folder — ~/booth-data/<name>/ on nh3-dev. No upload API.
Wiped 24h after last activity unless kept. No auth (LAN/WG-internal), so never drop secrets in a booth.
Ephemeral is the default; KEEP is the exception, not the rule. A booth is
meant to be wiped by the 24h sweep. Only booth keep a booth whose data must
explicitly persist beyond 24h — a standing board, or a record the operator
will deliberately revisit — never "just in case". When in doubt, leave it
ephemeral: a wiped render is cheap to regenerate, whereas a pile of stale kept
booths is clutter that never cleans itself up.
Show the operator something
booth new <name>; booth add <name> <file>... # or just cp/rsync into ~/booth-data/<name>/
rsync -a ./out/ nh3-dev:booth-data/<name>/ # from another host
booth url <name> # -> http://10.100.10.50:8090/b/<name>/
booth keep <name> / booth unkeep <name> # exempt from / restore the 24h sweep (the exception — only for data that must persist >24h)
Auto-renders a gallery of images, webm+mp4 video and audio. A <file>.txt sidecar
becomes that item's caption (this is how you label an A/B pair). A folder's own
index.html is served verbatim — build a custom report when you want one.
Ask the operator to decide (no chat round-trip)
As of Booth v0.2.x an ask is one shape of a MARK — pick (this), note (free
text the operator volunteers), flag (the operator pointing at one item). All three
are read the same way, and the operator can now flag and annotate items, which he
previously had to relay in chat.
booth ask <booth> <id> "<prompt>" "<option A>" "<option B>" [...] [--no-notes]
booth answer <booth> <id> --wait # blocks until answered (default 1h)
booth answer <booth> <id> # non-blocking; exit 1 while unanswered
booth marks <booth> [--wait [SECS]] # EVERY mark, as JSON; --wait while any pick is open
booth marks-import <booth> # pull pre-v0.2 sidecars in; deletes nothing
booth asks <booth> survives as a deprecated alias for marks and now emits JSON,
not the old aligned table — if you parse those columns, that parse is broken.
Open picks are flagged on the Booth front page, so a waiting question is visible without pinging anyone. ⚠ A partially answered pick counts as OPEN (changed in v0.2.0; the old badge called it closed while the panel called it partial).
Storage is one file per booth: <booth>/.marks.json. The pre-v0.2
<stem>.ask.json / <stem>.answer.json sidecar pair is gone — <stem>.answer.json
will 404 forever, so a remote session polling it is polling nothing. Read over HTTP
instead, one call for the whole booth:
curl -sf http://10.100.10.50:8090/b/<booth>/marks.json # {booth, marks:[...], open:[ids]}
Re-answering overwrites — a mark is the CURRENT judgment, not a log. Radio only, no
multi-select. Page anchors are #mark-<id> (was #ask-<stem>), and
/b/<booth>/asks 308-redirects to /b/<booth>/marks.
⚠ If a booth's .marks.json is ever damaged, reads degrade to "no marks" so the page
still loads, but every WRITE refuses with a 409 — deliberately, because overwriting
would replace every judgment in that booth. Repair it by hand; nothing deletes it.
Put the ask WHERE THE ARTIFACT IS. If the booth has its own index.html, the
Booth substitutes placeholders: <div data-booth-ask="<stem>"></div> for the whole
ask, data-booth-ask="<stem>:<question-key>" for one question's radios,
data-booth-ask-submit="<stem>" for notes + submit. (<stem> is the pick's id;
these placeholders are unchanged in v0.2.x.) Per-question fragments bind to
one form via the HTML5 form= attribute, so a five-clip audition can put each radio
group under its own audio and still submit in a single POST.
⚠ Keep the placeholder OUTSIDE any grid/flex container or it becomes a cell in it.
⚠ A partial answer is legal and you must handle it. The operator can leave any
question blank; the sidecar then carries complete: false and the blank keys in
unanswered. Check complete before acting, and read a key in unanswered as
"not decided yet", never as "declined".
Standing convention — the link board
Every operator-facing link worth more than the next thirty seconds goes on the standing link board, in the same turn you mention it.
booth link <url> "<short description>" # on nh3-dev
ssh nh3-dev 'booth link <url> "<desc>"' # from anywhere else
booth links # read it
Still put the link in your reply — this is in addition to, not instead of. Links in chat drown in scrollback; the board is a kept booth rendered at the top of the Booth front page. Don't post noise: if the operator would not click it a week from now, it does not belong there.
Full schema + rules: ~/development/booth/README.md (gitea vh/booth; extracted from eshpfi 2026-09-21)