Skip to main content
A few conventions apply to every command:
  • A command that creates or selects something prints the resulting id as its only output on stdout. Progress messages and errors go to stderr, so a script or an agent can capture stdout without parsing prose.
  • exec, ssh, and logs exit with the exit code of the remote command.
  • Commands that list things accept --json.
  • stop, sleep, and rm do not ask for confirmation. make is safe to retry: if the first attempt created a box, a retry waits for that box instead of creating another.
Box ids have the form box_…, org ids org_…, and API tokens tsr_api_….

Account

tesser login

Opens tesser.sh in the browser, where you sign in or create an account, choose or create an org, and approve the CLI. The resulting token is saved to ~/.config/tesser/credentials.json, and that org becomes the default for every later command. The token itself never passes through the browser. --org skips the org picker and requires that specific org. --token saves a token created on the dashboard instead of opening a browser, and must be combined with --org. --no-browser prints the sign-in URL and waits; this only works if a browser on the same machine can open it. For every command, the org is taken from TESSER_ORG if set, otherwise from the saved default, and the token from TESSER_TOKEN if set, otherwise from the saved credential for that org.

tesser logout

Revokes the saved token on the server, deletes it from disk, and clears the default org if it was this one. When the token comes from TESSER_TOKEN there is nothing saved to remove, and the command says so.

tesser whoami

Prints the signed-in email on stdout and, on stderr, which org is in use and where the org and token were read from. Exits 1 with a hint when there is no token.

tesser org

use requires a saved credential for that org; run tesser login --org <org_id> first if there is none.

tesser member

These are available to owners only. add invites an email address with the role member unless owner is given; the invitation is bound to the account the first time that person signs in. rm removes the member and revokes every token they hold. The last remaining owner cannot be demoted or removed.

tesser skill

install writes the agent skill, which ships inside the binary, to ~/.claude/skills/tesser/SKILL.md. With --project it writes to the current worktree’s .claude/skills/tesser/SKILL.md instead, and with --dir to the directory you name. print writes the skill to stdout.

Boxes

tesser make

Creates a box and prints its id. If a warm box is available in the pool it is claimed in a second or two; otherwise a new machine is launched, which takes about 90 seconds. If the command fails after the box was created but before it came up, the id is still printed, and running the same make again resumes waiting for that box rather than creating a second one. --ensure-running creates the org’s shared instance of <service> at the given commit. If an instance at that commit is already running, the command prints its box id and exits. If an instance at an older commit is running, the new box is started, waits for the health check, takes over as the org’s default, and the old box is removed. This form requires a git worktree (the commit is resolved locally), a manifest for the service, and values for every name listed under env.required, set with tesser env set.

tesser ls

Lists every box in the org with its id, kind, service, power state, whether it is online, and its public IP. Unclaimed pool boxes are not listed here; their count is printed on stderr and tesser pool ls lists them.

tesser status

Prints one box in detail: owner, commit (for pinned boxes), power state, whether the dev server is running and on which ports, IP addresses, creation time, and time of last activity.

tesser sleep

Powers the box down immediately. Its id, disk, and private IP are kept. There is no wake command: any command that targets a sleeping box wakes it first, which takes about 40 seconds, and restarts its dev server.

tesser stop

Stops the dev server and removes the box from the switcher, leaving the box awake. Any box whose dependency pointed at this one keeps pointing at it and gets connection refused until you run dev again; Tesser does not reroute the dependency silently.

tesser rm

Removes the box, its disk, and every dependency that pointed at it. This cannot be undone and does not ask for confirmation.

tesser pool

A warm pool makes make take a second or two instead of about 90 seconds. An unclaimed pool box removes itself after an hour.

Code and commands

tesser sync

Copies the current worktree to the box. Only changed files are transferred, and .gitignore is respected except for the files the manifest lists under [env] files. If the sync would delete most of the files on the box, it stops and reports it, since that usually means the box came from a different worktree; --force overrides this check. --restart runs the manifest’s setup and dev again after the sync, whether or not anything changed, for changes a running server cannot pick up by itself. Pinned boxes cannot be synced to. exec and dev perform this sync on their own before they run.

tesser exec

Syncs the worktree, runs the command in ~/workspace on the box, streams its output, and exits with the command’s exit code. Without a box id it uses the worktree’s workbench, creating one the first time. --in runs the command in the named service’s root directory. --deps-of gives the workbench the named service’s dependency ports for the duration of the command. Stdin is forwarded to the command.

tesser dev

Starts the dev server for a service from the current worktree. It creates or reuses the box for this worktree and service, syncs the worktree, makes sure the manifest’s dependencies are running, runs setup and then dev, waits for the port to answer, connects the box to its worktree siblings, and prints the box id. The first dev in a session selects its box in the switcher. Running dev again replaces the server, which is also how you recover from a crash. When the repository has exactly one manifest, the service name can be omitted. With a box id and a trailing command, dev runs that command instead of the manifest’s recipe. If the box has no manifest, the command must listen on port 3000.

tesser logs

Prints the dev server’s last 200 lines of output, or follows the output with -f. Pressing Ctrl-C stops following; the server keeps running.

tesser ssh

Opens an interactive shell in ~/workspace, or runs a single command there. Unlike exec, it does not sync first. Use it for inspection rather than editing, since an edit made on the box is overwritten by the next sync.

Services

tesser env

push sends gitignored env files to a box: by default every .env* file at the worktree root that git ignores, or the files you name. Pushed files stay in place across later syncs. Listing a file under [env] files in the manifest has the same effect on every sync. set, unset, and ls manage the values Tesser holds for a service’s pinned instances. ls prints the names only, and marks any name listed under env.required that has no value yet.

tesser override

Points one box’s <service> dependency at a specific box. <service> must be one of that box’s dependencies. --clear returns the dependency to what Tesser would choose on its own: the worktree sibling that serves that service, if there is one, otherwise the org’s shared instance.

The daemon

tesser daemon

Runs the local proxy, which serves localhost:3000 (the selected box), the <box_id>.localhost:<port> addresses, and the switcher widget at localhost:4100, and maintains the SSH tunnels and the laptop-side dependency ports. It answers requests from your own machine and from Tailscale peers; --allow-lan also admits the rest of the local network. If a port is already in use, the error names the flag that moves it.

tesser use

Points localhost:3000 at a box or a local target. The panel and the widget do the same thing with a click.

tesser target

Adds a server running on this laptop to the switcher. ls marks the selected entry with *.

Other

tesser nuke

Lists every box in the org and, after you type yes, removes all of them. --force skips the prompt. This is the recovery command for when something has gone wrong with the whole fleet.

tesser version, tesser help

--version, -v, --help, and -h are accepted as well. An unknown command prints the command list to stderr and exits 2.