Skip to content

agent-trace/v1 JSONL Schema

1. Status and source documents

This document is normative for agent-trace/v1 files emitted by the v0.5 harness. The locked event shapes come from prompt-exports/2026-04-30-v0.5-harness-build-plan.md. The architecture context is docs/designs/2026-04-30-inferguard-harness-architecture.md. The OpenTelemetry mapping is docs/research/38-2026-04-30-industry-harness-research.md §D.1. The operator overview is oss/inferguard/docs/HARNESS.md. The telemetry posture is oss/inferguard/docs/telemetry/v0/POSTURE.md. The upload payload contract is oss/inferguard/docs/telemetry/v1/SPEC.md.

2. Normative language

The key words MUST, MUST NOT, SHOULD, SHOULD NOT, and MAY are normative. A producer is the harness component that writes JSONL events. A consumer is any validator, analyzer, daemon, or hosted ingest path that reads JSONL events. A file is a UTF-8 text file with one JSON object per line. Blank lines SHOULD NOT be emitted. Consumers MAY ignore blank lines. Each line MUST parse as one complete JSON object. Each object MUST have schema_version: "agent-trace/v1". Events MUST be append-only during a run. Producers SHOULD flush after each line for crash-safe debugging.

3. Privacy default

Default traces contain shape, count, and timing information only. Default traces MUST NOT contain prompt text. Default traces MUST NOT contain model output text. Default traces MUST NOT contain tool argument values. Default traces MUST NOT contain tool result payload content. Default traces MUST NOT contain full working directory paths. Default traces MUST NOT contain environment variables. A local debugging flag MAY persist prompts for local use. Any local prompt-saving flag MUST default to false. Any local prompt-saving output MUST be marked in metadata. Telemetry MUST NOT upload local prompt-saving output.

4. Locked schema examples

The following event shapes are locked for v0.5. They are copied verbatim from the build plan and define the compatibility target.

// node event — a model call, tool call, or branch decision
{
  "schema_version": "agent-trace/v1",
  "event_type": "node",
  "trace_id": "ulid-or-uuid-of-whole-run",
  "node_id": "ulid-or-uuid-of-this-node",
  "parent_node_ids": ["..."],
  "timestamp_start": 1730000000.123,
  "timestamp_end": 1730000001.456,
  "kind": "model_call" | "tool_call" | "branch" | "retry" | "user_input" | "system",
  "framework": "langgraph" | "crewai" | "autogen" | "claude_code" | "cursor_sdk" | "raw_openai" | "unknown",
  "model_call": {                          // present iff kind == "model_call"
    "endpoint": "http://localhost:8000/v1/chat/completions",
    "model": "deepseek-ai/DeepSeek-V4-Pro",
    "input_tokens": 8192,
    "output_tokens": 1024,
    "input_tokens_source": "api" | "estimated",
    "output_tokens_source": "api" | "estimated",
    "ttft_seconds": 0.420,
    "tpot_seconds": 0.012,
    "latency_seconds": 12.345,
    "tool_choice": "auto" | "required" | "none" | null,
    "stream": true,
    "stop_reason": "tool_use" | "end_turn" | "length" | "error" | null,
    "request_id": "...",
    "kv_pressure_label": "measured" | "inferred_without_engine_metrics"
  },
  "tool_call": {                           // present iff kind == "tool_call"
    "name": "filesystem.read_file",
    "wall_time_seconds": 0.083,
    "stall_seconds": 0.003,
    "result_size_bytes": 4096,
    "result_kind": "text" | "json" | "image" | "binary",
    "is_external": true,
    "is_io_bound": true
  },
  "branch": {                              // present iff kind == "branch"
    "branch_kind": "speculative" | "retry" | "fan_out",
    "siblings": ["..."]
  }
}

// summary event — emitted once at end of run
{
  "schema_version": "agent-trace/v1",
  "event_type": "summary",
  "trace_id": "...",
  "started_at": "2026-04-30T12:00:00Z",
  "completed_at": "2026-04-30T12:05:23Z",
  "total_seconds": 323.0,
  "node_counts": {"model_call": 12, "tool_call": 47, "branch": 3, "retry": 1},
  "total_tokens": {"input": 524288, "output": 4096},
  "tool_stall_total_seconds": 145.0,
  "tool_stall_pct": 0.45,
  "exit_status": "success" | "error" | "interrupted",
  "error_message": null,
  "framework_version": {"langgraph": "0.4.x"},
  "rig_label": "h200" | "b200" | "gb200" | "h100" | "auto" | null,
  "engine": "vllm" | "sglang" | "dynamo-vllm" | null,
  "redaction": {
    "prompts_redacted": true,
    "tool_args_redacted": true
  }
}

5. Event ordering

A trace file MAY interleave node kinds. A trace file SHOULD order events by completion time. timestamp_start MAY be earlier than the previous line's start time when branches run concurrently. timestamp_end SHOULD be greater than or equal to timestamp_start. A summary event MUST be the last non-blank event in a completed file. A crashed run MAY omit the summary event. Consumers MUST tolerate files without a summary event. Consumers SHOULD surface missing summary as interrupted unless another error is known.

6. Top-level node fields

Field Type Required Units Notes Example
schema_version string yes none MUST equal agent-trace/v1. agent-trace/v1
event_type string enum yes none MUST be node for node events. node
trace_id string yes none Stable ID for the whole agent run. 01J...
node_id string yes none Stable ID for this node event. 01J...
parent_node_ids array[string] yes none Empty for roots; multiple parents allowed for joins. ["01J..."]
timestamp_start number yes Unix seconds Fractional seconds are allowed. 1730000000.123
timestamp_end number yes Unix seconds Fractional seconds are allowed. 1730000001.456
kind string enum yes none Determines which detail object is present. model_call
framework string enum yes none Best-known harness or framework. langgraph
model_call object conditional none Present iff kind == "model_call". {...}
tool_call object conditional none Present iff kind == "tool_call". {...}
branch object conditional none Present iff kind == "branch". {...}

trace_id SHOULD be a ULID or UUID. node_id SHOULD be a ULID or UUID. parent_node_ids MUST reference node IDs in the same trace when known. parent_node_ids MAY reference nodes that appear later when concurrent hooks flush out of order. framework MUST be unknown when the producer cannot classify the runtime. kind MUST be one of the locked enum values. Consumers MUST reject unknown schema_version values unless explicitly operating in permissive mode. Consumers SHOULD ignore unknown additive fields for forward compatibility.

7. kind enum

Value Meaning Detail object
model_call A request to an LLM or compatible inference endpoint. model_call
tool_call A tool invocation made by the agent framework or wrapper. tool_call
branch A graph branch, fan-out, or speculative fork. branch
retry A retry node for a failed or repeated operation. none in v0.5
user_input A user-input wait or boundary observed by the wrapper. none in v0.5
system A harness/system event needed to preserve DAG shape. none in v0.5

A retry node MAY use parent_node_ids to point to the failed attempt. A user_input node MUST NOT include raw user content by default. A system node MUST NOT include environment dumps.

8. framework enum

Value Meaning
langgraph LangGraph application or hook path.
crewai CrewAI application or hook path.
autogen AutoGen application or hook path.
claude_code Claude Code style agent subprocess.
cursor_sdk Cursor Agent SDK style subprocess or hook.
raw_openai No framework hook; raw OpenAI-compatible HTTP capture.
unknown Producer could not classify the harness.

Framework values are classification labels. They are not authorization labels. They MUST NOT imply that prompt content was captured.

9. model_call object fields

Field Type Required Units OTel relationship Example
endpoint string yes none server.address + server.port when exported. http://localhost:8000/v1/chat/completions
model string yes none gen_ai.request.model. deepseek-ai/DeepSeek-V4-Pro
input_tokens integer yes tokens gen_ai.client.token.usage with gen_ai.token.type=input. 8192
output_tokens integer yes tokens gen_ai.client.token.usage with gen_ai.token.type=output. 1024
input_tokens_source enum yes none Source quality for token usage. api
output_tokens_source enum yes none Source quality for token usage. estimated
ttft_seconds number optional seconds gen_ai.server.time_to_first_token. 0.420
tpot_seconds number optional seconds/token Related to gen_ai.server.time_per_output_token. 0.012
latency_seconds number yes seconds gen_ai.client.operation.duration. 12.345
tool_choice enum or null optional none No direct required OTel field. auto
stream boolean yes none Indicates streaming response mode. true
stop_reason enum or null optional none Maps to response metadata when exported. tool_use
request_id string optional none Provider request correlation ID. req_...
kv_pressure_label enum optional none InferGuard-specific signal quality label. measured

endpoint SHOULD be normalized before telemetry upload. endpoint in a local trace MAY include localhost and user-supplied endpoint values. Telemetry payloads MUST NOT include full internal endpoint URLs. input_tokens MUST be greater than or equal to zero. output_tokens MUST be greater than or equal to zero. latency_seconds MUST be greater than or equal to zero. ttft_seconds MUST be omitted or null when not observed. tpot_seconds MUST be omitted or null when not observed. input_tokens_source MUST be api when returned by the inference API. input_tokens_source MUST be estimated when counted locally. output_tokens_source follows the same rule. request_id MUST NOT be used as a consent or user identity token.

10. tool_call object fields

Field Type Required Units Notes Example
name string yes none Tool name or normalized tool identifier. filesystem.read_file
wall_time_seconds number yes seconds Total observed tool duration. 0.083
stall_seconds number optional seconds Time waiting on I/O or external resource. 0.003
result_size_bytes integer optional bytes Size of result payload, not content. 4096
result_kind enum optional none Shape label for result. text
is_external boolean yes none True when the tool touches an external system. true
is_io_bound boolean yes none True when dominated by I/O waits. true

name MUST NOT include raw arguments. wall_time_seconds MUST be greater than or equal to zero. stall_seconds MUST be greater than or equal to zero when present. stall_seconds SHOULD be less than or equal to wall_time_seconds. result_size_bytes MUST be greater than or equal to zero when present. result_kind MUST be one of text, json, image, or binary when present. is_external SHOULD be true for network, filesystem, database, browser, and shell tools. is_io_bound SHOULD be true when the tool blocks on external I/O. Tool arguments are never part of this object by default. Tool results are never part of this object by default.

11. branch object fields

Field Type Required Units Notes Example
branch_kind enum yes none Branch classification. fan_out
siblings array[string] yes none Node IDs in the same branch family. ["01J...", "01J..."]

branch_kind MUST be speculative, retry, or fan_out. siblings SHOULD contain node IDs. siblings MAY be empty only when the producer cannot observe sibling IDs. Branch events SHOULD preserve DAG shape even when no model call occurs.

12. Summary event fields

Field Type Required Units Notes Example
schema_version string yes none MUST equal agent-trace/v1. agent-trace/v1
event_type string enum yes none MUST be summary. summary
trace_id string yes none Matches node events. 01J...
started_at string yes RFC 3339 Run start timestamp. 2026-04-30T12:00:00Z
completed_at string yes RFC 3339 Run completion timestamp. 2026-04-30T12:05:23Z
total_seconds number yes seconds Wall-clock duration. 323.0
node_counts object yes count Counts by node kind. {"model_call": 12}
total_tokens object yes tokens Input and output totals. {"input": 524288}
tool_stall_total_seconds number optional seconds Aggregate tool stall time. 145.0
tool_stall_pct number optional ratio Stall time divided by total time. 0.45
exit_status enum yes none Run outcome. success
error_message string or null optional none Redacted high-level error. null
framework_version object optional none Framework version map. {"langgraph":"0.4.x"}
rig_label enum or null optional none Hardware label. h200
engine enum or null optional none Inference engine. vllm
redaction object yes none Redaction truth flags. {"prompts_redacted": true}

started_at and completed_at MUST be UTC or include an offset. total_seconds SHOULD equal completed_at - started_at within clock precision. node_counts SHOULD include every kind observed in the file. total_tokens.input SHOULD equal the sum of input_tokens from model calls. total_tokens.output SHOULD equal the sum of output_tokens from model calls. tool_stall_pct SHOULD be in the inclusive range [0.0, 1.0]. exit_status MUST be success, error, or interrupted. error_message MUST NOT include prompt text, output text, file paths, API keys, or tool arguments. redaction.prompts_redacted MUST be true for default traces. redaction.tool_args_redacted MUST be true for default traces.

13. OpenTelemetry GenAI mapping

The cited research file says OpenTelemetry GenAI conventions were experimental as of March 2026. InferGuard uses the names to maximize cross-vendor compatibility. input_tokens maps to gen_ai.client.token.usage with gen_ai.token.type=input. output_tokens maps to gen_ai.client.token.usage with gen_ai.token.type=output. latency_seconds maps to gen_ai.client.operation.duration. ttft_seconds maps to gen_ai.server.time_to_first_token. tpot_seconds relates to gen_ai.server.time_per_output_token. model maps to gen_ai.request.model. endpoint maps to server.address and server.port in local OTel export. Errors should map to error.type when represented as spans or metrics. Operators enabling OTel export may need OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental. OpenTelemetry export is operator-configured. OpenTelemetry export is not Touchdown telemetry.

14. Minimal valid model-call line

{"schema_version":"agent-trace/v1","event_type":"node","trace_id":"01HVTRACE","node_id":"01HVMODEL","parent_node_ids":[],"timestamp_start":1730000000.123,"timestamp_end":1730000001.456,"kind":"model_call","framework":"raw_openai","model_call":{"endpoint":"http://localhost:8000/v1/chat/completions","model":"deepseek-ai/DeepSeek-V4-Pro","input_tokens":8192,"output_tokens":1024,"input_tokens_source":"api","output_tokens_source":"api","ttft_seconds":0.420,"tpot_seconds":0.012,"latency_seconds":12.345,"tool_choice":"auto","stream":true,"stop_reason":"end_turn","request_id":"req_123","kv_pressure_label":"measured"}}

15. Minimal valid summary line

{"schema_version":"agent-trace/v1","event_type":"summary","trace_id":"01HVTRACE","started_at":"2026-04-30T12:00:00Z","completed_at":"2026-04-30T12:05:23Z","total_seconds":323.0,"node_counts":{"model_call":1},"total_tokens":{"input":8192,"output":1024},"tool_stall_total_seconds":0.0,"tool_stall_pct":0.0,"exit_status":"success","error_message":null,"framework_version":{"raw_openai":"unknown"},"rig_label":"auto","engine":"vllm","redaction":{"prompts_redacted":true,"tool_args_redacted":true}}

16. Validation rules

Validators MUST verify schema_version first. Validators MUST verify event_type next. Validators MUST enforce conditional detail objects for model_call, tool_call, and branch. Validators MUST reject negative durations. Validators MUST reject negative token counts. Validators MUST reject negative byte counts. Validators MUST reject invalid enum values. Validators MUST reject summary events with no trace_id. Validators SHOULD warn if timestamp_end < timestamp_start. Validators SHOULD warn if summary totals disagree with node totals. Validators SHOULD warn if redaction flags are false. Validators SHOULD warn if endpoint appears to contain credentials. Validators SHOULD warn if any string value resembles an API key. Validators SHOULD warn if any unexpected field appears to contain prompt or output text.

17. Forward compatibility

New optional fields MAY be added to node events. New optional fields MAY be added to summary events. New enum values require a schema revision unless consumers are explicitly prepared for unknown values. Renaming a field requires agent-trace/v2. Changing units requires agent-trace/v2. Changing privacy defaults requires agent-trace/v2 and a posture update. Consumers SHOULD preserve unknown fields when rewriting local traces. Telemetry payload builders MUST apply the stricter telemetry blocklist before upload.

18. File naming

The recommended file name is agent-trace.jsonl. A run directory MAY include related files such as summary.json or agent-trace.dot. The JSONL file is the normative trace. The DOT file is a visualization artifact only. The summary event in JSONL is the normative run summary for this schema.

19. Non-goals

This schema is not a prompt logging format. This schema is not an output transcript format. This schema is not a full OpenTelemetry trace export. This schema is not a permission system. This schema is not the hosted upload payload. This schema is the local harness trace contract.