Frank Program · homepage design grilling · overnight progress report · 2026-08-22 · from the chief designer
summary settled: 5 decisions + styling open: 38 questions (Q6-Q43) baseline dankclaw: UP (10/10) dankserver: media stack DOWN (no .env) state WIP — /srv/homepage/ not deployed; Caddy site live (401 / 302) next answer Q6-Q43 in the morning; then build order is fixed
| # | Decision | Value |
|---|---|---|
| Q1 | How the page learns up/down | Server-side checker writes status.json; the page reads only that file. (Eventual target: client-side probing — documented.) |
| Q2 | How the checker runs | systemd timer, rewrites status.json every 3 minutes. |
| Q3 | Page model | Single site on Dankclaw. Root = user services (no host labels). /admin/ = admin services, second operator-only password. Optional /how/ tourist page. |
| Q5 | Service split | User: SearXNG, ComfyUI, OpenWebUI, Gitea, Calibre-Web, RomM, Copyparty, Plex, Jellyfin. Admin: Hermes, Grafana, Prometheus, Loki, Caddy, dnsmasq, Gluetun, LLM fleet, low-level backends (status-only). *arr stack excluded (separate effort). |
| — | Styling | Terminal TUI. Terminus (monospace fallback). Green-on-black. 1995 phosphor palette. |
Palette: bg #050805 · text #33ff66 · up #33ff66 · down #ff5555 · WIP #ffcc33 · links #33ccff · headers #aaffcc.
Source: real HTTP fetch through Caddy + ss -ltn (they agree). The earlier /dev/tcp probe was the false one — it reported every port down while Caddy returned 200.
| Service | Site | HTTP | Port | State |
|---|---|---|---|---|
| Homepage | dankclaw | 401 | — | WIP auth-gated, not deployed |
| SearXNG | search | 401 | 8081 ✓ | UP (auth-gated) |
| ComfyUI | comfyui | 200 | 8188 ✓ | UP |
| OpenWebUI | chat | 401 | 3005 ✓ | UP (auth-gated) |
| Hermes | hermes | 401 | 8090 ✓ | UP (auth-gated) |
| Gitea | gitea | 200 | 3000 ✓ | UP |
| Grafana | grafana | 401 | 3002 ✓ | UP (auth-gated) |
| Prometheus | prometheus | 401 | 9090 ✓ | UP (auth-gated) |
| Loki | loki | 404 | 3100 ✓ | UP (no root page) |
| frank-default-large | :7770 | ok | 7770 ✓ | UP |
| Service | Site | HTTP | Port | State |
|---|---|---|---|---|
| Calibre-Web | books | 302 | 8083 ✓ | UP |
| frank-default-small | :7770 | ok | 7770 ✓ | UP |
| Plex | plex | 502 / 000 | 32400 bound | UNDETERMINED port bound, no HTTP reply |
| RomM | romm | 401 | 8085 ✗ | DOWN (401 = auth challenge only) |
| Copyparty | files | 401 | 3923 ✗ | DOWN (401 = auth challenge only) |
| Jellyfin | jellyfin | 502 | 8096 ✗ | DOWN |
| Radarr / Sonarr / Lidarr / Readarr / Prowlarr / qBittorrent | — | 502 | ✗ | DOWN (not started — *arr effort) |
1The port-probe contradiction is resolved. My first probe (/dev/tcp nested in bash -c over SSH) reported every port down while Caddy returned 200 in the same call. The ss -ltn + HTTP-fetch pair is the ground truth and they agree. Do not trust the /dev/tcp one-liner in an SSH'd subshell.
2The 401 trap. For basicauth sites, Caddy serves the 401 challenge before the proxy. So a 401 does not prove the backend is up — RomM and Copyparty return 401 while their ports are down. This is why the checker must probe the backend host:port directly, never the Caddy site.
3The homepage's core mechanism is architecturally blocked. The page is https://dankclaw.franksdank.cloud; the service URLs are http://<name>.franksdank.cloud. A browser fetch of those is cross-origin (CORS-blocked), mixed content (https→http, hard-blocked), and auth-gated (401). Three independent failures. Hence the server-side status.json design.
4The Dankserver media stack is down, and the cause is a missing .env. Only Calibre-Web (no secret deps) and the LLM (separate systemd unit) are up. compose.yaml needs MARIADB_ROOT_PASSWORD, ROMM_*, COPAY_PASS, … — none present on the target. This is a separate, urgent work item, distinct from the homepage.
5Plex is in an odd state. Port 32400 is bound on 0.0.0.0 but a direct HTTP request gets no reply (000). Needs a look — it may be a stale socket or a non-HTTP listener. Flagged as UNDETERMINED, not counted up or down.
6LLM "loading" nuance. During model load the LLM /health returns 503. A TCP-connect probe still reads "up" (the port is listening). Kept to three states for now; a dedicated "loading" state is a later refinement.
7My host is outside the LAN. *.franksdank.cloud resolves to the public IP here; the services are LAN-only (dnsmasq maps them to 192.168.0.143 for LAN clients). So page loads and probes must run from Dankclaw.
| Thread | What it is | Status |
|---|---|---|
| 1 · Homepage | This design. Server-side status, user + admin pages, terminal TUI. | GRILLING 38 open questions |
| 2 · Dankserver media stack | Down. Needs a .env (secrets) + a compose deploy. | BLOCKED separate, urgent |
| 3 · *arr stack | Radarr/Sonarr/Lidarr/Readarr/Prowlarr/qBittorrent. Not started; possibly a different host. | NOT STARTED |
| 4 · Usage-docs | Per-service how-to pages, maintained separately from the reference docs. | NOT STARTED |
| 5 · "How it's built" | Optional public architecture page for tourists. | OPTIONAL |
| 6 · Plex | Investigate the bound-but-silent port 32400. | INVESTIGATE |
| 7 · Client-side probing | Documented future intent: same-origin https paths + per-service health + CORS. | LATER |
Each carries a recommendation. Reply AGREE to accept it, or state the change. Group by category letter.
/how/ "tourist" page: build now or defer?Rec: defer. When built, make it public (no auth) so a visitor can see the architecture; render the mermaid diagrams from this repo.verdict: AGREE · or change to: ____status.json or two (user-status.json + admin-status.json)?Rec: one status.json; each service carries a category field; each page filters client-side.verdict: AGREE · or change to: ____services.json or split by page?Rec: one services.json with a category field; the checker reads one file.verdict: AGREE · or change to: ____nc variant works but hand-rolled JSON is error-prone.verdict: AGREE · or change to: ____host:port. Uniform, works for non-HTTP backends, matches the verified ground truth.verdict: AGREE · or change to: ____/health and treat 503 as Up. A "loading" state is a later refinement.verdict: AGREE · or change to: ____scripts/homepage-status.py + scripts/homepage-status.service + scripts/homepage-status.timer, tracked in git.verdict: AGREE · or change to: ____probe field is a full host:port — 127.0.0.1:PORT for Dankclaw, 192.168.0.235:PORT for Dankserver. Verified reachable over the LAN.verdict: AGREE · or change to: ____"wip": true field; the checker skips the probe. Drop the old self-referential "Homepage" entry.verdict: AGREE · or change to: ____status.json is old?Rec: write a generated_at timestamp; the page warns "status may be stale" when it is older than 10 minutes.verdict: AGREE · or change to: ____status.json. A crash never leaves a half-written file.verdict: AGREE · or change to: ____.env variable?Rec: yes — CADDY_ADMIN_HASH in the host .env (git-ignored), rendered at deploy, operator-only. Root keeps CADDY_BASICAUTH_HASH.verdict: AGREE · or change to: ____@admin path /admin/* matcher with a second basicauth @admin block. Confirm exact syntax against the Caddy docs during implementation.verdict: AGREE · or change to: ____services.json, drafted from the existing reference docs.verdict: AGREE · or change to: ____showLink: false.verdict: AGREE · or change to: ____systemctl list-units). Columns: STATUS | NAME | description | (open) (docs).verdict: AGREE · or change to: ____UP 9 DOWN 2 WIP 1.verdict: AGREE · or change to: ____@font-face, with a monospace fallback. Confirm the license (freely distributable) and drop files in fonts/.verdict: AGREE · or change to: ____#33ff66, red #ff5555, amber #ffcc33, cyan #33ccff, bg #050805). Tune for contrast.verdict: AGREE · or change to: ____text-shadow. Make it toggleable (?crt=0).verdict: AGREE · or change to: ____prefers-reduced-motion.verdict: AGREE · or change to: ____/usage/<svc>/; source under shared/homepage/usage/<svc>/.verdict: AGREE · or change to: ____deploy.sh (Dankclaw path): copy shared/homepage/ to /srv/homepage/, install the timer + service, render the Caddyfile (both hashes), reload Caddy.verdict: AGREE · or change to: ____/srv/homepage/?Rec: deploy.sh creates it and copies the assets; the checker writes status.json there at runtime.verdict: AGREE · or change to: ____status.json schema. TDD, per repo rules.verdict: AGREE · or change to: ____services.json schema, run caddy validate, and check the pages reference status.json.verdict: AGREE · or change to: ____/admin/).verdict: AGREE · or change to: ____probe field is a full host:port; a move is a config edit.verdict: AGREE · or change to: ____status.json every 60 s (the file updates every 3 min).verdict: AGREE · or change to: ____last checked HH:MM:SS from generated_at.verdict: AGREE · or change to: ____| File | Change |
|---|---|
docs/Infrastructure/Homepage.md | Rewritten to the settled design: structure, status model, checker, auth, classification, layout. Added three mermaid diagrams (site structure, status states, checker flow). |
docs/Infrastructure/Homepage Design Grilling.md | New. The decision log: settled Q1–Q5 + the 38 open questions (Q6–Q43) with recommendations + the build-order diagram. |
docs/index.md | Linked the new grilling page (satisfies the "index links every page" test). |
~/.pi/agent/docs/log.md | Added a homepage-design bullet to the 2026-08-22 entry (design, baseline, threads). |
report/homepage-grilling-2026-08-22.html | This report. Self-contained, terminal-TUI styled. |
Reply to the open questions (Q6–Q43) — AGREE or the change, grouped by category. Once settled, the build order is fixed:
settle Q6-Q43 -> write services.json + checker -> write pages + theme -> extend deploy.sh + Caddyfile -> tests green -> deploy to Dankclaw -> verify in browser
Separate threads to schedule (not part of the homepage build): the Dankserver media stack (missing .env), the *arr stack, the usage-docs workstream, the optional "how it's built" page, and the Plex investigation.
Report is self-contained (no network needed). A copy is committed at report/homepage-grilling-2026-08-22.html and served at the URL below.
generated 2026-08-22 (night) · frank program · chief designer · tests: 97/97 green