Skip to main content
Tesser is three planes that never blur: a control plane of tiny actors that only ever decides, a data plane of SSH and plain IPs that carries every byte, and a laptop viewport that renders it all through localhost.

The whole system in one diagram

Three planes, strictly separated:
  • Data plane — SSH and rsync to box public IPs, VPC private IPs between boxes. Every byte of sync, exec, logs, and mesh traffic. Boring on purpose; survives control-plane death entirely.
  • Control plane — cells. Decisions only: who exists, what routes where, what sleeps when. Never carries data.
  • Viewport — the laptop’s browser window into the system, owned by tesserd.

Boxes and instances

A box is one EC2 machine (public IP for the laptop’s SSH, VPC-internal private IP for the mesh). Two classes:
  • Instance box — born as (content source × service), runs exactly one service instance. One instance per box, always: this keeps ports collision-free, boxes fungible, lifecycles uncoupled, and makes the shared main instance of a service indistinguishable from anyone’s dev instance. A monorepo worktree spawns one box per service (a cohort).
  • Workbench box — born as (worktree, no service). A synced workspace plus compute, existing to exec — tests, typechecks, builds. Serving boxes serve; workbenches compute. Heavy jobs never contend with a dev server.
An instance is a running copy of a service, and its type is defined by its verbs: The distinction matters because a box transitioning content is two different operations: mutating a living process (HMR absorbing a sync) versus replacing an instance (new sha, new box, alias flip). The verbs keep those operations impossible to confuse.

Naming and routing

Names are globally meaningful, locally resolved. A service name (backend, worker) means the same thing everywhere — names are org-global, collisions rejected at registration — but which instance a name lands on is decided per box:
  • The org cell holds one default binding per name — normally the pinned main instance. A blue/green rollover is one atomic write here.
  • A dev box may carry per-name overrides, stored in its box cell, written by its owner’s tools. The common case is written automatically: cohort auto-wiring points a worktree’s sibling boxes at each other at creation time.
  • An org-owned (pinned) box structurally cannot carry overrides — so the shared mesh resolves identically everywhere and can never call into someone’s dev instance. Per-user routing conflicts aren’t forbidden; they’re unrepresentable.
There is deliberately no per-request routing: no identity headers, no interception. Overrides are resolver-scoped. To see your modified backend through the full chain, you run the (unmodified) services in front of it in your cohort — cheap, because boxes are cheap.

Deps are loopback ports, not URLs

A manifest declares dependencies as port bindings:
boxd owns those loopback ports and forwards through the mesh (caller boxd → target’s private IP → target boxd → target loopback). Consequences:
  • Apps need zero changes. Real repos already say localhost:5001 in their .env; on a tesser box that URL simply is the dep.
  • No DNS anywhere. No resolver interception, no hosts files, no invented TLD. Names live in manifests, tables, and UI — never on the wire.
  • Any protocol works. With one instance per box, forwarding needs no Host/SNI inspection, so postgres rides exactly like HTTP.
The laptop participates identically: tesserd binds the deps of the service being viewed, so browser JS calling localhost:5001 works the same as server-side code on a box.

The viewport

  • localhost:3000 — the selected target: the stable door.
  • <boxid>.localhost:<port> — any box’s port, directly. Browsers resolve *.localhost to loopback natively (RFC 6761, secure context, no config); tesserd binds each declared port number once and Host-routes, so two boxes on :8080 share one laptop listener. Box IDs are already unique, already on stdout — agents construct URLs mechanically, and there is no name allocation to design.
  • Nothing is installed or modified on the host OS. The only global resource consumed is loopback ports, first-come-fail-loud.

The control plane

Cells are small single-writer actors (Durable Object model): each is its own SQLite database, addressed by name. The code is written strictly inside celld’s compatibility subset — SQLite storage, alarms, hibernatable WebSockets, fetch — so the identical bundle runs on Cloudflare Workers now and on a self-hosted celld fleet in a customer’s AWS when BYOC matters.
  • Org cell — service registry, alias defaults, warm-pool state and refill alarms, fleet policy (reaper TTLs), tokens. Writers: rollovers and admin operations.
  • Box cell (one per box) — the box’s lifecycle state machine, its overrides, its derived routing table, presence, reaper timers. It is the join point: it subscribes to org defaults and materializes defaults ⊕ overrides per box. Nobody outside writes its derived state.
  • A user cell (token, presence, preferences — nothing routable) is folded into the org cell until a second user exists; the split is mechanical because nothing routes through it.
State placement rule: state lives in a cell iff someone needs it when the laptop lid is closed (boxes reading tables, alarms firing overnight). Everything whose only reader is an open laptop stays on the laptop: worktree↔box mapping, per-box SSH private keys, sync fingerprints, viewport selection, tunnel state.

boxd ↔ cell sync: drift-proof by construction

The routing table is pushed as a versioned full document — never diffs. boxd swaps it atomically; its state is always “table vN”, current or stale, never corrupt. Heartbeats echo the version; a mismatch triggers a full re-push, so drift self-heals within one heartbeat and every reconnect starts with a full sync. Each datum has exactly one writer (tables: cell→boxd; activity/health: boxd→cell), so merge logic never exists. If the cell is unreachable, boxd fails static — it serves its last table indefinitely; a stale route points at a dead box and fails loudly, never silently-wrong. boxd has no local mutation knobs; the day it grows a “quick local override” is the day this becomes a two-master system.

boxd

The one tesser process on every box:
  • Process supervisor — spawns the dev recipe as a child, holds the pipes, writes a rotated local log, records exit codes, replaces on restart. boxd supervises but never resurrects: a crash is recorded and reported; re-running dev is the recovery path, because callers own starts.
  • Mesh forwarder — owns the dep loopback ports; exposes the service’s declared ports on the private IP (services themselves bind loopback only).
  • Activity clock — timestamps meaningful events: mesh traffic, exec children, CLI ops. Live child processes pin the box awake; SSH keepalives and presence pings don’t count. This clock is what the reaper trusts.
  • Presence + health — a WebSocket to its box cell carrying heartbeats, table-version echoes, “listening on port” / healthcheck results, and bounded breadcrumbs: exit codes, health flips, a ~40-line crash snapshot (what a failed rollover reports). Bulk logs never leave the box — tesser logs is a direct SSH tail.

Content transport

rsync is the only transport; sha is only addressing.
  • Dev instances sync from the live worktree — fingerprint short-circuit so unchanged trees cost nothing, a mass-deletion guard against syncing the wrong worktree, and a per-box lock serializing concurrent syncs.
  • Pinned instances sync from a throwaway standalone shallow clone of the sha (real .git, one commit, detached HEAD) materialized by the caller.
  • Every box is guaranteed a valid standalone repo — sync never ships the source’s .git-shaped thing verbatim. (A linked git worktree checkout’s .git is a file pointing at a laptop path; shipping it raw breaks git on the box.)
No forge credentials, ever. Because there is no reconciler, every start has a caller; every caller has the repo and SSH reach; so the caller pushes content. Boxes never talk to GitHub. The cloud may propagate caller-delivered content between its own boxes (warm-pool seeding) but never originate it. Consequence: the system’s complete secret inventory is per-box SSH keys, cell-held env values, and the control-plane token. Warmth has two layers with different owners: machine-warmth (booted OS, toolchain, boxd — the cloud maintains it freely, it never goes stale) and repo-warmth (content + node_modules — caller-applied, decays gracefully, TTL-bounded in the pool, refreshed by any claim’s first delta sync).

Lifecycle

Three verb layers; EC2’s words are banned from the product: The reaper (the control plane’s only automation, and it only turns things off): Sleeping is ~100× cheaper than awake (EBS only: cents/day); the rm stage is fleet hygiene, not economics. Any caller-driven op wakes a box transparently; mesh traffic keeps a box awake but never wakes one — a request to a sleeping box fails fast, and ensure-on-use is the revival path. Blue/green rollover (pinned instances): ensure-running <newsha> → new box goes healthy (boxd reports port-listen / healthcheck) → org cell flips the alias atomically → drain grace for in-flight connections → old box removed. Rolling back is ensure-running the old sha.

Infrastructure

  • Public subnet, public IPs. Every box gets an auto-assigned public IPv4; the laptop SSHes straight to it — direct, key-only (per-box keypairs, BatchMode, per-box known_hosts). No jump host, no NAT. Public IPs change across sleep/wake; the daemon re-resolves tunnel endpoints when a box moves.
  • Box↔box mesh rides VPC-internal private IPs, which are stable for a box’s whole life — including across sleep/wake — so routing tables never chase addresses.
  • Security group: :22 in from anywhere (sshd only accepts the per-box keys), members may talk to members on anything, all egress.
  • Warm pool: cloud-maintained machine-warm blanks; claim-by-retag in seconds; unclaimed boxes self-destruct on a timer.
  • Static infra is an alchemy stack (infra/); ephemeral boxes are not IaC — cells drive RunInstances directly and EC2 tags remain legible truth.