~/workspace. Tesser creates boxes, syncs your worktree to them, runs
commands on them, and puts them to sleep when they are idle. You do not deal
with instance ids, SSH keys, or IP addresses; tesser status will show them
if you want to see them.
Each box is an m7a.large (2 vCPU, 8 GB of memory) with a 40 GB disk, running
Ubuntu 24.04 with Node 22, rsync, and Docker (compose included) installed. The
ubuntu user has passwordless sudo and is in the docker group, so
sudo apt-get install and docker compose up both just work. You can check
what else is available with tesser exec -- which pnpm and install what your
project needs with tesser exec.
Two kinds of box
A workbench holds your worktree and runs nothing on its own. It is the boxtesser exec uses when you do not name one, and it is where tests,
typechecks, builds, and one-off scripts run. Each worktree gets a workbench
the first time it needs one.
An instance box runs one service’s dev server. tesser dev <service>
creates one for each combination of worktree and service, so a repository
with a frontend and a backend ends up with two instance boxes and one
workbench.
Keeping these separate means a test run never competes with the dev server
for CPU, and an install on the workbench never replaces the dev server’s
node_modules while it is running.
Creating a box
Most of the time you do not create boxes directly, becauseexec creates the
workbench and dev creates the instance box. tesser make exists for when
you want a box before running anything on it: tesser make creates a
workbench and tesser make <service> creates an instance box. Both print the
new box id.
When a warm box is available in the pool, creating a box takes a second or
two. Otherwise a new machine is launched, which takes about 90 seconds.
tesser pool fill keeps a couple of warm boxes ready if you create boxes
often.
Syncing
Everyexec and dev copies your worktree to the box before running. Only
changed files are transferred, and .gitignore is respected, so
node_modules, .env.local, and build output stay on your laptop. The box
gets its own node_modules when the setup command runs. If a sync would
delete most of what is on the box, Tesser stops and reports it, because that
usually means the box was created from a different worktree. In that case,
create a new box rather than passing --force.
The copy on the box is a real git repository with a single commit, your
current HEAD. git status and git diff work there, and git log shows one
entry. Anything you commit on the box is lost at the next sync, so always
commit on your laptop.
Sleep, wake, and removal
Idle boxes go to sleep on their own. A sleeping box keeps its disk and its id and costs a few cents a day. Any command that targets a sleeping box wakes it first, which takes about 40 seconds, and if the box had a dev server running it is started again.
A box counts as idle when no command is running on it and no traffic is
reaching it. A test suite that runs for an hour keeps the box awake for that
hour, while an SSH session sitting at a prompt does not.
You can also act immediately:
tesser sleep <box_id> powers a box down,
tesser stop <box_id> stops the dev server but leaves the box awake, and
tesser rm <box_id> removes the box permanently. None of these ask for
confirmation.
Finding a box
tesser ls lists every box in the org with its kind, service, power state,
and whether it is currently online. tesser status <box_id> shows the details
of one box, including its IP addresses and when it was last active. Both
accept --json.
Looking inside a box
tesser ssh <box_id> opens a shell in ~/workspace, and
tesser ssh <box_id> -- <cmd> runs a single command there without syncing
first. Use these for inspection rather than editing, since an edit made on
the box is overwritten by the next sync. To read the dev server’s output, use
tesser logs <box_id> for the last 200 lines or tesser logs <box_id> -f to
follow it.