Agents talk to each other over a custom WebSocket bridge — with leader election and a Telegram voice bridge — so I can run every machine through one elected leader. It spans two architectures, Linux and macOS, with supervisors keeping it fault-tolerant, and it pages me when it hits something it can't resolve.
My homelab used to be one server with a pile of containers on it. Now it's a small fleet — addressable units I can work on independently, moving workloads between them as a project's scope changes.
The fabric is tied together with a Tailscale mesh for end-to-end encryption between every node, and I drop into tmux when I need to focus on one part of the system. The machines range in size: small cloud VPS, a 16-core 128 GB x86 Linux box, an M4 Max with 128 GB for local inference, and hourly RunPod rentals when a job needs more muscle than I own.
Messages have queues, supervisors that hold response times to account, and leader election to resolve contention — all of it there to manage context across the variety of complex problems each project throws at it.
.knowledge/ points straight into the same store the agents read.A Claude Code agent is an isolated process with a small context window. For a handful of them to act like one team — a lead delegating to PMs and coders across machines — they have to find each other, message reliably, and never step on each other's identity. The bridge is the two-layer Go system that makes that work.
There's one hub, a WebSocket router at ws://amazon.home.arpa:8991 that also keeps the registry of live sessions. Next to each agent runs a small bridge MCP server that hands the model the hub as tools it calls directly — register, send, get_messages, ack, status, list_peers, hub_status, leader_status. Every agent is name@machine and queues are per-machine, so the namespace stays human-readable on top of a distributed fabric.
claim_role only succeeds if no live lease exists. Lease generations let me tell a renewal (same generation) from a real handover (primary_changed) — the same shape as etcd or ZooKeeper, just hand-rolled for a fleet of agents.ack / status semantics, so a sender can confirm a peer actually got a message — not just that it left."The COO role is a lease, not a title. If the agent holding it stops sending heartbeats for sixty seconds, the lease expires and someone else can take over — but only on the one machine the code allows to hold it."
I wanted to keep a project moving even when I'm away from my computer — commuting, or out at the gym taking a break. The relay is a persistently managed, bidirectional connection to Telegram: agents can reach me when they need to unblock work or diagnose an issue, and I can answer back.
When I can't type, I dictate. Voice notes run through a local Whisper service — no cloud STT vendor involved — and the transcribed text goes over the relay to the right agent. Access controls sit in front so nothing reaches the bridge that shouldn't.
Every message over the bridge is watched for a response. An agent that doesn't answer is surfaced as an error in Telegram so I can act on it, common outages get escalated to me immediately, and automatic nudges try to clear the usual "stuck" behavior before it ever reaches me.
"I don't just send a message — I expect a response, and the whole system is built around that."
This is the least glamorous part, and the one that actually matters: keeping all of it up on its own, across two operating systems that don't agree on much.
Supervision has to work on both. Linux runs systemd, the Mac runs launchd, and a per-agent supervisor restarts crashed agents and wedged hubs under one shared model. The rule I learned the hard way: a supervisor must never evict a session I'm actively attached to. It only kills and recreates a pane when the process is genuinely dead — not when I'm sitting in it.
beast and daemon-managed. The fallback chain runs local Qwen → local Gemma → cloud Claude, so no single machine is a hard dependency and a provider outage doesn't stop me.state.md source-of-truth on every fresh boot — they don't start from zero.claude -p pass to merge duplicates, checks the result against seven validations, swaps it in atomically, and Telegrams me a one-line PASS/FAIL so I know it ran.These started as a handful of interests — data processing, scheduling, and hosting private video to support my dancing hobby. I use the sites every day, so I expect the infrastructure to keep them running 24/7: not clumsy hobby projects, but something that holds up as well as any SaaS service overlapping the same use cases. As more of the critical features have landed, I've started wiring in cross-dependencies — the dance uploader can reach out to swing-analytics to suggest possible instructors in a video.
Auth'd vault for managing my 900 dance videos — transcriptions, search, LLM chat, automated tagging, and A/B practice looping.
West Coast Swing results warehouse — 132,750 entries across ~175 events, 7-phase name normalization.
Event-schedule aggregator + webcal feed, with vision-LLM PDF→JSON ingestion.
Public methodology docs — how strength scores, odds-to-finals, and the ranking models actually work.
Hosting on T-Mobile Home Internet took heavy tuning — measurements surfaced issues with proxy_buffering, BBR congestion control, and per-chunk network flushing.
Open-floor finder for 4 gym brands — normalizes 2 JSON APIs and 2 HTML scrapes into “when is the dance studio actually free between classes?”
One downside of where I live: no fiber. T-Mobile Home Internet puts me behind CGNAT, with no public IPv4 and no stable IPv6 — so nothing on the internet can reach my LAN directly. A couple of cheap cloud VPS solve it: they give me public IP addresses that route inbound traffic to my services. They route; they don't compute. Everything real still runs at home.