Himansh Raj

Box Suite: Controlling My GPU Box from a Mac

· 3 min read

Box Suite: Controlling My GPU Box from a Mac

I do most of my work on a Mac, but the GPU lives elsewhere, an Ubuntu box with an i9-14900K and an RTX 5060 Ti. Box Suite is the pair of tools I built to control that box from my laptop without ceremony: boxctl, a Python CLI, and BoxDeck, a macOS menu-bar app. Nothing is hardcoded, you point them at your own machine with a small config file.

Two tools, one source of truth

  • boxctl, the CLI. It handles auth (Touch ID / TOTP), LAN↔remote routing, SSH tunnels, health checks, and launching VS Code Remote-SSH on the box.
  • BoxDeck, the macOS app. A menu-bar live telemetry chart, service toggles, and a remote file browser.

The important relationship: BoxDeck drives boxctl. One tunnel keeper, one source of truth. The app doesn't reimplement the connection logic, it delegates to the CLI.

Day-to-day it comes down to a few commands:

boxctl status # route, auth, key hours, tunnels, serve health, GPU
boxctl doctor # diagnose + auto-fix
boxctl connect # renew auth (Touch ID; TOTP fallback)
boxctl code [path] # VS Code Remote-SSH on the box

The non-obvious bits

Most of what I learned building this was in the details that only show up once you actually live with the tool:

  • Two routes, chosen automatically. ssh box probes the LAN first via an mDNS name, so DHCP can move the box without breaking anything, and falls back to the cloudflared domain. box-lan / box-remote force one when you need to.
  • Auth is layered on purpose. A silent 24-hour session key does the day-to-day work, and a Secure Enclave key (Touch ID) renews it. The subtle lesson: order matters. Listing the passkey first caused a biometric prompt on every background reconnect, so the layering had to be deliberate.
  • One tunnel keeper, always. Two keepers means two ssh loops, which means a Touch ID popup storm. That's why BoxDeck delegates to boxctl tunnel start instead of spawning its own.
  • One 16 GB GPU is a shared resource. Services marked gpu: true in ~/services.json on the box stop each other automatically, so two models never fight over the card.

A UI detail worth its own note

The menu-bar chart turned out to be the fiddliest part of BoxDeck. I ended up drawing it as an NSView, not an NSImage, because MenuBarExtra labels can't render a SwiftUI Canvas, and the NSImage + lockFocus route draws at 1× and looks fuzzy on Retina displays. It's a tiny thing, but it's the difference between the chart looking native and looking off.

What I took away

  • Routing and auth are where remote tooling gets hard. The happy path is easy; the failure modes, a moved IP, a background reconnect, a stray second tunnel, are what actually needed design.
  • Let one tool own the truth. Having BoxDeck delegate to boxctl instead of duplicating logic kept the whole thing coherent and stopped the popup storms.

Requirements are modest: macOS 13+, cloudflared, Python 3.12+ (via uv), and optionally Secretive for the Touch ID key.

If you want to look at the code, here it is: boxctl-deck on GitHub.