From 2ea316ffd8587a501ea2b11547ad2ae09fa3d7c6 Mon Sep 17 00:00:00 2001 From: Joe Gitta Date: Fri, 22 May 2026 20:48:02 +0000 Subject: [PATCH] =?UTF-8?q?add=20CLAUDE.md=20=E2=80=94=20full=20project=20?= =?UTF-8?q?context=20for=20AI=20assistants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a40bda4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,113 @@ +# SeniorNet Kiosk — Project Context for AI Assistants + +## What this project is + +A locked-down, zero-maintenance browser workstation for elderly users. The senior never sees a desktop — only a full-screen Chromium window with a slim toolbar on top. No configuration, no maintenance required from the user. + +## Architecture + +``` +┌─────────────────────────────────────────────────────┐ +│ PyQt5 toolbar (72px, always-on-top, FramelessHint) │ +│ [SeniorNet] [◀] [▶] [⌂] [☰ bookmarks] │ +├─────────────────────────────────────────────────────┤ +│ │ +│ Chromium --app mode │ +│ (CDP port 9222 for navigation) │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +- `browser.py` — main app. Launches both the PyQt5 toolbar and Chromium as a subprocess. +- Toolbar talks to Chromium via Chrome DevTools Protocol (CDP) over WebSocket on port 9222. +- Bookmarks stored in `bookmarks.json` (nested JSON, supports folders). +- Home screen: `/home/jgitta/kiosk-home/index.html` + +## Machines + +### kiosk-dev — 192.168.88.48 (SSH alias: `kiosk-dev`) ← ACTIVE DEV MACHINE +- Debian 13 Trixie, Proxmox VM 130 on jg-hud +- System Chromium: `/usr/lib/chromium/chromium` — NOT snap +- Repo at: `/home/jgitta/kiosk-browser/` +- This is the machine being actively developed and tested on + +### Production kiosk — 192.168.88.44 (SSH alias: `kiosk`) +- Ubuntu 24.04 + snap Chromium — needs to be migrated to Debian to match kiosk-dev +- Currently offline / pending migration + +## Deploy workflow + +```bash +bash /home/jgitta/kiosk-browser/deploy.sh "describe your change" +``` + +This: commits + pushes to Gitea, restarts kiosk-dev immediately, and deploys to production if reachable. + +**CRITICAL**: `kiosk-restart` must kill Chromium (`pkill -f "remote-debugging-port=9222"`) BEFORE killing browser.py. If only Python is killed, Chromium holds the SingletonLock and the new instance silently exits — deploys appear to work but nothing changes on screen. + +`/usr/local/bin/kiosk-restart` on kiosk-dev: +```bash +pkill -f "remote-debugging-port=9222" || true +pkill -f "python3.*browser" || true +sleep 1 +``` + +## Key files + +| File | Purpose | +|------|---------| +| `browser.py` | Main application — toolbar + CDP + Chromium launcher | +| `bookmarks.json` | Nested bookmark structure | +| `deploy.sh` | One-command deploy | +| `/home/jgitta/kiosk-home/index.html` | Senior home screen | +| `~/.config/openbox/autostart` | Auto-restart loop on crash | +| `/usr/local/bin/kiosk-restart` | Safe restart (kills Chromium + Python) | +| `/etc/X11/xorg.conf.d/50-kiosk-hardening.conf` | Blocks TTY switching | + +## Gitea repo + +`https://gitea.jgitta.com/jgitta/senior-kiosk` — master branch + +## Roundcube webmail + +- URL: https://mail.jgitta.com/roundcube/ (proxied via Caddy at 192.168.88.110) +- LXC container 203 on jg-hud, IP: 192.168.88.45 +- Ubuntu 24.04, Apache2, PHP, MariaDB, Roundcube 1.6.6 +- Gmail IMAP: `ssl://imap.gmail.com:993` +- Autologin plugin: `/var/lib/roundcube/plugins/autologin/autologin.php` +- Logs: `/var/lib/roundcube/logs/autologin.log` and `errors.log` +- Run commands on container: `ssh jg-hud "pct exec 203 -- bash -c '...'"` (jg-hud is the Proxmox host) +- browser.py clears the Roundcube session cookie on every startup (forces fresh autologin) + +## Known hard-won lessons + +### Chromium +- `--no-sandbox` causes "unsupported flag" infobar — never use it on Debian system Chromium +- `--test-type` triggers Google CAPTCHA bot detection — never use it +- `--disable-blink-features=AutomationControlled` causes "unsupported flag" infobar — removed +- `--disable-infobars`, `--disable-session-crashed-bubble`, `--disable-save-password-bubble`, `--suppress-message-center-popups`, `--disable-translate` are all deprecated/removed in current Chromium — do not use +- Profile dir: `/home/jgitta/chromium-kiosk` (not hidden — snap couldn't write hidden dirs; kept this convention) +- Chromium adds its own flags via the Debian wrapper (`--show-component-extension-options` etc.) — ignore these, they're harmless + +### PyQt5 / Openbox +- `QMenu` does NOT work under Openbox/X11 with `Qt.Tool | WindowStaysOnTopHint` parent — use a custom `QWidget` with the same flags instead (BookmarkPanel) +- Qt event filters only see clicks on Qt widgets — clicks that land on Chromium (separate X11 process) are invisible. Use a `QTimer` polling `QApplication.mouseButtons()` + `QCursor.pos()` to detect outside clicks. +- To prevent toolbar minimize: override `changeEvent`, detect `Qt.WindowMinimized`, call `QTimer.singleShot(50, self._self_restore)` +- To restore minimized Chromium: periodic `QTimer` + `xprop -id _NET_WM_STATE` to check `_NET_WM_STATE_HIDDEN`, then `xdotool windowmap ` + +### Roundcube autologin +- Plugin MUST call both `session->regenerate_id(false)` AND `session->set_auth_cookie()` after login +- Logs are in `/var/lib/roundcube/logs/` NOT `/var/log/roundcube/` + +### Deployment +- `pkill -f browser.py` in SSH kills its own session (shell cmdline contains "browser.py") — use `kiosk-restart` +- Chromium must be killed before Python or SingletonLock prevents new instance from starting + +## Infrastructure overview + +- **Proxmox host**: jg-hud (main), siklos (192.168.88.27) +- **TrueNAS**: 192.168.88.24 +- **Thinkstation** (dev desktop): 192.168.88.41 +- **Caddy reverse proxy**: 192.168.88.110 — handles *.jgitta.com +- **Gitea**: gitea.jgitta.com (port 3002 internal) +- **Headscale**: self-hosted Tailscale on siklos