Brief
What had to change
"A mobile-first PWA dashboard for driving a single VPS through a web browser: multi-pane terminals (up to 16 concurrent ptys), AI agent launchers, host ops, and audit — all behind a single shared secret and a Tailscale-only domain." And the boundary, in the PRD's own words: "It is a single-owner control surface, not a public SaaS or a remote-desktop replacement." The stated goal: "Give a single VPS operator a fast, visual, browser-based control surface for the host — terminals, files, telemetry — without manual SSH for everyday work."
Approach
How the work was shaped
The three-tier split is a real boundary rather than a convention: the frontend never shells out, every privileged call crosses the agent's authenticated HTTP gateway, and the agent binds 127.0.0.1 by default — with no command allowlist at all, written down as a decision (“the perimeter is the security boundary, not per-command sandboxing”) instead of left as an omission. The Bun migration shows how he decides: installs, scripts and the frontend runtime moved on measured numbers, but the PTY-owning agent daemon deliberately stayed on Node 22 after he found that under Bun 1.3.14 node-pty loads and spawns yet `onData` never fires — every terminal silently blank — and that `Bun.Terminal` does stream but gives the child no controlling tty and no `setsid` (`/proc` showing `tty_nr=0`, `tpgid=-1`), which breaks Ctrl-C and the process-group kill in `killSessionTree`. The same commit fixed the hottest path he tripped over on the way in: terminal scrollback did `buffer = truncate(buffer + chunk)` on every PTY chunk, re-copying the full 250 KB cap on the same event loop that serves PTY I/O and SSE across sixteen panes, now a chunk array with a lazily joined cached string so appends are O(chunk).
Outcome
What the result changed
+29% req/s on /login (466 → 603, p95 112ms → 87ms), measured 32 conns × 8s on the same host
Constraints that shaped the system.
- 01
Single-owner by design — "intentionally not a public SaaS or remote-desktop replacement". Explicitly no multi-user model.
Constraint - 02
Tailscale only: "production is bound to a Tailscale-only domain via Traefik. Public Internet should never reach the panel."
Constraint - 03
"There is no command allowlist — the perimeter is the security boundary, not per-command sandboxing." The authenticated owner runs commands in a real pty by design.
Constraint - 04
The agent is the only component with host access; the frontend never shells out directly, and the agent binds loopback (127.0.0.1) by default so the privileged host API is never network-exposed.
Constraint - 05
No data layer between the frontend and the agent, and no Convex — the agent persists state to JSON files on the host.
Constraint - 06
Workspace state sync is last-write-wins with no realtime push; the other browser only catches up on next page load.
Constraint - 07
Auto-deploy via GitHub Actions is intentionally disabled (workflow_dispatch only); day-to-day deploys happen on the host via scripts/deploy.sh.
Constraint - 08
Pane templates are persisted to localStorage only (not yet promoted to agent-side JSON like workspaces were).
Constraint - 09
The heartbeat glow only fires on AI agent sessions, because activity detection is heuristic on agent output; plain shell sessions stay still.
Constraint - 10
Session eviction: opening a 17th pty evicts the least-recently-updated session (LRU) rather than erroring; each session keeps a ring buffer of up to 250k chars.
Constraint
