Cloud setup hook
Your tests pass on your laptop because it has your toolchain. A cloud run starts from a fresh clone on a clean machine. If the repository needs a tool or dependency that machine lacks, the factory agent can't build or test your change, or the run fails before the agent starts.
The cloud setup hook fixes this. It's a script you commit at .tessl/cloud-launch-setup.sh, and Tessl runs it to prepare the machine before each loop run and cloud launch in your repository.
What the hook is
- Location:
.tessl/cloud-launch-setup.sh, at the root of your repository. The path is fixed. If the file isn't there, Tessl skips this step. - When it runs: while Tessl prepares a cloud run, after it clones your repository and before it installs the run's skill and starts the agent. It runs on loops that start an agent, such as Ticket to PR, and on
tessl launch skill --cloud. Tessl Code Review and vulnerability remediation runs don't use it. - Which version runs: the hook on the branch the run starts from, usually your default branch. A hook on another branch has no effect until you merge it, so check it on a branch first, as Check the hook on a branch describes.
- Working directory: the clone root. The script runs with
bash, so it doesn't need to be executable. - Environment: the run's environment variables, including the secrets in the run's environment.
WORKDIRholds the subdirectory the run works in (empty for the repository root), andAGENTholds the agent that will run. - Time limit: preparation, including the hook, must finish within 30 minutes. The hook's time counts toward the run's timeout.
- Reruns: a resumed run prepares the machine again and runs the hook again, so the hook must be safe to run more than once.
Cloud setup isn't eval setup
Tessl has two setup mechanisms with similar names. They don't share anything.
- Cloud setup hook:
.tessl/cloud-launch-setup.shin your repository. It prepares the cloud machine for loops, factory automations, and cloud launches. - Eval scenario setup: a
setup.shnext to a scenario'stask.md, or thesetuplist inscenario.json. It prepares one eval scenario's working directory. See scenario.json.
What the cloud machine already has
The cloud machine runs Ubuntu with passwordless sudo, Docker with Compose, build-essential, Node.js, Python 3 with uv, Go, and Bun already installed. The current versions are listed in the setup hook reference of the tessl-labs/factory-setup plugin, and the check prints the versions it finds on the machine.
The machine has 4 vCPUs, 8 GiB of memory with no swap, and a 20 GB disk with about 12 GB free. /tmp is held in memory (tmpfs, up to about 4 GiB) and counts against the 8 GiB, so put large files in /var/tmp or in the workspace.
Install only what your repository needs on top of that, and only what a cloud run needs to build and test. Leave out CI-only steps, such as browser downloads, unless your tests need them.
Write the hook
Follow these rules:
- Start with
set -eo pipefail. Installers are often pipelines, such ascurl ... | bash, andset -ealone lets a failed download pass. Leave out-u, because some version managers, such asnvm.sh, aren't safe under it. - Echo each step before you run it. When the hook fails, the output then shows which step broke.
- Install from your lockfile. Use
npm ci,bun install --frozen-lockfile,uv sync --frozen, or your package manager's equivalent, so the cloud run gets the same dependencies as CI. - Accept a version range. Use the tool already on the machine when it satisfies the range your repository declares in
engines,.nvmrc,.tool-versions,go.mod, or.python-version. Don't pin the exact patch version CI uses. - Prefer your package-manager pin. When
package.jsonsetspackageManager, setCOREPACK_ENABLE_DOWNLOAD_PROMPT=0and runcorepack enable --install-directory ~/.local/bin. - Put installed tools in
~/.local/bin. The hook runs in a child process, soexport PATH=...,nvm use, or sourcing a profile doesn't reach the agent. Install tools into~/.local/bin, or link them there. - Use
sudo apt-get install -yfor system packages. - Fail with a clear message. When no installed or installable version satisfies the range, exit non-zero and name the tool, the range, and the version you found.
- Make it safe to run twice. Skip work that's already done, as the
jqstep above does.
Node.js is the one tool you shouldn't replace. Cloud runs use the Node.js on the machine. If your repository needs an older major version than the machine has, older Node.js versions aren't supported in cloud runs yet.
What happens when the hook fails
The hook must exit with status 0. A non-zero exit fails the run while Tessl prepares it: the agent never starts, nothing reaches your repository, and tessl launch view shows the run as error. In its --json output, data.attributes.status is failed.
The run's preparation progress names the step that failed. For example, this run failed in the hook:
outcomeisfailed.first_failediscloud-launch-setup, which means your hook exited non-zero. Any other value names a different preparation step, such ascloneorskill-install.subphaseslists each step in order with its outcome. Steps after the failure don't appear.
tessl launch view <id> shows the run as Error (RECIPE_FAILED). For workspace admins, the lines below the error hold the failure details, including the failing command. A hook that fails during preparation leaves no agent transcript, so tessl launch logs has nothing to show for it.
To find and fix the cause:
- Confirm the failing step with
tessl launch progress <id> --filename prepare-subphases.json. - Run the hook from a fresh clone of the branch on your own machine:
bash .tessl/cloud-launch-setup.sh. The step it echoed last is the one that broke. - If it passes locally, check what it assumes about the machine: a tool, version, or path the cloud machine doesn't have.
- Fix the hook on a branch, and check it on that branch before you merge.
When you change a hook that's already on your default branch, every cloud run uses the new version as soon as you merge it. A broken hook stops every loop in the repository until you fix it, so check before you merge.
Check the hook on a branch
Check a new or changed hook on a cloud machine before it reaches your default branch. The check is a cloud run of the check-cloud-setup skill from the tessl-labs/factory-setup plugin. It runs the branch's hook twice, which also shows the hook is safe to rerun, and then reports the versions of the tools on the machine. It changes nothing in your repository. Like any cloud run, it uses credits.
If you set up your factory with the factory-setup skill, the agent runs this check for you before it merges the hook. To run it yourself:
-
Push the hook to a branch, for example
add-setup-hook. -
From your repository, launch the check against your default branch, naming the branch to check:
Use the environment your factory's loops use, so the check runs with the same secrets. The check only reads the branch, so
readGitHub access is enough. Keep thelaunchRunIdfrom the output. -
Check the run's status with
tessl launch view <id> --json. A run usually finishes within 10 minutes. -
When
data.attributes.statusiscompletedanddata.attributes.outcome.statusissucceeded, the hook passed twice.data.attributes.result.summarylists each tool on the machine and its version. Merge the hook. -
When
data.attributes.outcome.statusisfailed,data.attributes.result.summarynames the step that failed anddata.attributes.result.reasonholds the last lines of the hook's output. Fix the hook on the branch, push, and check again. -
When the run itself fails, read its preparation progress as What happens when the hook fails describes. If
first_failediscloud-launch-setup, the hook on your default branch failed while Tessl prepared the check: fix that hook first. Any other value names a different preparation step.
Confirm a run prepared successfully
After you merge the hook, any cloud run's preparation progress shows whether the hook ran and passed:
outcome is ok, first_failed is null, and the cloud-launch-setup step is ok. A skipped outcome on that step means the run found no hook on the branch it started from.
Related
- Environments: the secrets and GitHub access a cloud run gets.
tessl launch skill: run a skill in the cloud.tessl launch view: a run's status and result.