The console's Interface tab still offered an enable/disable switch for the game library, left over from when the feature was experimental. Removing it turned out to be the opposite of a one-line deletion. The console never read the setting. Its row rendered a value and flipped a bool, and every library affordance in the console — the home Y hint, the Y press, the `--browse <host>` deep link — is gated on PAIRING and nothing else. So the row showed "Game library · Off" while the same shell handed you the library on Y. The docs already said as much. What the flag actually gated was the other two desktop shells, GTK and WinUI, which hide "Browse library…" unless it is on — and its stored default is `false`. So deleting only the console row would have left every user who never found this switch with a hidden library in the desktop apps, while removing the last place in Gaming Mode where it could be turned on. The letter of the request, and the exact opposite of its intent. So the field goes, not just the row: `trust::Settings::library_enabled` and all four reads of it. No migration code and no serde alias is needed, and that is by construction rather than by luck — `Settings` is `#[serde(default)]` with a `#[serde(flatten)] extra` map, so a stored `"library_enabled": false` parses into `extra`, round-trips untouched, and is ignored. Everyone who had it off now has the library, and a downgraded binary still finds its old value under the same key. A test pins that contract, since it is the whole reason this is safe. At the two GTK and two WinUI menu sites the flag is replaced by the PAIRING predicate rather than dropped for an unconditional item. The library fetch authenticates with the paired identity, and GTK's saved cards include trusted-but- unpaired hosts, so an unconditional menu entry would promote a documented latent bug — a fetch that cannot authenticate — into the default experience on every install. Apple and Android keep their own independent toggles for now, deliberately: both already default TRUE, so nobody there loses anything by our not touching them, and their removal is a follow-up rather than a rushed edit across two more UI frameworks in this change. VERIFICATION. The console and GTK legs are gate-green in the Linux container (clippy `-D warnings`, a plain non-test build, and the test suites), and the GTK leg needed that plain build: deleting the read orphaned the struct field that held the settings store, which `--all-targets` hides and a shipping build raises. The WinUI edits are READ-VERIFIED ONLY — `punktfunk-client-windows` is `cfg(windows)` and compiles on neither the Mac nor the Linux container, so they are unproven until a Windows runner sees them.
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