Field report, Nobara + 0.20.0: switching into Game Mode mid-stream disconnects the client and the box never lights up again. His journal has the whole mechanism, ten seconds apart: 12:34:18.9 freed Steam: stopped the display manager for this stream 12:34:29.0 systemd[1685]: Stopping punktfunk-host.service Stopping the display manager ends the user's last login session. The packaged host is a `systemd --user` unit, so logind then stops user@1000.service once UserStopDelaySec elapses — 10s by default on Nobara — and takes the host with it. The stream dies, the scheduled restore never runs, and the display manager stays down with nothing left to restart it: a black box that needs a VT to recover. Exactly the two symptoms reported, and the intermittency is just whether an active Gaming Mode session was there to trigger the takeover at all. It never showed on the repro VM because lingering was enabled there for the earlier sessionless tests (`Linger=yes` — confirmed on the VM today), which is precisely the thing that breaks the dependency: logind keeps the user manager alive with no session. Our KDE/GNOME/Arch setup guides already ask for it; his box, following the KDE route, did not have it. So the takeover now ensures lingering BEFORE it touches the display manager: `loginctl enable-linger` directly (allow_active in logind's own policy — verified working unprivileged on Nobara), else the packaged helper gains a `linger` verb that enables it for PKEXEC_UID alone, never a caller-named user. If neither works the takeover is refused with an actionable error and managed degrades to attach — mirroring the box's own session is strictly better than a screen that needs a VT. Hosts that cannot be reached this way (root, a system unit) skip the check: the cgroup test is a pure `cgroup_under_user_manager` with a unit test, matched against the real shapes on a Nobara box (`user@1000.service/app.slice/...` vs a `session-N.scope`). Also documents the requirement in the gamescope guide's Nobara section. Checked on Linux: clippy -D warnings, 78 tests, rustfmt; helper verified with `sh -n`, and the linger enable/disable round-trip run live on the Nobara VM.
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
Develop
bun install
bun run dev # http://localhost:3001 (docs at /docs)
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