Skip to main content
The execution graph format represents a trace as JSON records: its opening, function calls starting and finishing, captured values, and its closing. Use the specification for the complete field definitions, emission rules, and capture bounds. The conformance corpus contains 21 fixtures with exact records, byte strings, and expected outcomes for another implementation to match.

Format version

The current format is version 2. The Python SDK writes format_version: 2 on trace-open; the other record kinds carry no version field. Version 2 adds step-open to the four record kinds in version 1. The current server accepts versions 1 and 2. A server reports its accepted versions in GET /v1/capabilities, under limits.record_format_versions. Ingest validates each record independently, without cross-checking its kind against the trace’s version stamp.

Five record kinds

Every record carries kind and trace_id. The remaining fields depend on kind: parent_name is omitted only for the root step. status on a completed attempt is ok or error; error_class is present only for error. started_us is an integer microsecond offset from the trace’s monotonic zero; duration_us is the attempt’s nonnegative integer duration in microseconds. The trace’s started_at uses UTC RFC 3339 with millisecond precision. A step-open must omit duration_us, status, error_class, continues_retry, and slots. Ingest rejects any of those keys with the per-record code invalid_record, even when the value is 0, false, or an empty object. in_flight is derived from an open record without a completion; producers do not write it as a status.

Identities and paths

A child path extends its parent’s bytes by one ordinal. Ordinals count steps, not attempts: grouped retries reuse a path and increment the zero-based attempt index. Sorting decoded path bytes produces depth-first order. The HTTP read API returns paths in opaque base32 form, not these producer hex strings. It also omits content_id from returned handles.

Values and content hashes

A completed attempt’s slots object holds the present input, output, error, and logs handles. A handle describes capture and references its bytes by content_id; the full bytes travel separately in a value record. An absent slot is an absent key. The specification defines handle rules, including the empty-logs exception. The value field is always a string. For encoding: json, it contains JSON text rather than a nested JSON object. For text, it contains UTF-8 text; for base64, it contains standard padded base64. Compute content_id as SHA-256 over the retained bytes, after truncation: UTF-8 bytes for json and text, or raw bytes before base64 encoding. JSON uses RFC 8785 canonical encoding with one source-type exception: integers retain their exact decimal digits; floats use ordinary RFC 8785 number formatting, including floats whose values are integral.

Conformance example

The following is the complete 11-content-id-field-order.json fixture, reproduced verbatim. It is a conformance example, not a runtime capture. Both source objects produce the same canonical text and hash.

Arrival order and derived fields

An attempt is identified by (trace_id, path, attempt). If its open and completion records both arrive, the completion determines the call’s name, parent name, start offset and outcome, regardless of arrival order. An open record arriving later cannot turn a completed attempt back into one in flight. Retry declarations merge separately, as below. trace-close is not an arrival barrier: the server accepts step records that arrive after it. Its records_lost reports loss known when the producer built that record; truncated reports that the 10,000-step cap was reached. The server derives attempt_grouping from the retry flags; producers do not emit that field. Any declared_retryable: true makes the step declared; otherwise, any continues_retry: true makes it observed_retry; otherwise it is single. The retry rules define when a producer reuses a path. Read-time value states expired and missing are also absent from emitted records.

Use the fixture corpus

The fixture manifest identifies the rule each case exercises. Cases 1–16 isolate path encoding, retries, handle shapes, tags, hashes, and logs. Cases 18–21 cover open attempts and arrival order. Fixture documents contain explanatory and expected-result fields alongside the records. They are not HTTP request bodies. Transport sends an array of records to POST /v1/records; the API specification defines authentication, headers, and per-record rejection responses.