# Model routing

Kestrel scores each step before it runs and sends it to the smallest model that can do it. Renames go to a small model; only the hard reasoning reaches a large one.

![Steps flow into the router. Most go to the small model, some to the medium one, and the rare hard step goes to the large one.](/illos/model-routing.svg)

## How a step is scored

Before each step, Kestrel scores how hard it is from 0 to 1, from what the step asks for and how earlier steps like it went. Then it picks the model for that score.

```yaml kestrel.yaml
routing:
  small:  score < 0.4    # 72% of steps
  medium: score < 0.8    # 21%
  large:  score >= 0.8   # 7%, the hard ones
```

Most of a run is reading files, renaming things and running tests. Those steps score low, which is why routing cuts the token part of a run's cost by about two thirds.

## Pick the models

```yaml kestrel.yaml
routing:
  models:
    small: claude-haiku
    medium: claude-sonnet
    large: claude-opus
```

## Force a model for one run

```ts TypeScript
await kestrel.runs.create({
  repo: "acme/web-app",
  task: "Untangle the billing state machine",
  routing: { floor: "medium" }, // never use the small model on this run
});
```

```python Python
kestrel.runs.create(
    repo="acme/web-app",
    task="Untangle the billing state machine",
    routing={"floor": "medium"},  # never use the small model on this run
)
```

> [!NOTE]
> Every step in a [trace](/runs/traces) shows its score and the model it went to, so you can see where the tokens went.
