TMax v1.1

Repaired data, self-generated data, and stable RL

Set the publication date: the date line above, plus the file name and date: in the front matter.

Terminal-Bench 2.0 against model size, from v1.0 to v1.1. Every TMax model moves up: TMax-9B goes from 27.2% to 33.0%, past Claude Haiku 4.5 and GPT-5-mini, and TMax-27B (43.8%) edges past the 1T-parameter Kimi-K2.5. We re-ran the Qwen base models too. TMax and Qwen scores use our harness on Daytona; other scores are self-reported or from the leaderboard.

The teaser GIF still has draft labels: the first frame’s subtitle says “Previous draft scores”, and the last frame says “27B is provisional (266/267 graded)” with an asterisk on TMax-27B. The first frame also shows Qwen3.6-27B at 39.5%, where the v1.0 post says 39.6%. Re-export before publishing. The site copy holds the first frame for 1.5 s and the last for 3 s; the original advances every ~65 ms and loops straight back from the final frame.

TMax v1.0 introduced a simple recipe for training terminal agents with RL: synthetic environments sampled along nine structured task axes, trained with outcome-only DPPO.Hamish Ivison*, Junjie Oscar Yin*, Rulin Shao, Teng Xiao, Nathan Lambert, and Hannaneh Hajishirzi. “TMax: A simple recipe for terminal agents.” arXiv preprint arXiv:2606.23321, 2026. *Equal contribution.

In v1.1, we keep the recipe and improve the data it trains on and the infrastructure it runs on.

TL;DR

TMax-9B now scores 33.0% on Terminal-Bench 2.0 (up from 27.2% in v1.0), ahead of Claude Haiku 4.5 (29.8%) and GPT-5-mini (31.9%), and every model size from 2B to 27B improves.

Release Everything below will be public. Links are placeholders until release.

Fill in the links once artifacts are up, and drop the .tbd class from each tag as it goes live. The paper calls the data TMax-13k; rename it there too, or note the alias. Confirm which data extras ship (audit labels, self-generated set).

What’s new in v1.1

v1.0 (June) v1.1
RL data TMax-15k: 14,601 environments, unaudited TMax-v1.1-13k: 13,565 environments, audited and repaired
Datasets compared 6 12
Sandboxes Podman, on the same nodes as inference Dedicated Apptainer sandbox fleet on CPU nodes
Training stability Long runs often unstable No collapse over 1,000 steps
TMax-9B on TB 2.0 27.2% 33.0%

1. Auditing and repairing every environment

v1.0 deliberately skipped validating its environments. The pipeline only checked that each environment builds, and relied on RL to drop tasks the model can never solve (a group where every rollout scores zero carries no gradient). That handles tasks that are too hard. It does not handle tasks that are broken the other way: a verifier that a lazy solution can pass. RL is very good at finding those shortcuts.

So v1.1 adds a one-shot audit-and-repair pass after generation, inspired by River.Yao et al., “River,” 2026. River uses rubric-based repair and filtering on existing datasets; we apply the same idea to our own generated data.

The v1.1 data pipeline. After the generator writes a task, an auditor labels whether its verifier actually checks the instruction, and a repairer rewrites the verifier or cleans the image where the problem is fixable. Unfixable tasks are dropped.

The audit found far more problems than we expected:

14,601 v1.0 tasks audited 76% verifier too weak 11% answer leaked in the environment 13,565 kept as TMax-v1.1-13k

What the auditor found in TMax-15k, and what we did with each task. We repair the three most common fixable labels, keep clean tasks as they are, and drop everything else. The 1,036 dropped tasks include flagged tasks whose repair could not be applied.

Weak verifiers dominate. A typical one checks that an output file exists and matches one fixed expected value, but never runs the program the task asked for, so an agent can hardcode the answer. Below are real verdicts from the auditor, lightly trimmed.

Task: write a C++ tool, analyze_gc.cpp, that computes statistics over a FASTA file.

“The verifier recomputes the correct stats for the single fixed FASTA file and exact-compares stats.txt, but it only checks that analyze_gc.cpp exists. It never compiles or executes that source, so an empty C++ file plus hardcoded expected output can pass.”

Repaired. The repairer rewrites the verifier so it tests the behavior the instruction asks for, not just one fixed output file.

Task: craft a payload that gets a Go validator to grant admin access.

“The verifier executes validator.go from the writable task filesystem without checking that it is unchanged; setup even applies chmod -R 777. An agent can replace the validator with a program that always prints Access Granted: Admin.”

Repaired. Also labeled verifier too weak. The repaired verifier must not trust files the agent can edit.

Task: write parse_logs.py to summarize a set of log files into a CSV.

“The setup writes the complete ground-truth parsing result to /tmp/expected_summary.csv, and that file remains accessible to the agent. A fake parse_logs.py can simply copy this file, passing both the exact-content and timing checks without parsing logs.”

Repaired. The leaked file is removed from the image. If the verifier needs it, it ships with the tests instead (see below).

Task: an ETL job that, among other things, reports the covariance determinant of three sensors.

“The verifier hardcodes the sample-covariance determinant as 1.7225, but the supplied CSV yields approximately 0.35237. Thus a faithful ETL implementation fails the verifier.”

Repaired. The repairer makes the verifier consistent with the instruction and the data.

Task: implement config_manager.py and match a reference implementation.

“The verifier requires /tmp/oracle_config_manager.py and explicitly asserts that it exists, but the setup script never creates that file. Therefore even a fully correct implementation fails.”

Dropped. Instruction–environment mismatches like this one, and the other rare labels, are removed rather than repaired.

Real GPT-5.6 Sol verdicts on TMax-15k tasks (a 40-task audit sample). Task descriptions are paraphrased from the verdicts.

The examples come from a 40-task sample of auditor verdicts (tasks 000011, 000022, 000278, 000322, 000344). That sample is from the prototype labelling run, so double-check these tasks got the same labels in the final pass. The “Repaired” lines describe what the repairer does for each label, not the exact patch for each task.

A leaked answer has to leave the image. Our first leak repairs added a check that the agent’s output is not a byte-for-byte copy of the leaked reference file. That doesn’t work: the agent can copy the reference, append a comment, and pass both the inequality check and the behavioral tests. Of the first 18 leak repairs we accepted, 11 relied on exactly that check. The final repairer instead rebuilds the image without the leaked file. If the verifier needs the reference, it ships with the tests, which are only copied into the sandbox at verification time, after the agent has finished.

As in v1.0, we still do not filter out tasks a strong model can’t solve; RL’s zero-variance filtering takes care of those.

So does repair help? Holding everything else fixed, training on the repaired data improves Terminal-Bench Lite by 5.8 points and Terminal-Bench 2.1 by 2.3 points over the unrepaired v1.0 data. Our interpretation: weak verifiers reward shortcuts, so a policy trained on them partly learns to take shortcuts instead of doing the task.

Repair is worth +5.8 points on TB Lite and +2.3 on TB 2.1. Qwen3.5-9B trained with the same recipe on the v1.0 data before repair and on the repaired TMax-v1.1-13k. Mean ± standard error over three trials per task.

2. Results

TMax-v1.1-13k against 12 other datasets

Since v1.0 we have doubled the set of baselines, adding six recent datasets: LiteCoder, SETA, CalibForge, Terminal-Lego, RST, and Facet. As before, we hold everything fixed (Qwen3.5-9B, our recipe, our harness) and change only the RL data. For several of these datasets, this is the first time they have been used for RL training in the open.

RL on Qwen3.5-9B, changing only the dataset. Switch benchmarks, hide the v1.1 ablations, or plot the gain over the base model. The peach bar is the v1.0 data before repair; the purple bar is data generated by Qwen3.5-9B itself (§3). Mean ± standard error over three trials per task.

TMax-v1.1-13k has the highest mean on both benchmarks: 65.6 on TB Lite and 29.6 on TB 2.1. Its lead over the strongest baselines (RST on TB Lite, Facet on TB 2.1) is within the error bars, so the fair summary is that TMax-v1.1-13k matches or beats every dataset we tried. Notice where the unrepaired v1.0 data lands on TB Lite: mid-pack. Repair is what moves it to the top.

Every model size improves

We apply the recipe without modification to the other Qwen3.5 sizes and to Qwen3.6-27B.

Base model vs. TMax v1.0 vs. TMax v1.1. TB 2.0 runs on Daytona over all tasks, the same setting as the v1.0 headline numbers, so the two versions are directly comparable there. TB 2.1 and TB Lite run on our own sandbox fleet and are shown for v1.1 only. Mean over three trials per task.

On Terminal-Bench 2.0, v1.1 beats v1.0 at every size: TMax-2B goes from 2.9 to 6.4, TMax-4B from 18.9 to 25.1, TMax-9B from 27.2 to 33.0, and TMax-27B from 42.7 to 43.8.We re-ran the base models for v1.1 (three trials per task instead of five), so their scores differ slightly from the v1.0 post. For example, Qwen3.6-27B moved from 39.6% to 42.0%.

TMax-9B now beats every prior terminal agent up to 30B parameters in our comparison, including CalibForge-30B-A3B (32.6%), as well as Claude Haiku 4.5 and GPT-5-mini. The 27B gain is small, since Qwen3.6-27B is already strong (it even dips slightly on TB Lite), but TMax-27B still edges past the 1T-parameter Kimi-K2.5 (43.2%).

The v1.0 generalization results also hold for the new TMax-9B. It improves SWE-bench Verified from 46.2 to 55.3 and AIME’24/25 (solved with the terminal) from 72.2 to 93.3, and it gains 8 to 14 points on TB Lite under every other harness we tried (OpenHands, mini-SWE-agent, Terminus-2).

3. Models can generate their own training data

v1.0 used Gemini-3-Pro to write every environment, and v1.1 adds GPT-5.6 Sol for auditing and repair. That raises a fair question: does the recipe only work because these teachers are much stronger than the 9B policy?

To test this, we reran the entire pipeline (generation, auditing, and repair) with Qwen3.5-9B, the same model we then train. This produced 3.1k environments.

Qwen3.5-9B trained on data it generated itself. RL on the 3.1k self-generated environments, compared with the median of the 12 prior datasets and with TMax-v1.1-13k. Mean ± standard error over three trials per task.

The self-generated data improves Qwen3.5-9B by 12.6 points on TB Lite (49.4 to 62.0) and 6.8 points on TB 2.1 (20.5 to 27.3). That beats more than half of the prior datasets, despite being smaller than most of them, and lands within a few points of TMax-v1.1-13k. The pipeline does not need a strong teacher: a model of similar strength to the policy is enough.

Why would this work? We think it comes down to an information asymmetry: for many tasks, building the environment is easier than solving it. Writing a sudoku puzzle together with a checker is easy; solving it through a terminal is harder. The generator only has to do the easy side.

Self-generation does cost more in yield. In our first self-generation run, only about 13–17% of the 9B model’s environments built and passed their initial-state check, so it took roughly six times as many task templates per kept environment as with Gemini.

The yield numbers come from the 1k self-generation pilot; confirm or update them for the 3.1k run, or cut the paragraph.

4. Stable RL: it was the infrastructure

In v1.0, long training runs were often unstable, and some collapsed after a few hundred steps. The standard fixes, an FP32 LM head to reduce the mismatch between trainer and inference engine and larger groups, helped but did not remove the instability. The v1.0 paper also named a suspect: to save cost, our Podman sandboxes ran on the same nodes as the inference engines and competed with them for CPU and memory.

That suspect turned out to be the main cause. Once we reduced infrastructure noise, training ran smoothly for 1,000 steps.

Why sandbox noise breaks RL

Every rollout is a long agent episode, around 25 commands, inside its own sandbox, and every layer underneath can fail. An image fails to pull, a node is preempted, a command hangs because the node is overloaded, or the rollout spends its time budget waiting for a free sandbox. In v1.0, all of these looked exactly like the model failing: reward 0.

That is worse than random noise. Group-based RL scores each rollout against its siblings, so a fake zero actively pushes the policy away from whatever that rollout was doing, even if it was on track.

A fake zero is a real gradient. One group of eight rollouts for the same task, where two sandboxes died partway through. Scored as 0, they get pushed down exactly like genuine failures. Masked, they drop out of the group and the six valid rollouts set the baseline.

Failures are also correlated. When a registry or a node goes down, it takes many rollouts with it at once, so the update is not just noisy but large and wrong. In one incident during development, an image registry outage turned over 4,000 rollouts into zeros. The measured training solve rate fell from 0.70 to 0.14 even though the model had not changed, and the policy kept training on that reward for 24 steps.

A dedicated sandbox fleet

We fixed this on two fronts: give sandboxes their own machines, and make the trainer tell “the model failed” apart from “the infrastructure failed”.

The v1.1 training setup. Each rollout leases an isolated 2-CPU Apptainer sandbox from a small controller, which grows and shrinks a pool of CPU worker nodes through Slurm. The agent’s commands go straight to the worker. Hidden tests run inside the sandbox at the end and produce the reward. A rollout that fails for infrastructure reasons is flagged and masked out of its group instead of being scored as 0.

A 1,000-step run on the sandbox fleet. Qwen3.5-9B trained with the v1.0 recipe on the v1.0 data (DPPO, FP32 LM head, 8 prompts × 32 rollouts per step). Switch metrics to see that entropy, gradient norm, and the logprob gap between vLLM and the learner stay flat while the solve rate keeps rising. One seed, resumed twice after crashes.

With essentially the same recipe and data as v1.0, training now runs to 1,000 steps without collapsing. The same fleet also runs our TB Lite and TB 2.1 evaluations, at a fraction of the cost of a hosted sandbox service.

Caveats on this section, from the codebase investigation:

5. Smaller changes

Citation

Please cite this work as:

Ivison, Hamish and Yin, Junjie Oscar and Shao, Rulin and Xiao, Teng and
Lambert, Nathan and Hajishirzi, Hannaneh, "Tmax: A simple recipe for terminal
agents", arXiv preprint arXiv:2606.23321, 2026.

Or use the BibTeX citation:

@misc{ivison2026tmaxsimplerecipeterminal,
      title={Tmax: A simple recipe for terminal agents},
      author={Hamish Ivison and Junjie Oscar Yin and Rulin Shao and Teng Xiao and Nathan Lambert and Hannaneh Hajishirzi},
      year={2026},
      eprint={2606.23321},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2606.23321},
}

Update the citation if v1.1 ships as a new arXiv version or a new paper.

← All posts