- 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, andlogsexit with the exit code of the remote command.- Commands that list things accept
--json. stop,sleep, andrmdo not ask for confirmation.makeis safe to retry: if the first attempt created a box, a retry waits for that box instead of creating another.
box_…, org ids org_…, and API tokens tsr_api_….
Account
tesser login
~/.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
TESSER_TOKEN
there is nothing saved to remove, and the command says so.
tesser whoami
tesser org
use requires a saved credential for that org; run
tesser login --org <org_id> first if there is none.
tesser member
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
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
tesser pool ls lists them.
tesser status
tesser sleep
tesser stop
dev again; Tesser does not reroute
the dependency silently.
tesser rm
tesser pool
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
.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
~/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
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
-f. Pressing Ctrl-C stops following; the server keeps running.
tesser ssh
~/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
<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
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
localhost:3000 at a box or a local target. The panel and the widget
do the same thing with a click.
tesser target
ls marks the selected
entry with *.
Other
tesser nuke
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.