The LocalService runner can't traverse the interactive user's profile the way the old SYSTEM runner could — so a plugin can no longer read a file an app running as *you* produced (the acute case: the Playnite exporter's library JSON under %APPDATA%). Confirmed on-glass: as LocalService the glob finds nothing and the profile is un-traversable. Add the inverse of plugin-state: <config_dir>\ingest, granted BUILTIN\Users Modify by plugins enable (disable reverts to inherited Users:RX). An interactive-user app drops ingest\<plugin>\… and the de-privileged runner reads it there — the one Users-writable carve-out in the otherwise Users-read-only tree. SDK exports pluginIngestDir(name) to resolve it; on Linux the systemd --user runner owns the config dir so same-user producers write there with no grant. Accepted tradeoff: the inbox is writable by any local user (trusted-single- user model; it feeds only a LocalService runner). Consumers must treat ingest data as lower trust than their own state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Windows host build/deploy scripts
Helper scripts for the Windows host box (the RTX .173 lab box, repo at
C:\Users\Public\punktfunk-native). Run them from the repo root in an elevated PowerShell.
One-time: persist the build environment
powershell -ExecutionPolicy Bypass -File scripts\windows\setup-build-env.ps1
Persists (Machine scope) the vars the host build needs (NVENC itself needs none — its entry
points are runtime-loaded from the driver's nvEncodeAPI64.dll):
| var | value | why |
|---|---|---|
LIBCLANG_PATH |
C:\Program Files\LLVM\bin |
bindgen (libclang.dll) |
CMAKE_POLICY_VERSION_MINIMUM |
3.5 |
audiopus_sys / cmake crates |
FFMPEG_DIR is not set — the --features nvenc build the RTX box uses does not link
libavcodec (that is only the amf-qsv feature). The VS C++ toolchain is loaded per-build via
vcvars64.bat (auto-discovered with vswhere).
Rebuild + redeploy the host service
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-host.ps1
Stops PunktfunkHost, backs up the current binary (punktfunk-host.exe.bak), builds
--release -p punktfunk-host --features nvenc from the current source, then restarts the
service on the new binary — with automatic rollback if the build fails or the new binary
won't start. The service is down only for the build duration.
Web management console
On an installed host (the setup.exe) the console is set up automatically — no manual steps.
The installer bundles the built (self-contained, no-node_modules) .output server + a portable
bun and runs punktfunk-host.exe web setup, which registers the PunktfunkWeb scheduled task
(at boot, as SYSTEM, restart-on-failure) running {app}\web\web-run.cmd →
bun …\.output\server\index.mjs on :47992, opens inbound TCP 47992, and writes the login password to
%ProgramData%\punktfunk\web-password (ACL'd to Administrators + SYSTEM). The mgmt bearer token it
proxies with is the host's own %ProgramData%\punktfunk\mgmt-token. Browse https://<host-ip>:47992
and log in with the password the installer shows on its final page. To change it, edit
web-password and re-run the task: schtasks /run /tn PunktfunkWeb.
Rebuild + restart the console (dev box)
powershell -ExecutionPolicy Bypass -File scripts\windows\build-web.ps1
bun install && bun run build (Nitro noExternals -> a self-contained .output, no
node_modules/.npmrc), then restarts the PunktfunkWeb task and checks :47992/login. Use
this to iterate on the console against an installed host - punktfunk-host.exe web setup (or a
fresh install) is what creates the task in the first place.
Plugin/script runner
powershell -ExecutionPolicy Bypass -File scripts\windows\build-scripting.ps1
powershell -ExecutionPolicy Bypass -File scripts\windows\build-scripting.ps1 -EnableTask
bun install && bun build src/runner-cli.ts --target=bun in sdk\ -> one self-contained
runner-cli.js (effect + the SDK inlined; the operator's plugin import() stays a runtime import,
gated on the same attempt= check CI and the .deb builder use), then lays it out as
<exe-dir>\scripting\runner-cli.js + scripting-run.cmd with the bun runtime at <exe-dir>\bun\bun.exe.
That layout is load-bearing. punktfunk-host plugins add/remove/list forwards package ops to the
runner, and on Windows it resolves the runner relative to the running exe (crates\punktfunk-host\src\plugins.rs).
Since deploy-host.ps1 runs the service out of target\release, a bundle sitting only in the
installed {app} leaves the freshly built exe reporting "the plugin runner isn't installed". The
script deploys next to every host exe it finds - the built one and whatever the PunktfunkHost
service actually runs.
The PunktfunkScripting task is registered disabled (opt-in) by the installer, so the script
stages the bundle but does not silently enable it. Pass -EnableTask on a box you are validating
plugins on (equivalent to punktfunk-host plugins enable).
Rebuild + redeploy everything
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-all.ps1
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-all.ps1 -EnableScriptingTask
Thin wrapper: runs deploy-host.ps1, build-web.ps1 then build-scripting.ps1 in sequence — the
web console and plugin runner are always included, so the host binary and the runner bundle
never drift apart. If the host build/start fails, deploy-host.ps1 rolls itself back and throws,
which stops this script before the later steps run.
Typical flow after pulling new code
git pull
powershell -ExecutionPolicy Bypass -File scripts\windows\deploy-all.ps1