Built with Claude Code. See how these projects were built for what that means in practice.
A note on what this page leaves out. hell.mesh is the piece of software that controls the machines in my house — turning them on, shutting them down, reading their sensors, moving files between them. Publishing its addressing, routing, key layout or access-control design would be handing out a map with the doors marked. So this write-up covers what it does and why it is built the way it is, and says nothing about hostnames, addresses, routes, keys or the guards around them. Where it gets vague, that is on purpose rather than an oversight.
What it is
A terminal control panel for a small mesh of machines: a workstation, a headless box with a GPU, a very low-power node that is always on, and a laptop that comes and goes. It is one Go binary with zero third-party dependencies, deployed to every machine in the mesh.
Open it and you get a live panel: which machines are up, which services are running on them, what their CPU, GPU and memory are doing right now. From there you can power machines on or off, browse and move files between them, launch my coding agent, or drop into a dedicated panel for the game server.
It also runs headless. There is a one-shot plain-text status mode for scripts, and a mode that emits one machine's hardware state as a single line of JSON so other tools can consume it.
The ideas that matter
Everything is data, not branches. Machines, services and the dependencies between them are values in a config file, not code paths. Adding a service is a struct literal; adding a dependency is one edge. Nothing in the poller or the renderer knows that any particular machine exists. This sounds like ordinary good practice, but it is the single decision that has paid off most — every feature since has been "add a row to the data" rather than "add a case to the switch".
Never invent a state. This is the rule I am most attached to. Off and unreachable are different things and are never collapsed into one. A service on an unreachable machine is "unknown", not "down". Where the panel genuinely cannot see something from where it is running, it says so in as many words rather than showing a plausible default. A monitor that guesses is worse than one that admits ignorance, because you learn to trust it and then it lies to you once.
Reading and acting take different paths. Gathering telemetry and performing a power action are routed differently, because the safety guards live on one path and not the other. Sending a shutdown down the reading path would skip every "is this machine busy right now" check. That was a real bug, and it was caught by a test rather than by a dark screen.
Destructive actions show their work. Anything that powers a machine down
resolves to an exact command, displays it, and requires a specific named keypress
to confirm. No y/n on a paraphrase of what is about to happen.
Colour means state and nothing else. One column carries colour; everything else is dim or default. When everything is colourful, colour stops being information.
The game-server panel
The most recent addition, and the first feature built on the extension recipe the project's own docs prescribe — proof that the recipe was real rather than aspirational.
It manages a Valheim server: start, stop, restart, and editing the three access lists the game maintains. A few decisions in it are worth pulling out, because they generalise well beyond a game server.
Power controls are rows, not just hotkeys, and all three always render in a fixed order. A button that appeared and disappeared as the server changed state would shift the list under your cursor at exactly the moment you were clicking. The unavailable one greys out and explains why it is unavailable, rather than vanishing — a control that disappears makes you wonder whether you imagined it.
An empty allowlist means everyone may join, not nobody. So it renders as
off rather than as 0. Inverting that is the most dangerous misreading
available on that screen, and a bare zero invites it.
Writes are atomic, and encoded in transit. The list files are read and written in place, because the server rereads them and a shadow copy that disagreed would be worse than having no panel at all. A truncated write would silently drop every admin. Encoding the payload is what stops a player nickname containing a space, an apostrophe or a semicolon from being interpreted by anything between the panel and the file.
Deliberately not built: kicking or banning a currently connected player. The game has no remote console, so that would mean writing to the server process's standard input, which the service does not keep open. Banning and restarting is the honest path, and the panel does not pretend to offer more than it can do.
Traps I would rather not rediscover
A remote terminal here reports 80 columns. The first version of the panel's header art was a 52-column side panel that needed 132 columns total. It was correctly hidden every single time, which looked exactly like a rendering bug. Anything laid out side-by-side has to degrade to hidden below its minimum width, or it will be invisible on the terminal actually in use and read as broken.
A successful suspend kills the connection carrying it. The error is the success signal. You cannot trust the exit code; you have to re-poll and see what actually happened.
A shell script of [ -f x ] && echo lines exits with the status of the last
test. One probe returned perfect data and reported failure, because an optional
file legitimately does not exist until first use — so the final guard exited
non-zero and the whole probe was treated as failed, with the correctly-parsed
data displayed as the error message. Probe scripts now end with an explicit
success.
Ask a service manager the wrong scope and it says "not found", which parses as "inactive" and draws as a stopped server that is in fact serving players right now. Scope is carried as data per service; it is never hardcoded.
The machine you are sitting on knew least about itself. The local path only checked network ports, so a local service without a port reported "no probe from here" — on the very box doing the reporting.
A confirm prompt whose first option does nothing reads as a broken panel. The shutdown prompt offered an unimplemented action at the top and demoted the real shutdown to the second key — so the obvious keypress did nothing, and the key that reads as "no" was the one that actually powered the machine off. It got reported as "the poweroff command doesn't work", and every layer underneath it was fine. Now the affirmative key always acts, cancel always cancels, and anything unimplemented is a dim note rather than an option wearing a keybinding.
Verify a deploy by hash, not by "I ran the copy command." Several bugs in one session looked like logic faults and were stale binaries.
Automated terminal testing needs a real pty that holds its input open. Piping into the panel closes standard input, and the resulting end-of-file storm drove the cursor to the bottom of the screen — which looked precisely like a cursor-placement bug and got chased as one. The unit test passed, the panel disagreed, and the panel was right.
Known open
Push-from-local in the file browser is keyed but not implemented; the key says so rather than silently doing nothing. Unattended wake-from-sleep is unproven — one machine suspends correctly but the wake has never been verified without a human in the room. One machine still needs inbound access configured from the others. Repointing a dependency before a shutdown is not wired up yet, and — per the lesson above — the prompt now says so as a note rather than offering it as a choice you cannot actually make.
Status
Working, in daily use, 53 tests green. Written up here at arm's length on purpose; the interesting engineering is in the design ideas above rather than in the addressing, and the addressing is the part that stays home.