bash tool, each task in its own Blaxel sandbox. Each task’s own tests grade the result.
The tasks are Harbor tasks, so Harbor builds each environment and runs each task’s verifier. You write only the agent. Start with the tool-using agent example if you haven’t run RL with the Loops cookbook before. This run is much larger, and some tasks take hours.
Prerequisites
- A Baseten workspace with Loops access to
zai-org/GLM-5.3-Flash, and its API key. GLM-5.3-Flash trains in either availability mode. - A Blaxel workspace and API key, with capacity for about 50 concurrent sandboxes at 8 GB of memory each.
- uv and Python 3.12 or later.
Install the cookbook
Install the Loops cookbook from PyPI into a uv project. The cookbook needs Python 3.12 or later, installs thebaseten-loops SDK, and provides the loops command. loops runs both recipes; each training config names its recipe with recipe = "rl" or recipe = "sft". Create a project first if you don’t have one:
examples/counting/train.toml, from your project’s directory. To change an example, copy its directory into your project at the same path. A config in your project wins over the installed one, and loops check prints the directory of the config it used.
Create a .env file in your project’s directory and set BASETEN_API_KEY to a workspace API key. The commands load .env from the training config’s directory or the directory you run them from. Never commit .env.
A run uses the serverless availability mode when your workspace has serverless access to the model, and the dedicated mode otherwise. To choose a mode, add BASETEN_LOOPS_SCOPE=serverless or BASETEN_LOOPS_SCOPE=deployment to .env.
Install Harbor with its Blaxel environment, and add BL_WORKSPACE and BL_API_KEY to .env:
WANDB_API_KEY to .env:
uv run loops run --help lists the flags.
Read the agent
examples/terminal_bench/terminal_agent.py defines TerminalAgent, a Harbor agent that calls the policy directly. Its system prompt describes a software engineer in a sandbox. Its one tool runs a bash command in the task’s environment and returns the exit code, stdout, and stderr, each truncated to max_output_bytes. The agent loops until the model replies without a tool call or reaches max_turns.
The agent decides what happens when a generation runs out of tokens. TerminalAgent discards a reply the token limit cut and samples the turn again, up to three times, so a cut generation never trains. After three cut attempts, the episode ends as truncated and is still graded. The tool-using agent makes the opposite choice: it ends and grades the episode, and the cut generation trains with the rest. Neither is a default; choose what fits your task.
examples/terminal_bench/harbor.yaml pins the Terminal-Bench 2.1 dataset to one commit, selects the cookbook’s Blaxel environment, and passes the agent’s limits:
examples/terminal_bench/harbor.yaml
loops_cookbook.harbor.blaxel:BlaxelEnvironment rather than Harbor’s own Blaxel environment. The cookbook’s class records every sandbox in the run’s resource journal, so loops cleanup can release them after a crash.
Read the training config
examples/terminal_bench/train.toml trains asynchronously: the sampler collects rollouts for the next update while the trainer applies the current one. The settings that shape the run:
examples/terminal_bench/train.toml
- Each update trains 4 groups of 8 attempts, for 50 updates.
max_steps_off_policy = 3lets a trained rollout come from a policy up to three updates behind the trainer. Async runs trade that staleness for throughput. Readfreshness/lag_meanto see the lag the run actually trained on.max_group_losses = 2lets a group train when up to 2 of its 8 sandboxes fail.
[compute] options off unless your workspace has spot capacity and sampler affinity routing enabled. With affinity on and routing off, sampling requests fail. To turn them off, start the run with the following command:
spot_job requests spot capacity for deployments; it doesn’t choose between the serverless and dedicated modes.
Scale out the run
GLM-5.3-Flash uses the serverless mode by default when your workspace has access, which needs no capacity request and suits a first run. A long asynchronous run that needs more training and rollout throughput belongs in the dedicated mode, where you set the trainer and sampler replica counts. To use the dedicated mode, add the following line to.env:
.env
trainer_replicas adds data-parallel trainer replicas for update throughput, and sampler_replicas adds sampler replicas for rollout throughput:
Run the example
To check the configuration, run the following command. It downloads the dataset, validates the job and agent options, and launches nothing. It warns about any task that declares more disk than the sandbox provides:rollout_timeout_seconds = 21600) and reports pipeline progress every 60 seconds, so a slow phase is distinguishable from a stall.
Read the results
Monitorreward/mean, discard/groups/no_variance, and rollout/* in W&B or in the run directory’s steps.jsonl. Terminal-Bench tasks vary widely in difficulty, so expect many no_variance groups from tasks the starting model always fails. See Check whether an RL run is learning.
To tell whether the trained agent is a better coding agent, score a saved checkpoint on tasks it didn’t train on. Training reward on Terminal-Bench measures the tasks in the training set. See Evaluate a model.
Add a loss on command output
examples/terminal_bench/train_echo.toml runs the same job with ECHO, a custom loss defined in echo_loss.py. It adds a next-token loss on the output the agent’s commands print, weighted by observation_weight, to the importance-sampling loss on the agent’s own tokens. The module’s docstring describes where it differs from the paper.
To install the loss’s extra, run the following command:
Shut down the run
loops run leaves the Loops run active. On serverless, deactivation is optional because idle runs incur no token charges. On dedicated capacity, deactivate the run when you finish to stop GPU billing without waiting for automatic shutdown. To end the run and its paired sampler in either mode, run the following command with your run directory:
Release sandboxes after a crash
Sandboxes bill until they’re deleted. If the run crashed, release its sandboxes with the following command:Next steps
- Design RL environments and rewards: Graders, task sizing, and exploits.
- Check whether an RL run is learning: Metrics for long, asynchronous runs.
- Deploy a checkpoint: Serve the trained adapter.