# Learned code (research preview)

Turn what Sai did into Simulang code you own, run it without the agent, and repair it when it breaks.

Sai solves a task by looking at the screen and deciding each step. Once it has solved a task, you can turn what it did into a Simulang function and run that function again with new inputs, without the agent. The code is faster and cheaper to run, and you can read it, test it and keep it under version control. When the code breaks, Sai repairs it from what went wrong.

The loop has four calls, and you run each one yourself:

1. **Record.** Send the task to [`POST /message`](/documentation/api-reference/message) with `options.recordTrajectory: true`, ideally as a template with inputs, so the inputs are named:

   ```json
   {
     "message": "Open {{site}} and read the title of the top story",
     "options": { "inputs": { "site": "https://news.ycombinator.com" }, "recordTrajectory": true },
     "wait": false
   }
   ```

2. **Learn.** [`POST /v1/agents/learn`](/documentation/api-reference/learn) with the turn's id returns `async function main(params = { site: "..." })`, the template and the parameters. A clarification you sent during the task, or a follow-up turn, can be included by listing its turn too.
3. **Run.** Open a [control lease](/documentation/api-reference/control) and run the code with new inputs: `await main({ "site": "https://lobste.rs" })` as the block's last line. The block's result is what `main` returns. The code throws `needs_sign_in: <site>` when the computer is not signed in, and `precondition_failed: ...` when it starts on the wrong screen.
4. **Judge and repair.** Check a run yourself, or with [`POST /v1/agents/judge`](/documentation/api-reference/judge). When it failed, call `learn` again with the code as `initialCode` and the run as an evaluation. If the code cannot handle a case at all, send the template to `POST /message` with those inputs, let Sai solve it, and pass that new turn to `learn`: the repair adds what the code was missing.

In the SDKs:

```python
learned = sai.learn.create([turn])
with sai.control.open(machine=pc) as lease:
    r = lease.run(learned, {"site": "https://lobste.rs"})
    if not r.ok:
        learned = sai.learn.create(
            initial_code=learned.code,
            evaluations=[Evaluation(inputs={"site": "https://lobste.rs"}, result=r, passed=False)],
        )
```

## What the code can do

Learned code runs in a control lease, so it can do what [direct control](/documentation/concepts/direct-control) can: the screen, apps, the browser, the shell, files, and `callLLM` to answer a question about the screen (billed to your account). It cannot ask a person anything mid-run. `showMessageToUser` writes a line to the run's `logs`.

## Limits of the preview

- `learn` reads the steps, the agent's reasoning, their results and the final answer, not the screenshots.
- One experience per call: turns from one session. Several demonstrations of the same task come later.
- One exec runs for at most 300 seconds. For a longer task the code is split into step functions you call in separate execs.
- `learn` never runs the code; you do, so you see each step.
- The default model is `anthropic/claude-opus-5-5`. A conversion takes about two minutes.
