Systems Thinking Data Salon

Building a Home Control Plane From Parts

How a chat relay and an old laptop became central control for the house.

Jean Haley — Site Reliability Engineer  ·  a headless AI agent on a dedicated laptop

Step one: define the MVP bounds

Detach a work session from my physical location and device.

How I modeled it, and the principle underneath

Model it first, and give every part its own concern.

Chat clientany device Backend server Message relay Claude Codethe model backend
Chat client → backend server → message relay → Claude Code backend.
separate concerns clean interfaces extensible maintainable scalable

Claude Code's channels (beta)

The relay-shim uses a channel to talk to a running session, both directions.

Chat clientTelegram · Discord relayd relay-shimthe channel Claude Codeone live session INBOUND — message in channel: inject as notification channel: reply tool last-mile send to the chat app OUTBOUND — reply out
Same channel, both directions. relayd bridges the chat client on each end.
relay delivers a message channel injects it model reads & decides reply tool sends back

The first implementation

relayd — day one.

TelegramDM relayd commands?/help /rate /pause budget / rate gatecircuit breaker Claude CodeSonnet the reply retraces the path back to the user
A Telegram router for a Claude Code backend: a commands gate, a budget/rate gate, and nothing else yet.

The first authentication layer

Nothing reaches the model until it's approved or denied.

Message+ sender ID relay gateapproved? denied? unknown? approved Model backend unknown → queued admin approvesor denies
Every message is gated at the relay before the model sees anything.

Accidentally multi-tenanted

Out of nowhere, several people were using one Claude session at once.

An honest warning

This is not safe.

I only share this space with close friends I've known and trusted for years. The model is remarkably good at knowing what lines not to cross. But leaning on a model for security will eventually break. Every model, given enough time, is susceptible to social engineering.

Gate a stochastic system behind a deterministic boundary. Don't run an instance like this without understanding that risk.

Giving it a little agency

I was missing a way for the model to act on its own.

Schedulercron · one-off tasks wakes at a set time Running modelworks the task, then continues the model can schedule itself
I schedule events and one-off tasks. The model can also schedule itself.

The machine, its senses, and a nervous system

I looped our alerts back to the model, so that it can heal itself.

metric / sensorCPU · memory · disk Grafana alert relay Modelinvestigates · fixesthen tells me
Grafana alerts through the relay become something like a nervous system. The model can self-heal.

The whole system, now

A persistent Claude Code session running on its own computer.

Chat clientsTelegram · Discord relaydgate · auth · budget RODIN · THINKPAD T480 — THE VESSEL Claude Codeone live session Schedulercron · self-wake ObservabilityPrometheus · Loki · Grafana k3s clustermost services SensorsBLE · network · router Tailscale — single controlled egress · WireGuard
Chat in through relayd; one session at the center; scheduler, observability, k3s and sensors around it; everything behind one Tailscale egress.

Everything it runs

Tools it's built and hosts, all over the tailnet.

Web tools, base

VS Code/
Daily newspaper/news
Email search/search
Grafana dashboards/grafana
Qdrant browser/qdrant
TV remote/tv
Glucose tracker/glucose
Guided tour/tour
This deck/talk
Email workspace (TUI)ssh -p 2229
BBS (gobbs)ssh -p 2227

Speaker notes

N: notes · P: pop out slide