Code agents and computer use
A code agent is a language model that acts by writing programs and running them. A computer-use agent acts on a screen instead, by clicking and typing the way a person does. Both put the model in front of a real machine, with files, processes, a network, and the power to break things. This section shows why a program is often a better action than a single tool call, how to run model-written code safely, how coding agents are measured and trained, and how screen agents see and point.
Interviewers ask about this area because it moved faster than almost any other. SWE-bench is a benchmark of 2,294 real GitHub issues, each graded by running the repository's own tests. In October 2023 the best model tested on it fixed 1.96% of the issues (Jimenez et al. 2023). That model was handed a few retrieved files and asked to write a fix in one shot. In the leaderboard's February 2026 entries, Claude Opus 4.5 fixed 76.8% of SWE-bench Verified, a subset of 500 issues that people screened by hand. It ran inside a harness, the program around the model that offers it tools and runs them, and this harness offered nothing but a shell. The run cost $0.75 per issue on average.
Three things changed between those two numbers. First, models learned to act. They search the repository, open files, run the code, read the error, edit, and run the tests again. Second, the commands they are given got better. With the model held fixed, changing a single command moved the share of issues fixed by as much as 7.7 points (Yang et al. 2024). Third, coding agents are now trained with reinforcement learning, in thousands of isolated copies of real repositories at once.
Here is the setting, restated from earlier in the chapter. §24.1 defined an agent as a loop. The model writes text, a parser turns the text into an action, the environment runs the action and returns an observation as text, and the model writes again. In symbols the agent is a policy , a probability distribution over the next action given the history . The history holds the task , and for each earlier turn the model's thought (the text it wrote around the action), the action , and its observation .
Until now each action was a JSON tool call, a small structured request that names one tool and its arguments. §24.2 showed how to check such calls and how to make them always well formed. §24.3 interleaved them with written reasoning and trained the policy on them. §24.4 showed that searching over them needs a way to undo them.
In this section the action becomes a program and the environment becomes a computer. Four consequences organize what follows. Code composes tools, so one action can do the work of many turns. Code can do anything, so it must run in a sandbox. Real software work needs benchmarks that grade by running tests, and interfaces shaped for the model, and those benchmarks double as training environments. And when the only interface is a screen, the agent must look at pixels and point at them, which costs many tokens and can miss.
Code as the action space
Start with a small task that every agent builder meets in some form. A user asks "How much do we owe Acme in late-delivery fees?" Three tools are available.
list_orders(customer, cursor)returns one page of three order ids, plus a cursor that says where the next page starts. The agent cannot guess the cursor. It must read it from the page.get_order(id)returns the promised and actual delivery days and the order's value.late_fee(value, days_late)applies the contract, 1% of the value per day late, capped at 10%.
Acme has seven orders, so there are three pages.
A turn is one call to the model. With JSON tool calls the agent cannot ask for page 2 until it has read page 1, because the cursor for page 2 is inside page 1's result. So paging takes three turns. Then the agent can fetch all seven orders in one turn of parallel calls, compute the fees for the late ones in one more turn, and answer in a sixth. Every order record, with its long shipping log, lands in the context and is read again by every later turn.
Written as code, the same work is one action. A while loop walks the pages, and a for loop fetches the orders and adds up the fees. The only thing that enters the context is the one line the program prints.
The difference in turns is not an accident of this example. A tool-calling agent must see a result before it can write any call that needs it. A program never waits for the model, because the interpreter passes each result to the next call through a variable.
To state this precisely, draw the calls as a graph. Put an arrow from call to call whenever 's arguments cannot be written without 's result. Such a graph has no cycles, since no call can need its own result, so it is a directed acyclic graph. Its critical path is the longest chain of arrows, as in the task graphs of §24.4, and is the number of calls on it.
∂ Proof
A turn is one call to the model, and it writes the arguments of every tool call it issues from the context it was given. The results of a turn's calls are appended only after that turn ends. If depends on , then 's result must already be in the context of the turn that issues , so is issued in a strictly later turn than . Along a path the turn indices strictly increase, so the last call is issued in turn or later. The answer needs that call's result, so it comes in turn or later.
For part 2, the interpreter evaluates all the calls inside one action in an order that respects the arrows, passing results through variables, so none of them waits for the model. The model needs one turn to write the program and one to read its output and answer. ∎
In plain words, tool calling pays one model call per level of dependency, and code pays one per program. The condition in part 2 matters. Sometimes the next step needs the model's judgment about a result, such as reading a document to decide what to search for next. Then code cannot compute the dependency and saves nothing. Code wins when the composition is mechanical, such as pagination, filtering, joins, arithmetic, and retries.
Two turns also assumes the program runs correctly the first time. Each failed run costs one more turn, with the error message as the observation. That is still far fewer turns than a long chain of calls.
In the Acme task the critical path is three page calls, then one get_order, then one late_fee. So , and the bound says at least six turns. The cells below run both agents. The tools count their calls, and a rough rule of four characters per token measures what each agent reads. Every turn also reads a system prompt with the tool definitions, of tokens, as in the token count of §24.1. As everywhere in this chapter, the policies are short scripts with the same interface as a model. The loops are real, and only the decisions are hand-written.
The JSON agent reads every result so far and decides its next batch of calls. Independent calls go out in parallel in one turn, as every major API allows. So this is the best a tool-calling agent can do.
The code agent writes one program. The executor runs it in a fresh namespace that holds only the tools. It returns what the program printed, or the exception it raised, as the observation.
Make the logs real database rows or web pages and the gap keeps growing, since each result in the tool-calling agent is read again by every later turn. The published evidence matches the theorem, including its condition.
Code as an action is a different idea from code as reasoning. In program-aided reasoning the model writes one program to compute an answer, so the interpreter does the arithmetic the model would get wrong (§18.1). A code agent writes programs that act on an environment across many turns, reads the errors, and revises. The interpreter's error messages are among the most useful observations an agent ever gets, because they name the file, the line, and the reason.
Code also has real costs, which is why production systems offer both kinds of action.
- Checking before running. A JSON call can be checked against its schema before it runs, forced to be well formed (§24.2), and shown to a person for approval. A program cannot be checked that way in general. Whether it will call a given tool or touch a given file is not known until it runs. So approval checks must move into the tools themselves and into the sandbox's permissions.
- Partial failure. A program that crashes after three of seven writes leaves the world half-changed. The tools a program calls should be idempotent, meaning that running a call twice has the same effect as running it once, so a retry repeats no side effects. §24.6 takes this up.
- Isolation. A JSON call can only invoke the tools you listed. A program can do whatever its interpreter can, which is the subject of the next part.
| JSON tool calls | code actions | |
|---|---|---|
| turns for dependent calls | at least | two, if the dependencies are computable |
| intermediate results | all enter the context and are read again | only what the program prints |
| check before running | schema validation, constrained decoding, approval per call | not possible in general; checks move into tools and permissions |
| failure | one call fails, the rest are untouched | a crash mid-program can leave partial side effects |
| isolation needed | the tools' own permissions | a sandbox for arbitrary code |
| best for | single calls, high-stakes actions, models that code poorly | pagination, filtering, joins, loops, data analysis, software work |
In practice, give an agent code actions when its tools are cheap to compose and their results are large. Keep JSON calls for the few actions that a person must approve one at a time. An interviewer will ask you to count the turns for a concrete task, and then ask what you give up by switching to code.
Sandboxes
A code action can do anything the interpreter can, and the interpreter can do anything the operating system lets it. So the question is never whether to isolate model-written code, only how strongly. A sandbox is an environment that runs code under limits the code cannot lift. Before choosing one, list what can go wrong.
- The model's own mistakes. An agent that runs
rm -rfin the wrong directory, force-pushes to a shared branch, or drops a database table needs no adversary. Practitioners report such mistakes as far more common than attacks. - Injected instructions. A repository file, an issue comment, or a web page can contain text that the agent reads as an instruction. §19.3 showed why this risk is built into any model that reads untrusted data. It calls the dangerous combination the lethal trifecta, an agent that holds private data, reads untrusted content, and has a way to send data out.
- Reward hacking. During reinforcement learning the policy is paid by a grader, and if it can reach the grader it can game it. Policies have been seen exiting before the assertions run, patching the test framework, and editing the tests (§18.3). Baker et al. 2025 caught a frontier reasoning model doing this during training on coding tasks, by having a second model read its chain of thought (§18.1).
- Exfiltration. Any secret in the environment, such as an API key in an environment variable or a cloud credential on the disk, is one
printaway from the context and one network request away from the outside world. - Resource abuse. An infinite loop, a fork bomb (a program that copies itself until the machine runs out of processes), a 50 GB file, or a cryptocurrency miner.
- Escape. Code that breaks out of the isolation and reaches the host machine, and through it every other user's sandbox.
The isolation boundary is where the options differ most, so here they are from weakest to strongest. The differences all come down to the kernel, the core of the operating system. Every other program asks the kernel for files, memory, and network access, through requests called system calls.
- A process shares everything with the host except what you take away. You take things away with resource limits (rlimits) and a filter on system calls (seccomp).
- A container gives the code its own view of files, processes, and the network (Linux namespaces) and caps its resources (cgroups). But it still runs on the host's kernel, so a bug in that kernel is an escape.
- gVisor puts a kernel written in user space between the code and the host. The code's system calls are served by gVisor rather than by the host kernel (gVisor documentation).
- A virtual machine gives the code its own kernel behind hardware virtualization (KVM on Linux). A small host program, the virtual machine monitor, emulates its devices. A microVM such as Firecracker (Agache et al. 2020) strips the virtual hardware down until a VM starts almost as fast as a container.
| boundary | how it isolates | what an escape needs | startup | typical use |
|---|---|---|---|---|
| process with rlimits and seccomp | limits and a system-call filter in the host kernel | a hole in the filter or the kernel | milliseconds | a second layer inside one of the others |
| container | namespaces and cgroups, shared host kernel | a host kernel bug | typically under a second | single-tenant CI, trusted code |
| gVisor | a user-space kernel intercepts system calls | a gVisor bug, then a host bug through its narrow interface | close to a container | multi-tenant code execution |
| microVM (Firecracker) | its own guest kernel, KVM hardware virtualization | a bug in the small virtual machine monitor or KVM | under 125 ms to application code | serverless, RL rollouts at scale |
| full VM | its own kernel and full virtual hardware | a bug in the hypervisor, the layer that runs the VMs | seconds or more | computer-use agents that need a whole desktop |
Stronger isolation costs startup time and compatibility. At the scale of agents it costs little else.
The other four parts of the definition are where most real incidents are prevented. Deny network access by default. When a task needs packages, route traffic through a proxy that allows only a package mirror. Mount the workspace read-write and the rest of the filesystem read-only, and keep hidden tests and graders outside the sandbox entirely. Pass no credentials through environment variables, because the first thing a curious program prints is os.environ. And limit everything, since an accidental infinite loop is far more common than an exploit.
Production sandboxes stack two layers. The outer one is a container or microVM per episode, one attempt at one task from start to finish. The inner one is a process with hard limits. The deeper box writes both out.
Training raises a different problem, which is scale. Reinforcement learning on agents often uses group baselines, as in GRPO (group relative policy optimization, §18.4). The policy makes attempts at the same task, called rollouts, and each rollout is scored against the average of its group. §24.3 applies this to agents. Every rollout needs its own sandbox, and all rollouts in a group must start from the same state.
For a language model alone, going back to any earlier state was free, since it only meant reusing an earlier prefix of text (§15.7). For a code agent, that reset has become an infrastructure system of snapshots and clones.
Stay inside the sandbox
A file tool that runs outside the sandbox must refuse paths outside the workspace, and this check is a classic place for security bugs. A symlink (symbolic link) is a file that points to another path, so a path inside the workspace can lead out of it. Implement is_within(root, path, symlinks), which returns True exactly when path resolves to root or to something under it.
rootis an absolute directory, possibly with a trailing slash. It contains no symlinks itself.pathis absolute, or relative toroot.symlinksmaps absolute link paths to their targets. A relative target is relative to the directory that contains the link.- Resolve the path the way the operating system does, one component at a time from the left. Skip empty components and
.. Let..move to the parent, never above/. Whenever the path built so far is a key ofsymlinks, replace it with its target and continue. So a..that follows a link applies to the link's target. - Allow at most 40 link expansions, as Linux does. If resolving needs a 41st, assume a loop and return
False. When in doubt, refuse.
A real system avoids checking paths with string logic when it can. It opens files relative to a directory handle and lets the kernel refuse any path that leaves it, as Linux's openat2 does with the flag RESOLVE_BENEATH. Or it runs the file tool inside the sandbox, where paths outside the workspace do not exist. But the exercise is the check that interviewers ask for, and any file tool that runs outside the sandbox must get it right.
The toy coding agent later in this section runs its code with much weaker protection than any of these, and it is worth seeing why that protection is weak. Its executor runs code in a Python namespace whose built-in functions leave out open and __import__. So the obvious ways to read a file or load a module fail.
The toy repository has a bug. Its median returns the upper of the two middle elements of an even-length list instead of their mean. The first line reproduces it (the answer is 3, not 2.5), and reading the test file or importing os fails.
That is useful hygiene against an agent's mistakes, but it is not a security boundary. Every Python object carries a reference to its class. From any object a program can walk the class hierarchy back to objects that reach the full interpreter. That is why projects that restrict Python from inside the same process have a long history of escapes. A namespace limits what an honest program can do by accident. Only an operating-system boundary limits what a hostile one can do.
An interviewer who asks you to design a sandbox wants all five parts of the definition, a reason for the boundary you chose, and the reset mechanism for training at scale.
Software engineering agents
Coding was the first domain where agents became widely used at work, for a reason the previous parts make clear. A repository comes with a cheap and mostly trustworthy reward, its test suite, and it fits naturally in a sandbox. This part covers how SWE-bench turns repositories into graded tasks, what the interface between model and repository should look like, where the numbers stand, and how coding agents are trained.
How SWE-bench is built and graded
Jimenez et al. 2023 built SWE-bench in three stages. A pull request is a proposed change to a repository, which maintainers review and merge. The authors collected about 90,000 pull requests from 12 popular Python repositories. They kept merged ones that resolve a GitHub issue and change the repository's test files, since a contributor who adds tests has written down what "fixed" means. Then they kept only those where the repository installs, the tests run, and at least one test fails before the fix and passes after it. That left 2,294 task instances.
Each instance comes with the repository at the commit just before the fix, the issue text, and two lists of tests. The tests that check the fix come from the pull request's changes to the test files, so the agent's copy of the repository does not contain them in their final form. Every instance has at least one such test, and 40% have two or more. A median of 51 existing tests check that nothing else broke.
In plain words, every test that proves the fix must pass, every old test must still pass or be skipped, and a test you cannot find in the log counts against you. XFAIL is the status that pytest, Python's standard test runner, gives a test that is marked as an expected failure and does fail. It counts as passing.
Skipped tests follow different rules in the two sets, which is how SWE-bench's grading code treated them when we read it in October 2026. A skipped old test is not a regression, but a skipped fix test proves nothing. The grading code notes that without this rule, a patch that made every FAIL_TO_PASS test skip would count as resolved.
The grading rule is strict, but it can still be wrong. Issues sometimes contain the fix. Tests can be too weak to notice a wrong patch, or so specific that they reject a right one. And frontier models have seen many of the reference fixes during training. §22.5 measures each of these and explains why OpenAI stopped reporting SWE-bench Verified in February 2026.
One more defense lives in the harness. Before running the hidden tests, SWE-bench's evaluation script restores the test files that the hidden tests change, and only then adds the hidden tests. So an agent's edits to those files are overwritten. It cannot undo edits to other files the tests depend on, such as a conftest.py, the file where pytest looks for shared test setup. A patched conftest.py can even print fake PASSED lines. So the grading code also compares the log with the exit code of the test command, and it rejects a run that exited with an error while reporting no failure. Graders also flag patches that touch test infrastructure. An interviewer who asks how SWE-bench is graded will follow up with exactly these failure modes.
Grade a SWE-bench run
Implement grade_run(instances, logs, patches, costs), the grader for a batch of task instances, by the definition above.
instances[id]is a dict with lists"FAIL_TO_PASS"and"PASS_TO_PASS".logs[id]maps test names to statuses ("PASSED","FAILED","ERROR","SKIPPED","XFAIL"), or isNoneif the patch did not apply.patches[id]is the list of file paths the patch modifies, orNone.costs[id]is the dollars spent on the instance.
Return a dict with four entries.
"resolved"maps each id to a bool, by the definition above."resolve_rate"is the fraction resolved."cost_per_resolved"is the total cost of all instances divided by the number resolved, orfloat("inf")if none was."touches_tests"is the sorted list of ids whose patch modifies a test file. A path is a test file if one of its directories is namedtestortests, or its file name starts withtest_, ends with_test.py, or isconftest.py.
The agent-computer interface
A human engineer does not fix a bug through a bare terminal. They use an editor with line numbers and a search that lists matches by file. They also use a linter, a program that checks code without running it and underlines a syntax error the moment it appears. The SWE-agent project (Yang et al. 2024) asked whether a model needs tools of the same kind, and its answer has shaped coding agents since.
SWE-agent's interface had four parts.
- Search. The commands
find_file,search_file, andsearch_dirlist every match as a file and line, return at most 50 results, and ask for a more specific query when there are more. - A file viewer. It shows 100 lines at a time with line numbers, the file's path and length, and how many lines lie above and below the window.
- An edit command. It replaces a range of lines and then shows the edited region. A linter checks the edit first, and an edit that introduces a syntax error is discarded, with the error shown to the agent.
- A history processor. It collapses every observation older than the last five into a single line.
The agent wrote a short note of reasoning and then one command per turn, the ReAct format of §24.3. Each run had a budget of $4. The paper then removed or changed one component at a time, with GPT-4 Turbo on SWE-bench Lite. An experiment of this kind, which measures what each part is worth by taking it away, is called an ablation.
Two patterns stand out. First, more context was not better context. The whole-file viewer and the full history both lost to their condensed versions. Second, a well-meant interface can do worse than none. Iterative search, modeled on an editor's "find next", scored below plain grep. The authors saw why in the transcripts. Agents called "next" until they had looked at every match, which could use up the budget or the context window.
In the widget's illustrative episode, the context at the last turn grows only about 2.5 times, from 7,913 to 20,013 tokens. With the last five observations kept, at most five of the large file views are in the context at once. The tokens read over the whole episode grow more than four times, and the resolve rate falls from 18.0% to 12.7%. Keep everything as well and the two costs compound.
The paper never measured that combination, since it changed one component at a time. Single changes say nothing about how changes combine. When an interviewer asks how to design a coding agent's tools, the lesson to give is that short, informative observations beat more context.
A history processor that keeps calls and results paired
The history processor is the cheapest of the four parts to build. It is also a common interview task, because the obvious version breaks the conversation. In the chat formats of the major APIs, an assistant message carries its tool calls, each with an id, and each result names the id it answers. In OpenAI's format a result is a tool message, and in Anthropic's it is a tool-result block. Both APIs reject a request in which a call has lost its result or a result has lost its call. So a history processor may shorten old results, but it must never drop them.
Parallel calls add a trap. Their results can come back in any order, so the command behind a result must be found by its id, never by its position.
There is also a cost that is easy to miss. A prompt cache stores the model's work on the start of a request. A later request reuses that work only up to the first message where the two requests differ (§24.6). A sliding window rewrites an old message on every turn, so the reusable part stops at the message that was just collapsed.
A history processor
Implement the two functions of a history processor like SWE-agent's, over chat messages. A message is a dict with "role" ("system", "user", "assistant", or "tool") and "content". An assistant message may have "tool_calls", a list of {"id", "cmd"}. A tool message has "tool_call_id", the id of the call it answers. The setup defines msg_tokens(m) and an example episode, make_episode().
collapse_history(messages, k) returns (new_messages, tokens).
- The newest
ktool messages stay exactly as they are. Treat anykbelow 1 as 1, so the newest tool message is never collapsed. - Every older tool message gets the content
f"(output of {cmd} omitted, {n} lines)", wherecmdis the command of the call with itstool_call_idandn = len(content.splitlines()). If that placeholder is not shorter than the original content, keep the original. - Every message keeps its position, role, and ids, and system, user, and assistant messages are never touched. Do not modify the input.
- Raise
ValueErrorif a tool message's id matches no earlier tool call. tokensis the sum ofmsg_tokensover the new list.
first_change(prev, new) returns the index of the first message at which two requests differ. If one list is a prefix of the other, it returns the length of the shorter one. It is the number of leading messages a prompt cache could reuse.
With the example episode shrinks from 833 tokens to 339. On the next turn the request first differs from the previous one at message 6, the file view that has just left the window. Everything from there on must be written to the cache again. A real transcript has thousands of tokens after that point. So a processor that collapses one observation per turn pays a cache write on most of the context every turn.
Production systems therefore clear old results in batches, and only when a clear removes enough tokens to pay for the rewrite. §25.2 derives that trade-off. It also gives the general form of this exercise, which clears tool results but leaves a reference to each, such as the file path, so the agent can fetch it again.
What still holds in 2026
Are these lessons still true when a harness with only a shell reaches 76.8% on SWE-bench Verified? The specific numbers belong to GPT-4 Turbo. Stronger models, trained heavily on tool use and able to use long contexts, need less help from the interface. But the principles have survived in production harnesses.
- Observations are short and informative, and long outputs are truncated with a note. Claude Code limits a tool response to 25,000 tokens by default (Anthropic 2025).
- Error messages say what to do next.
- Guardrails stop mistakes from compounding, which matters because a long task fails if any one of its many steps fails (§24.1).
- Small details matter. Anthropic's SWE-bench agent made mistakes with relative file paths until the tool required absolute ones (Anthropic 2024).
The edit command most agents use today replaces an exact string rather than a range of line numbers. The agent gives the old text and the new text, and the edit succeeds only if the old text occurs exactly once. Line numbers go stale the moment an earlier edit adds a line, while a unique string is its own address. The uniqueness rule turns an ambiguous edit into an error the agent can fix by quoting more of the surrounding code. Anthropic's text editor tool uses this convention, with a "view" command that shows line numbers for reading.
The editor tool
Implement the two commands of a string-replacement editor, a windowed view and a unique-match str_replace, the way coding-agent interviews ask for them.
view(text, start=1, window=100) shows lines start to start + window - 1, counting from 1 and stopping at the last line.
- Format each shown line as
f"{i:6d}\t{line}". - If lines are hidden above, the first output line is
"(k more lines above)". If lines are hidden below, the last is"(k more lines below)". - An empty file gives
"(empty file)", and astartoutside1..ngives a message starting with"error". Usetext.splitlines().
str_replace(text, old, new) returns (new_text, message).
- If
oldoccurs exactly once, replace it and return a message that starts with"ok"and contains"line L", the line where the match starts. - Otherwise return the text unchanged with a message that starts with
"error". For no match, the message contains"no match". For several, it contains"k matches"and"line L"for every match. - An empty
oldis an error. Overlapping occurrences count, so"aa"occurs twice in"aaa".
A small coding agent, end to end
Now put the pieces together. The cells below are a small coding agent on the toy repository from the sandbox part, whose median returns the upper middle element instead of the mean of the two middle ones. The agent has a summarized search, a windowed viewer, a unique-match editor, and the restricted executor for running code. Its scripted policy does what good agents do, in this order.
- Find the function the issue names.
- Open it.
- Reproduce the bug before touching anything.
- Edit.
- Check that the reproduction now gives the right answer, and submit.
Then the grader runs the three tests in tests/test_core.py, which the agent never opened. In SWE-bench terms, test_median_even is the FAIL_TO_PASS test and the other two are PASS_TO_PASS tests.
The loop gives every action an observation, and the grader is the SWE-bench rule in miniature.
The reproduction step is the one to notice. An agent that edits before reproducing cannot tell a fix from a coincidence. One that writes and runs a reproduction has a check that tells it when to stop. §24.1 showed that such checks are worth as much as accuracy over a long task, because a long task fails only on the errors that are not caught and repaired. Interviewers who ask you to design a coding agent listen for exactly this step.
A fixed pipeline, and the 2026 numbers
In mid-2024 a paper asked whether an agent loop is needed at all. Recall the distinction of §24.1. In a workflow, code fixes the sequence of steps and the model only fills in content. In an agent, the model chooses the next step. Agentless (Xia et al. 2024) replaced the agent loop with a workflow of three fixed phases.
- Localization narrows the repository to files, then to classes and functions, then to the lines to edit, using prompts and embedding retrieval.
- Repair samples candidate patches as search-and-replace edits, ten for each of four sets of locations, so 40 per issue with GPT-4o.
- Validation writes tests that reproduce the issue, runs them and the existing tests on every candidate, and discards the failures. It normalizes the survivors, ignoring whitespace and comments, and submits the most common one by majority vote.
Agentless resolved 32.00% of SWE-bench Lite (96 issues) at $0.70 per issue, more than every open-source agent of the time. The reason is that errors compound over steps (§24.1). With 2024's models, every extra decision an agent made was another chance to wander off. A pipeline that makes the decisions in code, samples many candidates, and lets tests choose among them removed most of those chances.
As models became more reliable per step, the balance moved back toward agents, which can explore, run anything, and recover. But the pipeline's central idea survived inside them, which is to sample several attempts and let tests choose.
By February 2026, comparing models fairly meant holding the harness fixed. The SWE-bench leaderboard's "bash only" view runs every model in the same minimal agent, mini-SWE-agent, whose only tool is a shell.
The four rows are within 1.2 points of each other and a factor of ten apart in price. That is the trade-off between cost and accuracy that §22.5 asks every agent evaluation to report. The leaderboard also publishes per-instance results, and two more facts come out of them (our analysis of those files).
- Failures cost more than successes. For Claude Opus 4.5, unresolved instances cost $1.16 on average against $0.63 for resolved ones, with a median of 38.5 model calls against 26.5. That is what you would expect if a stuck agent keeps trying until its budget runs out.
- The models fail on different issues. At least one of the four models resolves 428 of the 500 instances, 85.6%. All four resolve only 323.
That gap between "some attempt succeeds" and "the one attempt we submit succeeds" is the subject of the next part.
Sampling many patches and choosing one
§18.2 separated two questions about many samples. Coverage asks whether any of samples is right. Selection asks whether you can pick the right one. Coding agents live on that distinction.
With the hidden tests in hand, coverage is pass@, the probability that at least one of candidate patches resolves the issue. At deployment the hidden tests are not available. A system must choose with what it has. That may be reproduction tests it wrote itself, the existing tests, a learned verifier (a model that scores patches), or a vote. What it achieves is best-of-, the probability that the candidate it submits is correct.
Here is a simple model of a verifier. It gives every candidate a noisy score, and the system submits the candidate with the highest score. A correct patch scores and a wrong one scores . Here is an independent standard normal draw for each candidate, is the margin by which correct patches score higher on average, and is the noise.
Issue has its own probability that one sample is correct. On real benchmarks these probabilities pile up near 0 and near 1, with many issues almost always solved and many almost never. The cell draws 500 such issues and measures both curves, with .
Coverage climbs from 0.399 to 0.786 at 32 candidates. With the verifier keeps much of that gain, reaching 0.721. With it reaches 0.607, about half of the gap, and with only 0.475. Every curve starts at pass@1 (up to sampling noise), because with one candidate there is nothing to choose. None can exceed pass@, because a verifier cannot select a correct patch that nobody wrote.
This is why SWE-Gym (Pan et al. 2024) trained a verifier on agent transcripts alongside the agent, and reached 32.0% on SWE-bench Verified with it. It is also why every system that samples heavily spends as much effort on selection as on generation. When an interviewer asks how to spend more compute at test time, give this answer. More samples raise the ceiling, and a better verifier decides how close you get to it. The exercise computes these curves exactly.
Test-time scaling with a verifier
Compute the two curves of the cell above exactly, for the verifier model just described. Implement bon_curve(p, n_max, margin, sigma), which returns two arrays of length n_max, bon and cov, where entry n - 1 refers to candidates.
- Issue 's candidates are independently correct with probability
p[i]. - A correct candidate's score is distributed as and a wrong one's as , independently, with =
margin. Best-of- submits the highest-scoring candidate. cov[n - 1]is the mean over issues of pass@, andbon[n - 1]is the mean over issues of the probability that the submitted candidate is correct.
Compute both exactly, with no Monte Carlo sampling. Handle sigma == 0, where any correct candidate outscores every wrong one, and stay accurate as sigma shrinks toward 0.
Training coding agents
A repository with tests is a complete reinforcement-learning environment. The state is the repository and the processes in the sandbox. An action is a command or an edit, and an observation is its output. The reward arrives once, at the end, from the hidden tests. Training uses two tools from earlier in the chapter.
- The token source mask. Each transcript is stored with a mask that is 1 on tokens the policy sampled and 0 on every other token, including everything a tool wrote (§24.1). The loss uses only tokens with . So the thousands of tokens of file contents and test logs carry no policy gradient.
- Group baselines. Each rollout's advantage, how much better it did than expected, comes from comparing it with the other rollouts on the same issue, as in GRPO (§18.4). An issue that every rollout solves, or none does, therefore contributes no signal.
The hard part is the data, a working environment for every task in which the tests actually run. Three published answers span the options.
- Real issues with real environments. SWE-Gym (Pan et al. 2024) built 2,438 task instances from 11 Python repositories, each with an executable environment and tests. Fine-tuning on agent transcripts in it raised resolve rates by up to 19 points absolute. Adding a verifier trained on the same transcripts reached 32.0% on SWE-bench Verified.
- Synthesized bugs. SWE-smith (Yang et al. 2025) turns the problem around. Start from a repository whose tests pass, and break it. A model can rewrite or subtly corrupt a function, a program can change the syntax tree, a past pull request can be undone, or several bugs can be combined. Every change that makes some test fail is kept, and the failing tests become its FAIL_TO_PASS set.
- No execution at all. SWE-RL (Wei et al. 2025) runs reinforcement learning on the history of pull requests. The reward is for a malformed answer. Otherwise it is the textual similarity between the model's patch and the merged one, measured with Python's
difflib.SequenceMatcher. That needs no sandbox and scales to the whole history of open source, and Llama3-SWE-RL-70B reached 41.0% on SWE-bench Verified. The price is that the reward pays for resembling one particular fix. A different correct fix scores low, and a near-copy that fails its tests scores high.
The choice is a trade between realism and scale. Real issues are the most faithful and the most expensive to set up, synthesized bugs scale to tens of thousands of tasks, and similarity rewards need no sandbox but pay for the wrong thing.
The reward is also an attack surface. A policy optimized against tests learns whatever makes them pass, and the cheapest route is often not a fix. The hacks seen in practice are the ones §18.3 catalogued. They are exiting before the assertions run, special-casing the tested inputs, editing or deleting tests, and patching the test framework. The defenses follow from that list.
- Keep hidden tests outside the sandbox, and restore any test files before grading.
- Flag and inspect patches that touch test infrastructure, as the
touches_testslist of Exercise 24.5b does. - Hold out tests that the policy never sees during training.
- Measure cheating directly with tasks that are impossible by construction, as §22.5 describes, since any pass on an impossible task is a hack.
An interviewer who asks why a coding agent's reward went up while its patches got worse wants this list, in this order.
A 2026 coding-agent harness
The single shell of mini-SWE-agent is a measuring instrument. It holds the harness fixed so that models can be compared. The coding agents that engineers use every day wrap the same loop in much more machinery. Examples are Claude Code, OpenAI's Codex, and the open-source OpenHands. The authors of CodeAct are among OpenHands' developers, and its default agent acts with code actions inside a Docker container. "Design a coding agent" has become a standard interview question, and the machinery is not arbitrary. Each component answers a problem this chapter has already measured.
The table lists the components and the reason for each. Product details change every few months, and the deeper box below records how the shipping products implemented each component on October 20, 2026. The reasons do not change.
| component | what it does | why it is there |
|---|---|---|
| repository memory file | a markdown file of build and test commands, conventions, and warnings, loaded at the start of every session | it is part of the prompt that every turn reads (§24.1), so it must be short and stable to stay in the prompt cache (§24.6) |
| plan or to-do tool | a list of steps with statuses that the agent writes and updates as it works | a plan that is checked and revised (§24.4), and progress the model restates, so compaction cannot lose it (§25.2) |
| view, search, and string-replace edit | windowed reads with line numbers, search that lists matches, unique-match edits | the agent-computer interface of this section and Exercise 24.5c |
| a shell in a sandbox | builds, tests, git, and anything else the task needs | code actions need an operating-system boundary (the sandbox part of this section), and running the tests is the detection step of §24.1 |
| read-only subagents | explore the repository in a fresh context and return a summary | context isolation (§25.2, §24.7), and an explorer that cannot write cannot break anything |
| permission modes and rules | decide which calls run, which ask a person, and which are refused | a program's effects cannot be checked in advance, so approval moves into the harness, the permission engine of §24.6 |
| hooks | deterministic code run at fixed events, able to block a tool call | rules that must hold whatever the model decides, such as refusing edits under tests/ (the reward-hacking defense above) |
| compaction | near the context limit, clear old tool outputs, then summarize | the history processor of Exercise 24.5f, treated in general in §25.2 |
| checkpoints | snapshot each file before an edit so the edit can be rewound | retries and search need a way back (§24.4) |
| background and cloud runs | run a task asynchronously, in its own machine | a long task needs its own sandbox and durable state (§25.4) |
One principle organizes the whole design. Whatever the model reads, it may or may not obey, and only the harness decides what actually happens. Claude Code's documentation says this of its own memory files. It treats them as context rather than as enforced configuration, and it points to a PreToolUse hook for anything that must be blocked.
So conventions go in the memory file. Rules that must hold go in permission rules and hooks, such as never pushing to the main branch, never editing tests during a training episode, or never reading ~/.ssh. The sandbox is the last line of defense when both fail. A memory file is also text that came with the repository, so a hostile one is an injected instruction (§19.3). That is why Claude Code asks before it loads imports that point outside the project.
The same harness, given a budget of hours or days rather than minutes, can run a machine-learning project. Agents that run whole research projects, from proposing an experiment to writing it up, are measured on benchmarks such as MLE-bench. §26.5 reads those benchmarks and the evolutionary coding systems built on the same loop.
Computer and browser use
Most software has no API, no programming interface an agent can call. Booking systems, internal dashboards, spreadsheets, and design tools are built for people, who look at a screen and use a mouse and keyboard. A computer-use agent does the same. Its actions are a user's actions, which are moving the pointer to and clicking, typing a string, pressing a key combination, scrolling, and dragging. Its observations are what the screen shows. The hard design question is what form "what the screen shows" should take.
| format | what the agent sees | tokens per step | how it points | how it fails |
|---|---|---|---|---|
| raw HTML | everything in the markup, little of the layout | often tens of thousands or more on real pages | by element id or selector | too long; misses canvases and rendered state |
| accessibility tree | roles, names, and boxes of interactive elements | hundreds to a few thousand | by element number | apps with poor accessibility data; no visual detail |
| set-of-mark | the pixels plus numbered elements | an image plus a short legend | by mark number | marks clutter small elements; needs element detection |
| raw screenshot | the pixels only | one image (1,560 to 2,691 tokens at 1920 by 1080 on Claude) | by pixel coordinates | grounding errors, coordinate scaling bugs |
The benchmarks show the trade-offs moving over time. OSWorld (Xie et al. 2024) put agents in full virtual machines with 369 tasks across desktop and web applications. Each task is checked by a script that inspects the final state of the machine. At its release, people solved 72.36% of the tasks. Among the models, a text-only one reading the accessibility tree did best, GPT-4 at 12.24%. GPT-4V managed 5.26% on raw screenshots and 11.77% with set-of-mark. The authors named GUI grounding, turning "click the Save button" into the right coordinates, as a main cause of failure.
Grounding, and the coordinate bug
Grounding is the step from an intended element to an action the computer accepts. With an accessibility tree it is a lookup, since element 12 has a bounding box and the agent clicks its center. With a raw screenshot the model itself must output pixel coordinates, and two separate things can go wrong. The model can misjudge where the element is, a perception error that training on large amounts of screen data reduces. Or the system can misread the coordinates the model gave, a plain software bug that no training fixes.
The bug comes from downscaling. Providers shrink large images before the model sees them, and the model answers in the coordinates of the image it saw. On Claude's standard resolution tier, the documented rule shrinks a 1920 by 1080 screenshot to 1456 by 819. That is the largest size with the same aspect ratio that fits two limits, 1,568 pixels on the long edge and 1,568 tokens for the image (Claude vision documentation). Scaling only to the edge limit would give 1568 by 882, which is wrong, and the documentation warns about exactly this.
The widget below plays this example on screens of four sizes and on both tiers. Switch between using the model's coordinates as given and mapping them back.
So a computer-use agent that "cannot click straight" may have a perfect model and a broken harness. Interviewers like this bug because it separates people who have built such an agent from people who have only read about one.
Serialize a screen for the model
Implement two functions that sit between a computer and a computer-use model. The first turns an accessibility tree into numbered lines within a character budget. The second maps a click from the model's image back to the screen.
serialize(tree, budget) takes an accessibility tree of nested dicts with keys "role", "name", "bbox" ([x0, y0, x1, y1] in screen pixels), "visible", and "children".
- List each node that has an interactive role (
button,link,textbox,checkbox,combobox,menuitem,tab,radio), is visible, has only visible ancestors, and has a box of positive width and height. - Number them 1, 2, 3, ... in document order, the order of a depth-first walk that visits a node before its children. Write one line each as
[k] role "name". - Keep lines in that order while the text joined by newlines stays within
budgetcharacters, and stop at the first line that does not fit. If any were cut, add a last line[+m more], which does not count toward the budget. - Return
(text, boxes), whereboxes[k]is the center of elementk's box as a tuple of two floats, for every listed element including the cut ones.
to_screen(x, y, model_size, screen_size) maps a click from the model's image to the screen. With model_size = (wm, hm) and screen_size = (ws, hs), return (floor(x * ws / wm + 0.5), floor(y * hs / hm + 0.5)), clamped to 0..ws - 1 and 0..hs - 1.
What screenshots cost
Images are expensive, and the loop makes them more so. Claude prices an image by patches. After any downscaling, an image of by pixels costs
visual tokens, one per 28 by 28 block of pixels. Claude 4.7 and later models use a high-resolution tier, with limits of 2,576 pixels on the long edge and 4,784 tokens, so they take a 1920 by 1080 screenshot at full size. It costs tokens there. On the standard tier it shrinks to 1456 by 819 and costs tokens. §27.1 explains the idea of cutting an image into patches, and §31.5 covers how open vision-language models turn images into tokens.
The cost of one screenshot is only the start, because every turn reads again the screenshots it keeps. Suppose an agent takes one screenshot per turn for turns, and turn reads the last of them, for some . With and the turns read 1, 2, 3, 3, and 3 screenshots, 12 in all.
∂ Proof
For turn reads screenshots, which sum to . For each of the remaining turns reads , which adds . The total is . With this is . Check with and , which gives , as counted above. ∎
In plain words, keeping every screenshot makes the cost grow with the square of the number of turns. That is the same growth as the transcript's token count in §24.1. Keeping the last makes it grow linearly, about screenshots per turn.
This is the screen version of the coding result above, where keeping only the last five observations beat keeping them all. §25.2 treats context trimming in general. The cell checks the sizes and totals.
The cell confirms both image sizes and both totals. The widget plots how many observations each turn reads, so the shaded area is the episode's total. Press Play to watch an episode grow, then vary the format, the number of turns, and how many observations are kept.
Here is the patch arithmetic in PyTorch, the way a vision encoder cuts an image into tokens. Pad the image on the bottom and right to multiples of 28. Unfold it into non-overlapping 28 by 28 blocks, and project each block's numbers to one embedding. How any particular provider's encoder embeds the patches is not public, but the count is the one the formula gives.
Native agents, many rollouts, and where the numbers stand
The first computer-use systems wrapped a general model in prompts and added a separate model for grounding. A native agent is one model trained end to end to see screens and act on them, which removes the hand-off between a planning model and a separate grounding model.
The biggest jump came from choosing among attempts rather than from a better model. A single computer-use rollout is brittle, since small errors compound over a long episode, and different rollouts fail in different places. That is the same coverage gap as on the SWE-bench leaderboard. Agent S3 with Behavior Judge (Gonzalez-Pumariega et al. 2025) runs several rollouts and turns each into a short narrative of what the agent did and what changed on the screen. A judge model, a language model asked to compare outputs (§22.4), reads the narratives and picks one. The system reached 72.6% on OSWorld, above the 72.36% human figure.
Computer use inherits every threat of the sandbox part and adds one. The agent reads web pages, so every page is a possible prompt injection (§19.3). An agent with a logged-in browser holds exactly the private data and the outbound channel that make the lethal trifecta dangerous. So run it in a virtual machine with no saved credentials. Require a person's approval for purchases, messages, and deletions. And evaluate it for dangerous autonomous and cyber capabilities before deployment (§19.4).
Where it breaks
- Benchmarks drift away from the work. Leaked fixes, weak or overly specific tests, contamination, and websites that change after a benchmark is written all move scores without moving ability (§22.5).
- Tests that do not test the fix. A patch that passes FAIL_TO_PASS can still be wrong if those tests are narrow, and reinforcement learning against such tests pays for wrong code.
- Agents that edit the grader. Test edits, framework patches, and early exits, unless the tests live outside the agent's reach.
- Sandbox escapes and leaks. Restrictions inside the same process, path checks by prefix, secrets in the environment, and unrestricted outbound network access.
- Grounding. Clicks that miss because the model misjudged the element, or because the system forgot to rescale its coordinates.
- Context. Screenshots and file contents dominate the context unless old observations are dropped or condensed, and every turn reads again what is kept.
- Rules the harness does not enforce. An instruction in a memory file or a prompt is a request the model may ignore, and an injected file can countermand it. Anything that must hold belongs in permissions, hooks, and the sandbox.
Read more
- Wang et al. (2024). Executable Code Actions Elicit Better LLM Agents. CodeAct, the M³ToolEval comparison of code, JSON, and text actions, and the training data for code agents.
- Jimenez et al. (2023). SWE-bench: Can Language Models Resolve Real-World GitHub Issues?. How 90,000 pull requests became 2,294 graded tasks, and the FAIL_TO_PASS and PASS_TO_PASS design that most coding benchmarks copy; current results are on the SWE-bench leaderboards.
- Yang et al. (2024). SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering. The agent-computer interface, its commands, and the ablations that showed interface design matters.
- Xia et al. (2024). Agentless: Demystifying LLM-based Software Engineering Agents. The fixed localize, repair, and validate pipeline that matched the agents of 2024, and a careful look at flawed benchmark tasks.
- Yang et al. (2025). SWE-smith: Scaling Data for Software Engineering Agents. Synthesizing training environments by breaking working repositories; compare Pan et al. (2024), Training Software Engineering Agents and Verifiers with SWE-Gym, and Wei et al. (2025), SWE-RL.
- Xie et al. (2024). OSWorld: Benchmarking Multimodal Agents for Open-Ended Tasks in Real Computer Environments. Real virtual machines, execution-based checks, and the comparison of screenshots, accessibility trees, and set-of-mark; read with Gonzalez-Pumariega et al. (2025), Scaling Agents for Computer Use.
- Agache et al. (2020). Firecracker: Lightweight Virtualization for Serverless Applications. The microVM design behind fast, strongly isolated sandboxes.
- Anthropic (2025). Writing effective tools for AI agents. Practical interface design for agents, from response formats and truncation to evaluation-driven tool improvement; read with the Claude Code documentation's How Claude Code works for a whole production harness.