Files
saphid--frame-control/compat-db
saphidandClaude Opus 5.5 d4486a7681 Frame Control: Mac app, web UI, Android and Steam tooling
Package the Frame Control web UI as an installable Electron Mac app and
bring in the tooling built alongside it.

- app/: Electron wrapper that starts ui/server.py on a free loopback port,
  hardened window (sandbox, no navigation, runAsNode fuse off), login-shell
  PATH so Homebrew tools work from Finder, first-run offer to run
  connect.sh, ad-hoc signed DMG/zip via electron-builder.
- ui/: headset view (OpenVR screenshots), device status, library, Steam
  "Get games" (owned games, install, store search), Android apps as
  persistent Lepton instances with a rated F-Droid catalogue and a private
  compatibility database, Android display controls over ADB, file and
  clipboard transfer, Flatpaks, remote and power actions.
- apk-catalog/, compat-db/, frame/: catalogue build pipeline, Lakebed
  capsule for compatibility reports, Frame-side launchers.
- tests/ and CI: server guard and validation tests plus Steam helper tests,
  run on Python 3.9 with script and app syntax checks.
- Docs: README leads with the Mac app; new Android, panels, Steam games and
  field-notes docs; security notes on LAN-exposed ADB ports.

Screenshot values for the headset's IP and Wi-Fi name are placeholders.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 22:21:20 +10:00
..

compat-db: Frame Control's compatibility database

A private Lakebed capsule holding compatibility reports for Android apps on the Steam Frame. Only Frame Control can read or write it.

  • Live: https://frame-compat.lakebed.app (deploy dep_dDmcsosVSiFirpW6, owned by saphid, doesn't expire). The browser page only says it's private.
  • Access: GET /v1/reports?since=<createdAt> and POST /v1/reports with {"reports": [...]}. Both need the x-frame-control-key header. There are no Lakebed queries or mutations, so nothing else can reach the rows.
  • Key: FRAME_CONTROL_KEY in .env.lakebed.server (git-ignored, synced on deploy) and in the Mac's login Keychain (service frame-control-compat-db, account app-key), where ui/frame_compat_db.py reads it.
  • Duplicates: each report carries a clientId, and a report already stored is skipped, so retries and restores are safe to repeat.
  • Free-plan limits: 1 MiB of data and 16,384 rows per deploy, 1,000 writes a day. A report is about 300 bytes, so roughly 3,000 reports fit.

Backups

scripts/compat-db-backup.sh exports every report through the app key and keeps dated copies in ~/Library/Application Support/Frame Control/compat-db/backups (newest 60). When the data has changed, it also uploads them to Google Drive (the backup folder, folder <drive-folder-id>) with gog. The LaunchAgent frame-compat-backup runs it daily at 03:40; the log is ~/Library/Logs/frame-compat-backup.log. If an export has fewer reports than the last good backup (backups/.last-good), it's kept as refused-*.json, nothing is uploaded, and every later run refuses too until you rerun with --accept-shrink.

Reports that can't be sent (unreadable outbox lines, or ones the server rejects, which it lists by clientId) are never dropped: they move to ~/Library/Application Support/Frame Control/compat-db/compat-outbox.jsonl.rejected, with the reason.

Restore (to this deploy or a new one):

python3 ui/frame_compat_db.py import BACKUP.json   # duplicates are skipped
python3 ui/frame_compat_db.py count

npx lakebed db export dep_dDmcsosVSiFirpW6 --out full.json is a second, owner-only export path through the Lakebed CLI.

Change and deploy

cd compat-db
npx lakebed dev --port 3917                 # local; data resets on restart
npx lakebed deploy                          # updates frame-compat.lakebed.app

To rotate the key: generate a new one, update the Keychain item and .env.lakebed.server, then deploy.