`punktfunk-gamescope` had never been published to the apt registry — not in any release. It was built inside the host job's Ubuntu 24.04 image, where it cannot build: our pin vendors wlroots 0.19.3, which floors `wayland-server` at 1.23.1, and noble ships 1.22.0 (it also lacks libxcb-errors-dev and has only libdisplay-info 0.1.1). Every rung of that path was a `::warning::` returning 0 and the one hard gate ran last by design, so v0.26.0 and v0.27.0 both released with the package missing while docs-site told apt users to install it. The same tags shipped it fine for Arch, Fedora 44 and Bazzite. It now builds in its own job on Debian 13 (ci/gamescope-trixie.Dockerfile), the oldest apt base the tree configures on. One package serves Debian 13 AND Ubuntu 26.04 — measured by installing and running it on both — because the build also vendors libdisplay-info via the new `--extra-fallback` option: linked against the distro copy it demands `libdisplay-info2` on trixie, which Ubuntu 26.04 does not have (it carries libdisplay-info3). The option is opt-in, so the Arch/Fedora/nix outputs are byte-for-byte unchanged. Ubuntu 24.04 gets no gamescope package and cannot — its wayland is too old to run one however built. Debian 13 is now a documented host target. That needed no packaging change at all: the host .deb's glibc-2.39 floor and bundled FFmpeg already made it installable, and it had been working for a long time while docs-site said Debian was unsupported and unverified. Verified by installing: host, web console and plugin runner install, resolve every soname and run. The desktop client stays Ubuntu-26.04-only (built there, floors at `libc6 >= 2.43`; Debian 13 has 2.41). Compositor detection now answers Cinnamon (Mint, LMDE) with the route that works instead of advice that cannot help. Muffin forked from Mutter 3.36: `org.cinnamon.Muffin.ScreenCast` has only RecordMonitor/RecordWindow, never RecordVirtual, and xdg-desktop-portal-xapp implements no ScreenCast — so no value of PUNKTFUNK_COMPOSITOR makes a Cinnamon desktop host a virtual display. The error names headless gamescope, which needs no desktop compositor. The XDG sniff moved into a pure function so those branches are testable; Cinnamon is matched before GNOME, since it is a GNOME derivative and the generic arm would otherwise hand it the Mutter backend (caught by the new test). New `smoke-install` job installs every published package from the registry in pristine ubuntu:24.04, ubuntu:26.04 and debian:trixie images, asserts each binary resolves its libraries and runs, and insists the version served is the one this run built. Nothing in deb.yml had ever installed a package it produced, which is how both of the above survived unnoticed. ⚠ Bootstrap: seed `punktfunk-gamescope-trixie:latest` into the LAN registry once (docker.yml builds it thereafter) or the new job cannot start.
punktfunk-docs
The Punktfunk documentation site: Fumadocs on TanStack Start (Vite + Nitro/bun preset).
Content lives in content/docs/ as .md/.mdx. This site is the source of truth
for the user-facing guides; design rationale lives in the internal punktfunk-planning repo.
API reference
/api renders the host's management REST API as an interactive
Scalar reference (linked from the top nav, the docs
sidebar, and the landing page). It reads public/openapi.json — a
snapshot of the repo's generated spec. Refresh it after a management-API change:
# from the repo root — regenerate the spec, then copy the snapshot in:
cargo run -p punktfunk-host -- openapi > api/openapi.json
cp api/openapi.json docs-site/public/openapi.json
Nothing in CI diffs the two, so the snapshot goes stale silently — that manual cp is the only
thing keeping them in sync. Before publishing docs, check that they match:
diff <(jq -S . api/openapi.json) <(jq -S . docs-site/public/openapi.json)
That should print nothing. Right now it doesn't: the committed snapshot predates the
/api/v1/update/check, /api/v1/update/apply and /api/v1/update/status endpoints, so the
published /api reference is missing the host self-update surface — re-copy it.
Develop
bun install
bun run dev # http://localhost:3001 (docs at /docs)
CI gates every change on bun run build followed by bun run lint (the TypeScript typecheck), in
that order — the build emits the .source typegen the typecheck imports. Run both before you push.
Build & serve
bun run build
bun run start # serves .output/ via Bun
Layout
source.config.ts Fumadocs MDX collection (content/docs)
content/docs/ the docs content (.md/.mdx) + meta.json nav
src/
routes/
__root.tsx RootProvider + html shell
index.tsx landing page
docs/$.tsx catch-all docs renderer (Fumadocs DocsLayout)
api/index.tsx Scalar API reference (reads public/openapi.json)
api/search.ts Orama search endpoint
lib/source.ts Fumadocs loader over the generated collection
lib/layout.shared.tsx shared nav chrome
components/mdx.tsx MDX component map
styles/app.css Tailwind 4 + Fumadocs preset