# 888.church > Ben Banker — gouache painter and digital artist. This site also offers a public-domain museum art feed for > visiting AI bots (short-lived tokens, poster builder). All links below are relative: use them on the host you fetched this file from. **Start here:** [/witness](/witness) explains the bot program in plain language: join for free, get a 1-hour token, read Ben Banker's Witness art feed and search open-access museum art. Read-only; nothing is posted anywhere. ## Bot instructions - [Art feed: tokens, reading the feed, limits](/bot-instructions/feed.md) — joining takes two steps: `GET /api/feed/challenge`, solve a small SHA-256 proof-of-work, then `POST /api/feed/join` with `{challenge, solution}`. Keep the returned `device_id` and send it as `X-Device-Id` every time. - [Posters: build and share a public-domain poster](/bot-instructions/poster.md) - [Art search + Witness discovery](/bot-instructions/search.md): with the same feed token, `GET /api/search?q=` searches many open-access museums and libraries at once; `GET /api/witness/feed?pack=` gives Witness subject feeds with factual captions. Sources and their status: `GET /api/sources` (no token). 200 search calls per token per day. ## Human pages - [Art feed (Join for a token, gallery)](/feed) - [Works](/works) - [Store](/store) ## Joining the art feed (short version) ```python import hashlib, json, urllib.request BASE = ""; dev = None # reuse your saved device_id def call(p, b=None): h = {"Content-Type": "application/json", **({"X-Device-Id": dev} if dev else {})} return json.load(urllib.request.urlopen(urllib.request.Request(BASE + p, json.dumps(b).encode() if b else None, h))) c = call("/api/feed/challenge"); dev = c["device_id"]; i = 0 ok = lambda s: 256 - int.from_bytes(hashlib.sha256((c["challenge"] + s).encode()).digest(), "big").bit_length() >= c["difficulty"] while not ok(format(i, "x")): i += 1 token = call("/api/feed/join", {"challenge": c["challenge"], "solution": format(i, "x")})["token"] ``` ```js const { createHash } = await import('node:crypto'); const BASE = ''; let dev; // saved device_id const H = () => ({ 'Content-Type': 'application/json', ...(dev ? { 'X-Device-Id': dev } : {}) }); const zb = (b) => { let n = 0; for (const x of b) { if (x) return n + Math.clz32(x) - 24; n += 8; } return n; }; const c = await (await fetch(BASE + '/api/feed/challenge', { headers: H() })).json(); dev = c.device_id; let i = 0; while (zb(createHash('sha256').update(c.challenge + i.toString(36)).digest()) < c.difficulty) i++; const { token } = await (await fetch(BASE + '/api/feed/join', { method: 'POST', headers: H(), body: JSON.stringify({ challenge: c.challenge, solution: i.toString(36) }) })).json(); ```