Attribute keys and mappers
The judgment.* span attribute keys Judgment reads, and how attribute mappers fill them at ingest.
Judgment reads the judgment.* span attributes below as structured fields. Any other key is stored as a custom attribute and stays searchable.
Columns:
- Mapper target: whether an attribute mapper can write the key. Keys marked No are set by the SDKs or the ingest pipeline.
- Set by SDK helper: the judgeval helper that writes the key, as
python_name/typescriptName, checked against judgeval 1.3.3 (Python) and 1.3.4 (npm). None means no SDK helper writes it; set it withTracer.set_attribute/Tracer.setAttribute, a raw OpenTelemetry SDK, or a mapper.wrap()here means the OpenAI wrapper.
The Agent keys and judgment.state_before / judgment.state_after are declared in both SDKs, but no helper in the current SDK releases writes them, even where a description says the SDK sets them automatically.
Span attribute keys
Core
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.input |
Yes | observe (automatic), set_input / setInput |
The input a step receives. |
judgment.output |
Yes | observe (automatic), set_output / setOutput |
The output a step produces. |
judgment.llm.tool_calls |
Yes | None | Structured tool/function calls made during a step. |
judgment.span_kind |
Yes | observe(span_type=...) / observe(fn, { spanType }), set_span_kind / setSpanKind, wrap() |
The type of step (llm, tool, function, agent, …). Judgment infers this automatically when usage or provider/model attributes are present, so you rarely need to set it yourself. |
judgment.span_name |
Yes | None | The name shown for this step in the trace. Falls back to the raw OpenTelemetry span name when unset. |
judgment.agent_version |
Yes | None | The version of the agent or prompt implementation used for this step. Powers the agent-version breakdown in monitoring. |
Identifiers
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.session_id |
Yes | set_session_id / setSessionId |
Ties multiple traces to one conversation or session. Map here to view all of a user’s requests together. |
judgment.customer_id |
Yes | set_customer_id / setCustomerId |
Which of your customers (tenant/account) a trace belongs to. Map here to filter and break down activity by customer. |
judgment.customer_user_id |
Yes | set_customer_user_id / setCustomerUserId |
Which individual end user a trace belongs to. Map here to trace activity down to a single user. |
judgment.project_id |
No | None | The Judgment project a trace belongs to. Judgment sets this from your API key/SDK configuration; it is not a mapper target. |
judgment.test.run_id |
No | test_case / testCase |
The test run a trace belongs to. Read from the trace’s root span, together with judgment.test.case_id, to attach the trace to its test case. |
judgment.test.case_id |
No | test_case / testCase |
The test case within judgment.test.run_id that a trace answers. Read from the trace’s root span; the first matching trace is used for the case. |
Agent
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.agent_id |
No | None | Identifies the agent instance that produced this span. Judgment SDK agent instrumentation sets this automatically; it powers agent grouping and is not a mapper target. |
judgment.parent_agent_id |
No | None | The agent ID of the caller, for spans produced by a sub-agent. Used to reconstruct multi-agent call hierarchies. |
judgment.agent_class_name |
No | None | The class/type name of the agent implementation, set automatically by SDK agent instrumentation. |
judgment.agent_instance_name |
No | None | The specific instance/display name of the agent, set automatically by SDK agent instrumentation. |
judgment.is_agent_entry_point |
No | None | Marks the span where an agent run begins, as opposed to an internal step of that run. |
Trace Links
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.link.target_trace_id |
No | observe(..., fork=True) / fork: true |
The trace ID of a sub-agent (or otherwise related) trace this span links forward to, for cross-trace navigation. |
judgment.link.target_span_id |
No | observe(..., fork=True) / fork: true |
The span ID within the linked target trace, paired with judgment.link.target_trace_id. |
judgment.link.source_trace_id |
No | observe(..., fork=True) / fork: true |
The trace ID of the caller when this trace was started by another (e.g. a parent agent invoking a sub-agent). |
judgment.link.source_span_id |
No | observe(..., fork=True) / fork: true |
The span ID within the linking source trace, paired with judgment.link.source_trace_id. |
Usage & Cost
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.llm.provider |
Yes | recordLLMMetadata (provider) |
The model provider, e.g. OpenAI or Anthropic. Map here so Judgment can price token usage accurately. |
judgment.llm.model |
Yes | recordLLMMetadata (model), wrap() |
The exact model used, e.g. gpt-4o. Map here (together with provider) so cost is calculated correctly. |
judgment.usage.non_cached_input_tokens |
Yes | recordLLMMetadata (non_cached_input_tokens), wrap() |
Input tokens charged at the normal (uncached) rate. Map here to report input token cost. |
judgment.usage.cache_creation_input_tokens |
Yes | recordLLMMetadata (cache_creation_input_tokens) |
Input tokens written into the prompt cache. Map here to track prompt-cache write cost. |
judgment.usage.reasoning_tokens |
Yes | None | Tokens a reasoning model spends “thinking”. Map here to account for reasoning cost. |
judgment.usage.cache_read_input_tokens |
Yes | recordLLMMetadata (cache_read_input_tokens), wrap() |
Input tokens read from the prompt cache at the cheaper cached rate. Map here to track cache savings. |
judgment.usage.output_tokens |
Yes | recordLLMMetadata (output_tokens), wrap() |
Tokens the model generated in its response. Map here to report output token cost. |
judgment.usage.non_cached_input_image_tokens |
Yes | None | Image input tokens charged at the normal rate. Map here if your model bills image inputs separately. |
judgment.usage.output_image_tokens |
Yes | None | Image tokens the model generated. Map here if your model bills image outputs separately. |
judgment.usage.total_cost_usd |
Yes | recordLLMMetadata (total_cost_usd) |
A total cost you have already computed for this step, in USD. Map here to report cost directly instead of from tokens. |
State snapshots
| Key | Mapper target | Set by SDK helper | Description |
|---|---|---|---|
judgment.state_before |
No | None | A snapshot of the agent’s state before this step ran, for evaluators/judges that score state transitions. |
judgment.state_after |
No | None | A snapshot of the agent’s state after this step ran, paired with judgment.state_before. |
Reserved keys
Other judgment.* keys are reserved for the Judgment SDKs and the ingest pipeline. Don’t set them yourself or target them with a mapper.
Resource attributes
Judgment reads these from the OpenTelemetry resource, not from span attributes.
| Resource attribute | Set by | Meaning |
|---|---|---|
service.name |
Tracer.init, default: the project name |
Service that emitted the span. Override with resource_attributes (Python) or resourceAttributes (TypeScript). |
deployment.environment.name |
Tracer.init(environment=...) |
Environment of the trace. deployment.environment is read as a fallback. Empty shows as No environment. |
telemetry.sdk.name, telemetry.sdk.version |
Tracer.init |
SDK identity. |
judgment.project_id |
judgeval Workers tracer | Project ID stamped on the resource. Ingest routes by the X-Project-Id header, not this attribute. |
Built-in normalization
At ingest, built-in mappers copy common third-party attributes onto judgment.* keys. They cover OTel GenAI semantic conventions, OpenInference, LangSmith, Vercel AI SDK 6 and 7, Logfire, Braintrust cost, and generic LLM provider attributes.
| Incoming attribute | Judgment key |
|---|---|
gen_ai.response.model, then gen_ai.request.model |
judgment.llm.model |
gen_ai.system |
judgment.llm.provider |
gen_ai.usage.input_tokens, gen_ai.usage.output_tokens |
judgment.usage.non_cached_input_tokens, judgment.usage.output_tokens |
gen_ai.usage.cache_read_input_tokens, gen_ai.usage.cache_creation_input_tokens |
judgment.usage.cache_read_input_tokens, judgment.usage.cache_creation_input_tokens |
gen_ai.input.messages, gen_ai.prompt, gen_ai.tool.call.arguments |
judgment.input |
gen_ai.output.messages, gen_ai.completion, gen_ai.tool.call.result |
judgment.output |
gen_ai.conversation.id |
judgment.session_id |
gen_ai.tool.name present |
judgment.span_kind = tool |
gen_ai.operation.name = chat or text_completion |
judgment.span_kind = llm |
Add a configured mapper only for keys this list does not cover.
Mapper order
Ingest runs mappers in five layers. Each layer sees the output of the layers before it.
| Order | Layer | What runs |
|---|---|---|
| 1 | Platform normalization | The built-in mappers above. |
| 2 | Organization mappers | Org-wide configured mappers. |
| 3 | Project mappers | Mappers configured for the project. |
| 4 | Platform enrichment | Span kind inference and LLM cost calculation. |
| 5 | Conversation | Records model calls in the form the Conversation view reads. Runs only for organizations where conversation recording is enabled. |
Customer mappers run before span kind inference and cost calculation. A mapper that writes judgment.llm.provider, judgment.llm.model, and token counts therefore feeds cost calculation and llm span kind inference.
Span kind inference marks a span llm when it carries usage, provider, or model attributes for a billable GenAI operation. Rollup operations such as invoke_agent are excluded.
Mapper settings
| Setting | Default | Behavior |
|---|---|---|
| Enabled | On | Disabled mappers are skipped. |
| Override | Off | Off: writes the target only if it has no value yet. On: always writes the target. |
| Remove Source | On | Deletes the source key, only when the mapping was applied. |
- Targets must be keys with Mapper target = Yes.
- Mappers apply at ingest. Spans stored before a mapper existed do not change.
- Creating, editing, or deleting a mapper applies to spans ingested from then on.
- Org-wide mappers can only be edited by a Judgment administrator. Creating, editing, or deleting project mappers needs the developer role, in the app and through MCP.
Manage mappers
In the app: open Settings, choose the project, then open Mappers.
MCP tools: list_mappers, get_mapper, create_mapper, update_mapper, delete_mapper. See MCP tools for inputs and roles.