# Run traces

Each run records its steps as a trace: every file read, every tool call and every test, on one time axis. The slow step is obvious at a glance.

![A playhead moves along the run. Each step sits on the time axis with its tool calls under it; the test step takes most of the run and is marked slow, and the pull request opens once the evals finish.](/illos/run-trace.svg)

## Read a trace

Every run has a trace from the moment it leaves the queue. Open it in the dashboard, or print it in the terminal:

```bash Terminal
kestrel trace run_8f2c

run 8f2c · fix flaky checkout test                         PR opened
step                     model    time
read_repo                small     2.1 s
plan_fix                 large    14.8 s
edit checkout.test.ts    medium    6.3 s
run_tests                none     48.2 s   slow
evals                    small     7.5 s
```

## What a step records

| Field | Example |
|---|---|
| `name` | `run_tests` |
| `model` | `medium`, or `none` for steps without a model |
| `score` | `0.62`, the [routing](/agents/routing) score |
| `durationMs` | `48200` |
| `toolCalls` | Each call with its input and output |
| `tokens` | Input and output tokens for the step |

## Get it from the SDK

```ts TypeScript
const trace = await kestrel.runs.trace("run_8f2c");
const slowest = trace.steps.toSorted((a, b) => b.durationMs - a.durationMs)[0];
console.log(slowest.name, slowest.durationMs); // "run_tests", 48200
```

```python Python
trace = kestrel.runs.trace("run_8f2c")
slowest = max(trace.steps, key=lambda s: s.duration_ms)
print(slowest.name, slowest.duration_ms)  # "run_tests", 48200
```

## Send traces to your own tools

Traces export as OpenTelemetry spans. Add an endpoint and every run is sent as it ends.

```yaml kestrel.yaml
traces:
  export:
    otlp: https://otel.acme.dev/v1/traces
```

> [!NOTE]
> Traces are kept for 7 days on Hobby, 90 days on Team and a year on Enterprise.
