Files
enricobuehlerandClaude Opus 5 8f9e451395
ci / web (pull_request) Successful in 1m3s
ci / bun-nix (pull_request) Successful in 41s
ci / rust-arm64 (pull_request) Successful in 1m58s
ci / docs-drift (pull_request) Failing after 47s
ci / docs-site (pull_request) Successful in 1m48s
android / android (pull_request) Successful in 7m26s
ci / rust (pull_request) Failing after 8m7s
apple / swift (pull_request) Successful in 2m4s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
docs: one home per fact — IA rules, CI drift gates, and READMEs stop restating the docs
WP0+WP1 of the docs-and-onboarding overhaul (punktfunk-planning
design/docs-and-onboarding-overhaul.md):

- CONTRIBUTING.md + docs-site/README.md state the ownership rule (docs-site
  owns user-facing facts; READMEs keep rationale + pointers; the website
  deep-links) and the get-started vs reference audience split.
- ci.yml gains a docs-drift job (scripts/ci/check-docs-drift.sh +
  check-docs-links.sh): the OpenAPI snapshot must be a byte copy of
  api/openapi.json, PUNKTFUNK_* vars the docs mention must exist in the tree,
  the undocumented-var set is ratcheted against a named baseline file,
  host-cli.md commands must exist in the host crate, data/platforms.json must
  parse, and internal doc/README links must resolve. The rust job additionally
  regenerates the spec from the built host and diffs it — closing the 'not
  gated' hole CONTRIBUTING itself confessed to. All seven gates were shown to
  FAIL on planted violations before landing (the gate-of-the-gate rule).
- data/platforms.json: single source for install commands, repo URLs, ports
  and the Sunshine/Apollo/Vibeshine conflict facts — the docs rewrite (WP2),
  website download page (WP3) and guided installer (WP4) consume it.
- READMEs (root, bazzite, debian, arch, rpm, flatpak) stop restating docs
  walkthroughs (net -444 lines); facts whose only home a README was (the
  ds_inhibit SELinux storm, the ffmpeg-libs weak dep, the pacman.conf
  double-append) stay put, marked for the WP2 migration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 16:39:39 +02:00
..

punktfunk-host — Debian/Ubuntu package (apt)

Which distros the published packages install on — measured by installing them, not inferred from the build image (scripts/ci/deb-install-smoke.sh asserts this on every run):

Ubuntu 24.04 Ubuntu 26.04 Debian 13 Debian 12
punktfunk-host glibc 2.36 < 2.39
punktfunk-web / punktfunk-scripting
punktfunk-gamescope wayland 1.22
punktfunk-client libc6 >= 2.43 libc6 >= 2.43

Debian 13 is a supported host target (docs); the client is the one gap, since it is built on 26.04 and floors at that release's glibc.

punktfunk-host is published as a .deb to Gitea's Debian package registry in the public unom org, so the Ubuntu hosts update with plain apt. CI (.gitea/workflows/deb.yml) builds and publishes on every push to main (a rolling <next-minor>~ciN.g<sha> build — the base is derived from the latest stable tag by scripts/ci/pf-version.sh — to the canary apt distribution) and on vX.Y.Z tags (a clean X.Y.Z to the stable distribution, plus attached to the unified Gitea Release). The two are separate apt distributions, so a stable box never jumps to a canary build — see Release Channels. The repo line below subscribes to stable; swap stablecanary for the latest main builds.

The same workflow also publishes punktfunk-web (the browser management console — pairing + status) and punktfunk-client (the native GTK4/libadwaita Linux client). punktfunk-host Recommends punktfunk-web, so a default apt install punktfunk-host pulls the console too (alongside the udev/sysctl bits) unless you've disabled weak deps; punktfunk-client is independent — install it on the box you stream to. (punktfunk-probe is the headless reference/test tool, not packaged here.)

Package layout mirrors the Fedora RPM (../rpm/punktfunk.spec): the host binary, the /dev/uinput udev rule, the systemd user unit, headless session helpers, the example config, and the OpenAPI doc. Runtime Depends are computed by dpkg-shlibdeps from the binary itself. The NVIDIA driver (libnvidia-encode / libEGL_nvidia / libcuda) is not a dependency — it's installed out of band, like on the RPM side.

Ubuntu 24.04 LTS (and why it needs a special build)

punktfunk-host needs FFmpeg 8 (libavcodec62), but Ubuntu 24.04 LTS ships FFmpeg 6.1 (libavcodec60). So a host .deb built the obvious way — on the same Ubuntu 26.04 image as the client (ci/rust-ci.Dockerfile) — declares Depends: libavcodec62, … and a glibc-2.41 floor that 24.04's apt can't satisfy ("the required packages are too recent"). To fix that, the host .deb is instead built on an Ubuntu 24.04 image (ci/rust-ci-noble.Dockerfile) that carries a from-source FFmpeg 8, and that FFmpeg is bundled into the package (build-deb.sh BUNDLE_FFMPEG=1 → the libav* land in /usr/lib/punktfunk-host, the binary's rpath points there, and the libav* sonames are dropped from Depends). The result is one host .deb that installs on Ubuntu 24.04 LTS through 26.04 (glibc floor 2.39; no distro-FFmpeg dependency). The client/web/scripting .debs still build on 26.04 (the native client needs SDL3 / GTK4 ≥ 4.20, absent on 24.04) — install the client on the box you stream to, which is independent of the host's distro.

punktfunk-gamescope is built on Debian 13, not Ubuntu

The patched gamescope has its own job (build-publish-gamescope) in a Debian 13 image (ci/gamescope-trixie.Dockerfile), and that is not a preference — it is the only apt distro the tree configures on. Built in the noble host image, as it was until 2026-08, it failed every single run:

wlroots| Dependency wayland-server found: NO found 1.22.0 but need: '>=1.23.1'
subprojects/wlroots/meson.build:96:17: ERROR: Dependency 'wayland-server' is required but not found

Our pin vendors wlroots 0.19.3, which floors wayland-server at 1.23.1; noble ships 1.22.0 (and has no libxcb-errors-dev, and only libdisplay-info 0.1.1). Because every rung of that path was a ::warning:: returning 0, v0.26.0 and v0.27.0 both shipped with no gamescope .deb while the release notes and docs-site said it was apt-installable. Debian 13 has wayland 1.23.1 exactly — the oldest apt base that works.

Two things make the one package serve both Debian 13 and Ubuntu 26.04:

  • --extra-fallback libdisplay-info (see packaging/gamescope/build-punktfunk-gamescope.sh). Linked against the distro copy, the package picks up Depends: libdisplay-info2 (>= 0.2.0) on trixie — and Ubuntu 26.04 carries libdisplay-info 3 (0.3.0), so apt refuses it there. gamescope vendors the library as a submodule, so the vendored build drops the dependency. Same reasoning the script already applies to wlroots: a binary we ship must not follow the build host's shared libraries.
  • The static C++ runtime the build script already forces, so libstdc++ never appears in NEEDED. The binary asks only for GLIBC_2.38.

Ubuntu 24.04 gets no gamescope package and cannot: the wayland floor is a runtime one too.

Install on a host

The user-facing walkthrough — repo key, sources line, apt install, first-run setup — lives on the docs pages (Debian / Ubuntu), stated once so it can't drift (see "Where facts live" in CONTRIBUTING.md). Packager-relevant: the registry is public (no apt auth — only the repo's signing key), and stable / canary are separate apt distributions, so a stable box never jumps to a canary build.

Firewall

Debian ships no firewall and Ubuntu's ufw is installed-but-inactive by default, so out of the box there is nothing to open. The package ships openers for both — ufw profiles at /etc/ufw/applications.d/punktfunk and firewalld service definitions at /usr/lib/firewalld/services/ (neither auto-enabled). The commands, per-port breakdown and the data-plane hole-punch behavior are documented once: Debian for the openers, port facts in data/platforms.json and on Moonlight, hole-punch mechanics in Troubleshooting.

Updates

sudo apt update && sudo apt upgrade        # picks up the newest published build
systemctl --user restart punktfunk-host    # if the unit was already running

Build a .deb locally

VERSION=0.0.1 bash packaging/debian/build-deb.sh   # -> dist/punktfunk-host_0.0.1_amd64.deb

Needs dpkg-dev (dpkg-shlibdeps, dpkg-deb). It builds the release binary first if missing. Building on a GPU box is fine — the NVIDIA driver lib is filtered out either way.

That plain invocation hard-depends on the build box's system FFmpeg, so it only installs on a box with the same libav* soname. For the universal package CI ships (installs on 24.04 LTS → 26.04), build it in the noble image with FFmpeg bundled:

docker build -f ci/rust-ci-noble.Dockerfile -t pf-noble ci
docker run --rm -v "$PWD:/src" -w /src pf-noble \
  bash -lc 'VERSION=0.0.1 BUNDLE_FFMPEG=1 bash packaging/debian/build-deb.sh'

BUNDLE_FFMPEG=1 needs patchelf and an FFmpeg install at FFMPEG_PREFIX (default /opt/ffmpeg, which the noble image provides).

The arm64 client .deb

The client also ships for arm64 (punktfunk-client_<version>_arm64.deb, published to the same apt distribution — the registry keys pool entries by architecture, so an arm64 box needs no extra configuration). There is no arm64 host package: the Linux host encodes with NVENC/QSV/AMF, all x86.

It is cross-compiled on an ordinary amd64 machine in ci/rust-ci-arm64cross.Dockerfile — the rust-ci toolchain plus an Ubuntu ports arm64 multiarch sysroot. No arm64 runner is involved:

docker build -f ci/rust-ci-arm64cross.Dockerfile -t pf-arm64cross .   # repo-root context
docker run --rm -v "$PWD:/w" -w /w pf-arm64cross \
  bash -lc 'VERSION=0.0.1 ARCH=arm64 TARGET=aarch64-unknown-linux-gnu \
              bash packaging/debian/build-client-deb.sh'

TARGET moves the binaries to target/<triple>/release; ARCH sets the package's Architecture: field. Set both — one without the other builds an amd64 binary into a package labelled arm64, or vice versa. dpkg-shlibdeps reads the arm64 sonames straight out of the multiarch sysroot, so Depends: comes out right with no manual list.