The .agentlog format¶
Shadow's on-disk trace format. JSON-Lines, content-addressed, streaming-safe.
Full spec: SPEC.md — normative; worked examples included.
Envelope¶
Every record:
{
"version": "0.1",
"id": "sha256:<hex>",
"kind": "metadata|chat_request|chat_response|tool_call|tool_result|error|...",
"ts": "2026-04-24T10:00:00.000Z",
"parent": "sha256:<parent_id>" or null,
"payload": { ... }
}
idissha256:+ hex(SHA-256(canonical_json(payload))). Two records with identical payloads have identical ids, content addressing.parentlinks records into a DAG. The session-rootmetadatarecord hasnull; all others point back. Subsequentmetadatarecords (used as session-boundary markers) have a non-null parent.- Canonical JSON: sorted keys, no whitespace, UTF-8, RFC 8259 numbers.
Payload kinds¶
The version field stays "0.1" (envelope is unchanged). Shadow v2.3
added three backwards-compatible record kinds inside that envelope.
v0.1 kinds (see SPEC.md §4.1 – §4.7):
metadata: session root or session-boundary marker. Carries SDK info, runtime, tags, tool schemas.chat_request: what was sent to the model.chat_response: what came back. Carriescontent(list of blocks),stop_reason,latency_ms,usage.tool_call: a synthesised or recorded tool invocation.tool_result: the value the tool returned.error: failure record with retriable flag.replay_summary: written byshadow replayto mark a candidate trace's outcome.
v0.2 record-kind extensions (see SPEC.md §4.8 – §4.10):
chunk: one chunk of a streaming model response. Payload carrieschunk_index,time_unix_nano(absolute, so long-stream replay doesn't drift),delta(provider-shape passthrough), and an optionalis_finalflag.harness_event: a single record kind for harness-side events with acategorydiscriminator over a closed taxonomy:retry,rate_limit,model_switch,context_trim,cache,guardrail,budget,stream_interrupt,tool_lifecycle. Also carriesname(a sub-event identifier within the category, required),severity(info/warning/error/fatal), and a free-formattributesdict.blob_ref: content-addressed binary reference. Carriesblob_id(sha256 of bytes),mime,size_bytes, optionalagentlog-blob://URI, optional 64-bit dHashphashfor the cheap similarity tier, optionalembeddingslot for the semantic tier.
A v0.1-only parser is allowed to skip records whose kind it doesn't
recognise.
File layout¶
Traces live under .shadow/traces/<id[:2]>/<id[2:]>.agentlog
(git-objects-style sharding). SQLite index at .shadow/index.sqlite.
Size limits¶
Parser defaults (v1.1+):
DEFAULT_MAX_LINE_BYTES= 16 MiB (per-record cap)DEFAULT_MAX_TOTAL_BYTES= 1 GiB (whole-trace cap)
Both tunable per-Parser via with_max_line_bytes / with_max_total_bytes
for legitimately larger records (multimodal payloads, batch ingest).