jackmhny 04ef2a0d74
Some checks failed
ci / verify (push) Has been cancelled
feat: build CouchOS Melee appliance
2026-08-03 02:52:28 +02:00
2026-08-03 02:52:28 +02:00
2026-08-03 02:52:28 +02:00
2026-08-03 02:52:28 +02:00
2026-08-03 02:52:28 +02:00

CouchOS

CouchOS targets the couchos laptop: a Debian 13 living-room Melee appliance for the couch user. This repository is being built remotely from a separate workstation. couchd is intended to bind only to Tailnet IP 100.64.0.15, and the dashboard is intended to be served same-origin at couch.mhny.dev.

As of Monday, August 3, 2026:

  • The main root-side blocker on the target laptop is still interactive sudo access. The repo contains the setup and verification logic, but it has not claimed to apply privileged changes from this remote implementation workstation.
  • The TV currently advertises only 1920x1080@60.00 on HDMI-1. There is no verified 120 Hz mode to automate today.
  • The Xbox controller is known at C8:3F:26:12:69:7B. It is presently paired and connected, but it is not yet trusted under jackmhny.
  • An HDMI PulseAudio sink is currently absent on the target laptop, so HDMI sink selection remains deferred until PulseAudio exposes one.
  • Dashboard DNS already exists externally. This repo covers the dashboard files and Caddy snippet, not DNS creation.

Layout

  • src/couchd/: stdlib-only Python control daemon, launcher, discovery, and status probes
  • setup.sh: idempotent root/couch setup with --dry-run and PASS/FAIL --check
  • scripts/check.sh: local/CI verification entrypoint from a clean checkout
  • scripts/preflight.sh: deployment evidence checks plus reboot/soak evidence capture
  • scripts/install_slippi.sh: official launcher installer with checksum fail-closed behavior
  • scripts/backup_restore.sh: scoped backup/restore without launcher account/session data, ROMs, replays, or tokens
  • systemd/systemd-user/: user units installed under /etc/systemd/user and started from the couch graphical session
  • dashboard/: same-origin static UI
  • config/: non-secret config templates plus LightDM/logind/Caddy config

Automated Vs Manual

Automated by this repo:

  • Stable install under /home/couch/couchos
  • LightDM autologin config for couch into XFCE
  • logind lid-ignore on AC power
  • couchd and display/audio user units bound to the couch graphical session via XFCE autostart entries
  • Runtime config generation with the real couch UID and runtime dir
  • First-apply bearer token generation with mode 0600, preserving any existing token
  • XFCE compositing off, blanking/suspend off, lock/screensaver off, notification daemon/update-notifier autostart suppressed
  • Tailnet-only daemon binding, constant-time bearer auth, strict route allowlist, safe process adoption/stop logic
  • Dashboard static assets and Caddy reverse-proxy snippet with server-side bearer injection

Still manual or operator-observed:

  • Installing the privileged changes on the actual laptop
  • Setting a real ISO path under /home/couch
  • Confirming actual launcher fallback entries discovered on the machine
  • First-run Slippi UI steps and controller profile mapping
  • Confirming autologin/session behavior, five reboot controller behavior, and 30-minute gameplay/FPS observations

couchd

Exposed routes:

  • GET /status
  • POST /launch/melee
  • POST /open/slippi
  • POST /stop

Implemented constraints:

  • Tailscale IPv4 bind only; loopback and 0.0.0.0 are rejected
  • Constant-time bearer token comparison
  • Exact route allowlist with safe query-string stripping
  • Nonempty action request bodies rejected
  • Request body size capped
  • Expected config/discovery/launch failures converted to JSON 409; unexpected action failures return JSON 503
  • State persisted atomically and corrupt/stale state tolerated
  • Existing couch-owned Slippi/Dolphin processes under allowed roots can be adopted to prevent duplicates
  • Stop logic verifies PID identity and allowed roots before sending TERM/KILL
  • Display status reports the active starred refresh, for example HDMI-1 1920x1080@60.00
  • Launcher and Dolphin version probes degrade safely on missing commands or timeouts

Setup

Root/system phase:

sudo ./setup.sh --phase root --dry-run
sudo ./setup.sh --phase root

Couch/user phase:

sudo ./setup.sh --phase couch --dry-run
sudo ./setup.sh --phase couch

Notes:

  • setup.sh does not install Caddy. The deployed site can stay behind an existing Caddy basicauth block or another external public auth layer such as Cloudflare Access.
  • The generated runtime config keeps iso_path, launcher_shortcut, and xbox_bluetooth_address null unless the operator supplies real values.
  • Launcher fallback is not invented. If direct Dolphin launch is unavailable, configure only a discovered gtk-launch desktop entry that the target machine actually exposes.
  • On first apply, setup.sh generates a cryptographically random bearer token at /home/couch/.config/couchd/token with mode 0600 and leaves an existing token untouched.
  • To synchronize that token with Heavy Caddy without printing or committing it, read it locally on the laptop as root and copy the same value into the Caddy environment source used by the deployed site, then reload Caddy after updating that secret.

Dashboard And Caddy

Use config/caddy/couch.mhny.dev.caddy as the site snippet.

What this snippet assumes:

  • An existing Caddy basicauth block, Cloudflare Access, or equivalent public auth already exists outside this repo
  • The static dashboard is deployed at /var/www/couchos
  • Caddy injects Authorization: Bearer {env.COUCHD_BEARER_TOKEN} server-side before proxying /api/* to 100.64.0.15:8765

Verification

Project checks:

./scripts/check.sh

Deployment checks:

./setup.sh --check
./scripts/preflight.sh quick
./scripts/preflight.sh five-reboots
./scripts/preflight.sh soak-30m-start
./scripts/preflight.sh soak-30m-finish

five-reboots and soak mode now record real boot IDs, controller snapshots, and honest operator-observation placeholders instead of just incrementing counters.

Recovery

  • ./scripts/backup_restore.sh backup [archive.tar.gz]
  • ./scripts/backup_restore.sh restore <archive.tar.gz>

Backups are mode 0600 and intentionally exclude:

  • launcher account/session data
  • replays
  • ROMs
  • bearer tokens

External References

Description
Reliable Debian living-room Slippi Melee appliance
Readme 76 KiB
Languages
Python 59.9%
Shell 35.7%
CSS 1.9%
JavaScript 1.3%
HTML 1.2%