### Install Debian host with guided installer Source: https://docs.punktfunk.unom.io/docs/debian Runs the guided installer preview, which performs steps 2 to 4 and warns if the GPU driver (step 1) is missing. ```bash curl -fsSL https://punktfunk.unom.io/install.sh | sh ``` -------------------------------- ### Enable user services at boot with loginctl Source: https://docs.punktfunk.unom.io/docs/running-as-a-service Run this command to allow user services to start at boot, equivalent to the guided installer's --linger option. This is the first step for a headless Linux host. ```bash sudo loginctl enable-linger "$USER" ``` -------------------------------- ### Run the guided installer (preview) Source: https://docs.punktfunk.unom.io/docs/arch One-command installer that performs steps 2 to 4 and warns if step 1 is missing. Use this instead of the manual steps below. ```bash curl -fsSL https://punktfunk.unom.io/install.sh | sh ``` -------------------------------- ### Install and wire in the host (Arch repo + setup) Source: https://docs.punktfunk.unom.io/docs/omarchy Adds the Punktfunk Arch repository, installs the required packages, and runs `punktfunk-omarchy setup` to configure the desktop integration. Note that `pacman -Syu ` is aborted by Omarchy; use `pacman -Sy` and `pacman -S` as shown. ```bash curl -fsS https://git.unom.io/api/packages/unom/arch/repository.key | sudo pacman-key --add - sudo pacman-key --lsign-key E0CA04465C99C936E0B0C6510A317015A34DDD69 grep -q '^\[punktfunk\]' /etc/pacman.conf || printf '\n[punktfunk]\nServer = https://git.unom.io/api/packages/unom/arch/$repo/$arch\n' | sudo tee -a /etc/pacman.conf >/dev/null sudo pacman -Sy sudo pacman -S punktfunk-host punktfunk-web punktfunk-scripting punktfunk-client punktfunk-omarchy setup ``` -------------------------------- ### Install and start punktfunk-web console package Source: https://docs.punktfunk.unom.io/docs/troubleshooting-startup Install the console package by name and start it. Use the appropriate package manager for your distribution: apt for Debian/Ubuntu, dnf for Fedora, pacman for Arch. Then enable and start the user service with systemctl. ```bash sudo apt install punktfunk-web # Debian, Ubuntu sudo dnf install punktfunk-web # Fedora sudo pacman -S punktfunk-web # Arch systemctl --user enable --now punktfunk-web ``` -------------------------------- ### Unattended install with setup executable Source: https://docs.punktfunk.unom.io/docs/windows-host Runs the setup silently with default options. Use /MERGETASKS to change defaults, /WEBBIND to set console binding. ```powershell punktfunk-host-setup-.exe /VERYSILENT /SUPPRESSMSGBOXES ``` -------------------------------- ### Uninstall Punktfunk with the guided installer Source: https://docs.punktfunk.unom.io/docs/uninstall The guided installer performs the package and repository removal for apt, dnf, pacman and the Bazzite sysext. Fetch the installer with `curl -fsSLO https://punktfunk.unom.io/install.sh`, then run `sh install.sh --uninstall`. ```bash sh install.sh --uninstall ``` ```bash curl -fsSLO https://punktfunk.unom.io/install.sh ``` -------------------------------- ### Read the install script before running Source: https://docs.punktfunk.unom.io/docs/install Downloads the install script and opens it in less, then runs it. Use this to inspect what the script does before executing. ```bash curl -fsSLO https://punktfunk.unom.io/install.shless install.shsh install.sh ``` -------------------------------- ### Install host packages on RPM systems Source: https://docs.punktfunk.unom.io/docs/gamescope On Fedora, Nobara, and other RPM systems, the host packages are installed with the host. On an older install, run this command to get them. ```bash sudo dnf install punktfunk-gamescope ``` -------------------------------- ### Run web console, runner, and docs site (Bun) Source: https://docs.punktfunk.unom.io/docs/developers/build-from-source Commands to run the web console, build the production server, run the SDK runner, and serve the docs site. All require bun install in the directory first. The console dev server runs on http://localhost:47992 and talks to the host on 127.0.0.1:47990. The docs site runs on http://localhost:3001/docs. PUNKTFUNK_MGMT_URL points the console's dev server at another host. ```bash bun run dev ``` ```bash bun run build, then bun run start ``` ```bash bun src/runner-cli.ts ``` ```bash bun run dev ``` -------------------------------- ### GET /api/v1/native/pair Source: https://docs.punktfunk.unom.io/openapi.json Starts the pairing process for a native client. ```APIDOC ## [GET] /api/v1/native/pair ### Description Initiates a pairing flow for a native client. ### Method GET ### Endpoint /api/v1/native/pair ### Response #### Success Response (200) Pairing initiated #### Error Responses - **401** - Missing or invalid bearer token - **503** - Native host not enabled ``` -------------------------------- ### Build and use client CLI for pairing and streaming Source: https://docs.punktfunk.unom.io/docs/developers/testing Build the client CLI and session, then pair with the host IP (asks for PIN) and launch the stream. Any installed client pairs the same way. ```bash cargo build --release -p punktfunk-cli -p punktfunk-client-session target/release/punktfunk pair # asks for the PIN target/release/punktfunk launch ``` -------------------------------- ### GET /api/v1/store/installed Source: https://docs.punktfunk.unom.io/openapi.json Lists installed plugins with provenance and live registration. ```APIDOC ## [GET] /api/v1/store/installed ### Description List installed plugins. Plugins-dir packages, with provenance and live registration. No provenance record means CLI install (`tier: "cli"`); absence is the answer, not a gap. ### Method GET ### Endpoint /api/v1/store/installed ### Response #### Success Response (200) - **body** (array of InstalledView) - Installed plugin packages #### Response Example ```json [ { "name": "string", "version": "string", "tier": "string" } ] ``` #### Error Responses - **401** - Missing or invalid bearer token - **403** - Not authorized for the plugin token ``` -------------------------------- ### punktfunk://connect example links Source: https://docs.punktfunk.unom.io/docs/presets-and-links Example links that name the host by label, so each asks first. The first connects to a host by label, the second also launches a game, and the third applies a preset. ```text punktfunk://connect/Living%20Room%20PC punktfunk://connect/Living%20Room%20PC?launch=steam:570 punktfunk://connect/Living%20Room%20PC?preset=Work ``` -------------------------------- ### Run host on Linux desktop and pair Source: https://docs.punktfunk.unom.io/docs/developers/testing Start the host inside the session, then open a pairing window that prints the PIN. The client pairs and streams using the built CLI. ```bash cargo run -rp punktfunk-host -- serve cargo run -rp punktfunk-host -- ctl pair arm # prints the PIN ``` -------------------------------- ### GET /api/v1/library/scanners Source: https://docs.punktfunk.unom.io/openapi.json Lists all installed library source plugins and their enable state. ```APIDOC ## [GET] /api/v1/library/scanners ### Description Lists library sources, one row per installed library plugin, with its enable state. Sources default to enabled; disabling hides titles from the next read. The custom store is not a source and is always on. Every row is `origin: "plugin"`. ### Method GET ### Endpoint /api/v1/library/scanners ### Parameters None ### Response #### Success Response (200) - **description**: This host's scanners with their enable state - **schema**: array of ScannerInfo #### Response Example [ { "id": "steam", "enabled": true, "origin": "plugin" } ] #### Error Responses - **401**: Missing or invalid bearer token ``` -------------------------------- ### Minimal C client example Source: https://docs.punktfunk.unom.io/docs/developers/embedding Connects to a host, pulls 600 access units, and quits. Requires a valid host argument and matching ABI version. Generates a temporary identity, sets connection options, and handles keyframe requests. ```c #include #include "punktfunk_core.h" int main(int argc, char **argv) { if (argc < 2 || punktfunk_abi_version() != PUNKTFUNK_ABI_VERSION) return 1; static char cert[4096], key[4096]; /* generate once, then load from storage */ if (punktfunk_generate_identity(cert, sizeof cert, key, sizeof key)) return 1; PunktfunkConnectOpts o = {0}; o.struct_size = sizeof o; o.host = argv[1]; o.port = 9777; o.width = 1920; o.height = 1080; o.refresh_hz = 60; o.video_codecs = PUNKTFUNK_CODEC_HEVC | PUNKTFUNK_CODEC_H264; o.client_cert_pem = cert; o.client_key_pem = key; o.device_name = "My Client"; o.timeout_ms = 180000; /* long enough to click Approve in the console */ uint8_t host_fp[32]; int32_t status = 0; PunktfunkConnection *c = punktfunk_connect_opts(&o, host_fp, &status); if (!c) { fprintf(stderr, "connect: status %d\n", status); return 1; } uint8_t codec = 0; punktfunk_connection_codec(c, &codec); PunktfunkFrame f; uint64_t seen = 0, drops = 0; for (int n = 0; n < 600;) { PunktfunkStatus rc = punktfunk_connection_next_au(c, &f, 20); if (rc == PUNKTFUNK_STATUS_CLOSED) break; if (rc != PUNKTFUNK_STATUS_OK) continue; punktfunk_connection_note_frame_index(c, f.frame_index, NULL); /* feed f.data / f.len to a decoder for `codec` */ punktfunk_connection_frames_dropped(c, &drops); if (drops > seen) { punktfunk_connection_request_keyframe(c); seen = drops; } n++; } punktfunk_connection_disconnect_quit(c); punktfunk_connection_close(c); return 0; } ``` -------------------------------- ### POST /api/v1/profiles/{id}/wake Source: https://docs.punktfunk.unom.io/openapi.json Gets a profile's seat ready. Starts a stopped seat so the next connect lands in it, and answers at once with the seat `starting`; poll `enumerate` until it is `ready`. A light seat starts with its first connect, so on Linux this only answers the row. ```APIDOC ## [POST] /api/v1/profiles/{id}/wake ### Description Get a profile's seat ready. Starts a stopped seat so the next connect lands in it, and answers at once with the seat `starting`; poll `enumerate` until it is `ready`. A light seat starts with its first connect, so on Linux this only answers the row. ### Method POST ### Endpoint /api/v1/profiles/{id}/wake ### Parameters #### Path Parameters - **id** (string) - Required - The profile id ### Response #### Success Response (200) - The profile, its seat `starting` (ProfileAdmin) #### Error Responses - **401** - Missing or invalid bearer token - **404** - No profile with that id - **409** - The profile has no seat of its own - **503** - The seat's host didn't answer ``` -------------------------------- ### Add the Punktfunk repository and install the host Source: https://docs.punktfunk.unom.io/docs/arch Trust the repository key, add the repository to pacman.conf, and install the host, console, and plugin runner. Always use a full -Syu to avoid partial upgrade issues. ```bash curl -fsS https://git.unom.io/api/packages/unom/arch/repository.key | sudo pacman-key --add - sudo pacman-key --lsign-key E0CA04465C99C936E0B0C6510A317015A34DDD69 grep -q '^\[punktfunk\]' /etc/pacman.conf || printf '\n[punktfunk]\nServer = https://git.unom.io/api/packages/unom/arch/$repo/$arch\n' | sudo tee -a /etc/pacman.conf >/dev/null sudo pacman -Syu punktfunk-host punktfunk-web punktfunk-scripting ``` -------------------------------- ### GET /api/v1/emulators Source: https://docs.punktfunk.unom.io/openapi.json Lists all emulators known to the host, including installation status and user-installed copies. ```APIDOC ## GET /api/v1/emulators ### Description Every catalog entry: whether this OS can install it, what hermir installed, and the copies the user installed. A plugin may read this to find a managed copy's program. ### Method GET ### Endpoint /api/v1/emulators ### Response #### Success Response (200) - **EmulatorStatus[]** - One row per catalog emulator #### Error Response (401) - **ApiError** - Missing or invalid bearer token #### Error Response (500) - **ApiError** - The catalog or the prefix could not be read ``` -------------------------------- ### Install the host as a sysext Source: https://docs.punktfunk.unom.io/docs/bazzite Downloads and runs the sysext installer script. Installs the host, console, tray, plugin runner, and the HDR gamescope build. No reboot required. ```bash curl -fsSLO https://git.unom.io/unom/punktfunk/raw/branch/main/packaging/bazzite/punktfunk-sysext.shsudo bash punktfunk-sysext.sh install ``` -------------------------------- ### Held game.launching hook example Source: https://docs.punktfunk.unom.io/docs/automation Example hook that holds the game launch until the command exits or the webhook answers, with a timeout of 20 seconds. The filter matches preset 'Docked'. If the hook times out or fails, the game starts anyway and the log explains why. ```json { "on": "game.launching", "filter": { "preset": "Docked" }, "hold": true, "timeout_s": 20, "run": "/home/me/.config/punktfunk/scripts/tv-profile.sh" } ``` -------------------------------- ### POST /api/v1/emulators/{id}/prepare Source: https://docs.punktfunk.unom.io/openapi.json POST endpoint to prepare an emulator for launch, handling first-run setup, firmware installation, and pad binding. ```APIDOC ## [POST] /api/v1/emulators/{id}/prepare ### Description Prepares an emulator for a launch by answering first-run questions, installing firmware, and binding pads in seat order. Idempotent; each step reports what it did. ### Method POST ### Endpoint /api/v1/emulators/{id}/prepare ### Parameters #### Path Parameters - **id** (string) - Required - The catalog id, like `pcsx2` #### Request Body - **PrepareEmulatorRequest** (object) - Required - The request body schema is defined by the `PrepareEmulatorRequest` component. ### Response #### Success Response (200) - **array** - What each copy's preparation did, items of type `PreparedCopy` #### Error Responses - **400** - A malformed platform, or a firmware folder that isn't one - **401** - Missing or invalid bearer token - **403** - The firmware folder is outside the calling plugin's state directory - **404** - Not in the catalog - **500** - The catalog or the firmware folder could not be read ``` -------------------------------- ### First build: clone, build, and test Source: https://docs.punktfunk.unom.io/docs/developers Run these commands on Ubuntu 26.04 with rustup and the workspace packages. rustup installs the compiler version pinned by rust-toolchain.toml; do not override it or rustfmt will reformat files you never touched. ```bash git clone https://git.unom.io/unom/punktfunk.git && cd punktfunk cargo build --workspace --locked cargo test --workspace --locked ``` -------------------------------- ### KDE desktop setup script Source: https://docs.punktfunk.unom.io/docs/bazzite Run after logging out and back into the Desktop session. Seeds the input grant so the host doesn't wait on a dialog. Only needed for streaming the KDE desktop. ```bash bash /usr/share/punktfunk/bazzite/kde-desktop-setup.sh ```