Case Study · Server Ops Tooling
palctl
A REST-native control plane for a Palworld dedicated server that restarts on the symptom, not the clock— it reads the game server's actual memory off the OS and forecasts the leak curve, so it can restart early while the server is empty instead of at the threshold with players mid-session. One engineer, five surfaces over one core.
Why it exists
There are good Palworld managers. This one is different in three specific ways.
Every other Windows GUI drives RCON, which Pocketpair has deprecated. palctl uses the recommended REST API— which also unlocks what RCON simply can't report: server FPS, frame time, uptime, base-camp count, and per-player level, ping, location, and building count.
Palworld's dedicated server leaks memory. The universal advice is “restart it on a timer,” which either kicks people for no reason or leaves the server a slideshow for hours before the timer fires.
palctl reads the server process's actual resident memoryfrom the OS and restarts when it's really bloating — with a countdown, a world save, and a hold-off while players are online. You can't do that from a web panel or a cloud bridge. You have to be on the box — which is also why the Discord bot is self-hosted: your token, your machine, no third party holding your admin password.
Architecture
Two processes, five surfaces, one shared core.
The split is deliberate. The daemon is the manager — wrapped in a Windows service or a systemd unit, it survives reboots and sign-outs. The GUI is a viewer you open when you want it: closing the window manages nothing worse. Everything a user touches — desktop, CLI, web, Discord — drives the same token-gated daemon API, so the four surfaces can never disagree about what the server is doing.
A headless process running five supervised async loops under one asyncio.gather — poll/diff, memory watchdog, scheduler, leak forecaster, update-check — plus the Discord bot and the control API. One escaped exception is logged and contained; the other loops keep running instead of the whole daemon going down.
Dashboard (FPS, frame time, a memory sparkline with the watchdog limit drawn in, uptime, in-game day, base camps), Players with kick/ban, a Console, and a typed, grouped Settings editor over the one-line OptionSettings blob. Console actions run on a worker thread, so a slow service call can’t freeze the window.
status, players, events, start/stop/restart, save, backup/backups/restore, update, announce, kick/ban/unban, and ui — all talking to the daemon’s token-gated localhost API. Because it rides the same API as everything else, it works over ssh, in cron, and on the headless box the desktop GUI can’t serve. palctl kick zoe resolves the name to a user ID for you.
One self-contained page the daemon serves on 127.0.0.1 only — live status, players, the memory sparkline, events, and the full control set with confirm-gated restore. The per-user token rides the URL fragment, so it never leaves the browser. Remote access goes over an ssh tunnel or Tailscale, never an exposed port.
13 slash commands plus join/leave, level-up, watchdog, up/down, and update-available notifications, an optional auto-refreshing status message, and a welcome line. Your token, your machine — no third-party bridge holding your admin password. First-connect retry, and sends are queued so a Discord rate limit can’t stall polling or the watchdog.
The ini parser, backups, session/metrics tracking (SQLite), scheduler, path detection, SteamCMD orchestration, the operation lock, the watchdog hold-off, and the leak forecaster are all OS-agnostic and unit-tested on any OS. Only service control, the downloads, and the GUI need Windows — which is why the same daemon runs headless on Linux.
The hard parts
The recurring theme is restraint: an auto-restarter that misfires is worse than none.
By the numbers
Under the hood
The stack, by layer.
What it won't do — and can't
Scoped to what the API actually supports, and honest about the rest.
The installer isn't code-signed yet, so Windows SmartScreen shows a one-time prompt — every release ships a SHA256SUMS.txt so the download can be verified against what CI built. A wingetlisting and free code-signing via SignPath's open-source program are on the roadmap.