---
title: Transcripts
description: >-
  The transcript.jsonl file every attempt writes, its event types and their
  fields.
---
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reeval.ai/llms.txt
> Use this file to discover all available pages before exploring further.

Every attempt writes `transcript.jsonl`: one JSON object per line, for each prompt, each thing the agent did, and the end of each turn.

```text
{"ts":"2026-09-26T17:40:57.860Z","atMs":0,"turn":0,"type":"prompt","text":"Create greet.js exporting greet(name) that returns \"Hello, <name>!\", and greet.test.js that tests it with node:test. No dependencies."}
{"turn":0,"ts":"2026-09-26T17:41:01.984Z","atMs":4124,"type":"reasoning","text":"I'll create greet.js exporting a greet(name) function and greet.test.js using node:test. No dependencies are needed.","durationMs":44}
{"turn":0,"ts":"2026-09-26T17:41:02.107Z","atMs":4247,"durationMs":323,"type":"file-edit","toolCallId":"tool_4a0edce3-d2af-4c58-8fe6-9494ce0981f","path":"greet.js","kind":"create","added":5,"removed":0}
{"turn":0,"ts":"2026-09-26T17:41:02.115Z","atMs":4255,"durationMs":432,"type":"file-edit","toolCallId":"tool_59d79d2c-e05e-4c4f-93c6-711b425c6a2","path":"greet.test.js","kind":"create","added":8,"removed":0}
…
{"ts":"2026-09-26T17:41:06.125Z","atMs":8265,"turn":0,"type":"turn-end","status":"completed","durationMs":8265}
```

That's a real Cursor attempt, trimmed. The same events are in `c.send()`'s `turn.transcript` and in Studio's Transcript tab.

## Where it is

Next to the attempt's other files (`diff.patch`, `judge-input.json`, …), in the run's folder under `.reeval/runs/`, and in the history folder when the run is recorded. The folders are slugs of the eval id and cell key:

```text
.reeval/runs/<runId>/<eval slug>/<cell slug>/<n>/transcript.jsonl
evals/.history/<runId>/<eval slug>/<cell slug>/<n>/transcript.jsonl
```

`history.artifacts` in the config decides which attempts keep it in history: `all` (default), `failures` or `none`.

## Common fields

<Property name="type" type="string">
  The event type, below.
</Property>

<Property name="turn" type="number">
  The turn it belongs to, from 0.
</Property>

<Property name="ts" type="string">
  When it happened, as an ISO timestamp.
</Property>

<Property name="atMs" type="number">
  Milliseconds since the turn started.
</Property>

<Property name="durationMs" type="number | null">
  How long it took. `null` when the harness never reported the end. `error` events have none.
</Property>

## Event types

<Property name="prompt" type="{ text }">
  The prompt of a turn, first in each turn. `atMs` is 0.
</Property>

<Property name="text" type="{ text }">
  A message from the agent. The last `text` of a turn is its final message, whole (the record cuts it at 8 KB).
</Property>

<Property name="reasoning" type="{ text }">
  The agent's reasoning, when the harness reports it.
</Property>

<Property name="file-edit" type="{ toolCallId, path, kind, added, removed }">
  A file the agent created, modified or deleted. `kind` is `create`, `modify` or `delete`. `added` and `removed` are line counts, or `null` when the harness didn't send the content (deletes, for example).
</Property>

<Property name="tool" type="{ toolCallId, tool, input, output, ok }">
  Any other tool call, merged with its result: the harness's tool name (`bash`, `glob`, `mcp__docs__search`), its input and output as the harness reports them, and whether it succeeded.
</Property>

<Property name="web-search" type="{ toolCallId, query, references, ok? }">
  A web search. `references` is how many sources the harness says it used, or `null`. `ok` is whether it succeeded; a refused search (egress 403, a tool error) is still a `web-search` with `ok: false`. Absent `ok` means it succeeded.
</Property>

<Property name="web-fetch" type="{ toolCallId, url, ok }">
  A fetched URL, and whether the fetch succeeded.
</Property>

Cursor's SDK leaves web search and fetch calls out of its stream: Cursor's backend runs them on its own servers. reeval's adapter recovers them after each turn from the agent's stored conversation, with the backend's own times, so they're normal `web-search` and `web-fetch` events.

When it can't (the store is unreadable, or the turn ended before the result), the turn has `unreported: ['web-search', 'web-fetch']`, the record's `activity.webSearches` and `webFetches` are `null` rather than 0, and the web matchers refuse the turn. Cursor reports file edits relative to the workspace, with line counts.

<Property name="retry" type="{ message }">
  A model call that failed while the turn went on: the agent retried it. Antigravity's CLI retries a call Gemini refuses or drops mid-reply, up to 9 times; each retried attempt is a `retry` event, and its partial reply isn't a `text` event. The call that ends the turn is its `error`.
</Property>

<Property name="error" type="{ message }">
  An error the harness reported. The turn usually ends with status `error`.
</Property>

<Property name="turn-end" type="{ status, durationMs }">
  The end of a turn: `completed`, `aborted` or `error`, and the turn's length. `atMs` equals `durationMs`.
</Property>

A real `error` event, from a Claude Code attempt on an account without credit:

```text
{"turn":0,"ts":"2026-09-26T17:09:11.329Z","atMs":1184,"type":"error","message":"Credit balance is too low"}
```

## Tokens and the served model

Token usage isn't in `transcript.jsonl`. Where the harness reports it (`cursor()`, `claudeCode()`, `antigravity()`, `opencode()`, `pi()`, `codex()`, `fx()` and `grokBuild()` do; `goose()` doesn't), each turn in the run record, and each `Turn` from `c.send()`, has `usage` and `model`. These fields are from a real Cursor turn in the record:

```text
{"status": "completed", "durationMs": 9390, "usage": {"input": 24432, "output": 371, "cacheRead": 19574, "cacheWrite": 0, "reasoning": null}, "model": "composer-2.5[fast=false]"}
```

<Property name="usage" type="{ input, output, cacheRead, cacheWrite, reasoning } | null">
  Tokens the turn used. `input` is uncached input; `output` includes `reasoning`, its share of thinking, which is `null` when the harness doesn't split it out. `null` when the harness reports no usage.
</Property>

<Property name="model" type="string | null">
  The model the harness says served the turn. Cursor's includes its parameters, such as `composer-2.5[fast=false]`. It can differ from the model you asked for.
</Property>

Each attempt sums its turns' `usage`, and the run's `cost` has the total; reeval prices no models, so there's no USD.

`reeval query`'s `attempts` table has the same numbers as `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_write_tokens`, `reasoning_tokens` and `served_model`. The run summary and the studio show them on each attempt line and, summed over counted attempts, on each cell. A harness that reports none (`goose()`) leaves the field blank, never `0`.

## Large outputs

A tool output over 128 KB keeps its first 96 KB and last 16 KB, with a marker between them giving the characters left out and the whole output's sha256:

```text
[reeval: truncated <n> of <total> characters, sha256 <hash>]
```

## Raw transcripts

```bash
REEVAL_RAW_TRANSCRIPT=1 npx reeval run greet
```

With `REEVAL_RAW_TRANSCRIPT=1`, each attempt also writes `transcript.raw.jsonl`: every stream part the harness adapter sent, unnormalised, one per line with its `turn`. It's for debugging how reeval reads a harness, and it can be large.

## Related

- [The attempt context](/reference/attempt-context)
- [The run record](/reference/record)
- [Debug data](/reference/debug-data)
- [Studio](/guide/studio)
