at play · case study
The Hub
An AI coding agent on my own server, driven from my phone — any CLI agent by design. What began as an idea tester now runs as production infrastructure: it works nights, runs goal-driven loops, ships products, watches itself, and backs itself up.
hover to inspect- role
- design & code · ops
- stack
- FastAPI · Claude Agent SDK · xterm.js · Tailscale
- frontend
- vanilla JS PWA — no build step, vendored deps
- runs on
- a self-managed VPS — systemd, isolated users
- status
- private build, in daily use
Everything it does
- chatstreaming agent, voice input, live cost meter, per-session spend cap
- terminalreal PTY with the first-party CLI — 3 sessions that survive disconnects
- dashCPU · RAM · disk, systemd · docker · CI — local and remote boxes over SSH
- pipelinean idea walks research → plan → spec → build; a judge gates every stage
- goal loopa goal stated once runs cycles until a checker says it is met — six hard stops
- night shiftstage chains marked "tonight" run in git worktrees, judged on the diff
- per-task modelmodel picked per task and per stage — cheap research, heavy build
- product factoryone command: repo → CI → hosting → DB → domain → analytics
- lifecycle registrykill / watch / keep verdicts read from real traffic
- cron jobsscheduled headless agent runs, morning briefing push
- watchdogalerts only on state change, two-strike rule, recovery push
- backupsnightly AES-256, 7 rotated copies, restore needs only openssl
- web pushterminal bell, job alarms, briefings — straight to the phone
- share targetphotos, PDFs and links shared from the phone land on the VPS
- file dropphone ↔ server file exchange, both directions
- voicelocal Whisper transcription — audio never leaves the box
- multi-instanceone install command; each hub gets its own user + systemd unit
- securitytailnet-only + own auth: scrypt, hashed sessions, IP lockout
- design system4 themes, thumb-first, 52 px targets, written rulebook
Rather touch it than read it? An interactive playground — the interface with example data, a replay of the factory shipping a product, and the loop drawn out — lives on the studio site.
Born on a walk
The need: ask an LLM something from the phone, mid-walk, without a third-party service reading the traffic. So the agent lives on a server I run, and the phone carries only a thin, installable PWA — a thought typed on the street becomes a running experiment on the VPS before the walk is over. Provider-agnostic by design: another CLI agent is a lane in the diagram, not a rewrite.
The path
There is exactly one road to the server: the tailnet. hub binds to localhost and is published only through Tailscale's private HTTPS — it does not exist on the public internet, there is no relay, no vendor bridge, no one in the middle.
Two bills, kept honest
The provider's terms draw a hard line: SDK traffic bills the metered API key; subscription OAuth belongs to the first-party CLI only. hub is architected around that line — chat and cron pay per token, the terminal's CLI rides the subscription, and its PTY deliberately strips the API key from the environment so the two paths cannot cross even by accident.
Reading the compliance page before drawing the architecture is the whole trick — the billing split isn't a setting, it's the shape of the system.
Locked from both sides
The tailnet is the outer wall; hub carries its own auth as a second, independent layer — scrypt passwords, session tokens persisted only as hashes, per-IP lockout. Auth is middleware, not a per-route decorator: a route added next year is protected because it exists. And there is no loopback bypass — "local" on a shared box is not "me".
The kill switch exists — but it demands a restart, logs on every boot, stamps every response header, and paints a red banner. An off switch nobody can see is how a box stays open for months.
The night shift
Ideas arrive by day; the server has all night. The night is a schedule, not a place: any stage of any project can be marked "tonight" from its card, and the sweep runs it in an isolated git worktree — never the live checkout, never main — while a small judge model reads the actual branch diff against the stage's brief. The morning brings a push, a written report, and a decision that stays human: accept, continue, or discard.
The loop closes
Work is a chain, not an errand: an idea walks research → plan → spec → build, every stage commits its artifact into the repo — IDEA.md, RESEARCH.md, PLAN.md, SPEC.md — and a judge gates every stage, so the chain stops at the first result that doesn't hold. The model forgets everything between runs; the repo doesn't. Above the chain runs the goal loop: a goal stated once, and cycles that keep going until a checker model — grading the project against the goal, not the agent's account of it — says it is met.
A loop that cannot stop is a bill, not a feature. Six independent conditions end it, and the cycle ceiling is enforced per stretch — even a hand-edited config cannot push past it.
A factory at the end of the line
One command provisions a complete product — repo, CI, hosting, database, domain, analytics — then the agent builds inside it, and a product can ship the same day. The lifecycle registry closes the loop: after each product's review window it reads real traffic and answers the question dashboards dodge — is 22 visitors good or bad. Every product under Eldora Studio came off this line.
It runs itself
A watchdog engineered against alert fatigue — pushes only on state change, two failures before an alarm, recovery announced immediately. Every night an encrypted backup gathers everything git doesn't hold; restore depends on nothing but openssl. The day starts with a briefing push: what ran, what failed, what the night shift built.
A server of one's own
Everything under hub is handled solo, and repeatably: one install script provisions a full isolated instance, so a second hub is one command on any box. The same screen that talks to the agent watches the machine it lives on — ops isn't outsourced here; it's part of the build.
Anthropic has since shipped the mainstream version of this idea — Remote Control, bridging a laptop session to the phone. hub still runs where that can't: on a server that never sleeps, over a network nobody else can see.