Context
AgentV's OTel exporter creates self-contained traces — each agentv eval run starts a new root span. There is no way to attach an eval trace to an existing parent span from a CI/CD pipeline or orchestrator.
Braintrust's trace-claude-code plugin supports this via CC_PARENT_SPAN_ID / CC_ROOT_SPAN_ID environment variables.
Proposal
Use W3C TRACEPARENT environment variable for trace composition. This is the industry standard (W3C Trace Context) and works automatically with any OTel-instrumented pipeline.
# CI/CD pipeline sets TRACEPARENT before spawning eval
TRACEPARENT="00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" \
agentv eval evals/test.yaml --export-otel --otel-backend langfuse
Implementation
In otel-exporter.ts, before creating the root span:
import { W3CTraceContextPropagator } from '@opentelemetry/core';
// In exportResult(), before startActiveSpan:
const propagator = new W3CTraceContextPropagator();
const traceparent = process.env.TRACEPARENT;
let parentCtx = api.ROOT_CONTEXT;
if (traceparent) {
parentCtx = propagator.extract(api.ROOT_CONTEXT, {
traceparent,
tracestate: process.env.TRACESTATE ?? '',
}, {
get: (carrier, key) => carrier[key],
keys: (carrier) => Object.keys(carrier),
});
}
tracer.startActiveSpan('agentv.eval', { startTime: startHr }, parentCtx, (rootSpan) => {
// ... existing export logic (unchanged)
});
TRACEPARENT format
version-traceid-parentspanid-traceflags
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
version: always 00
traceid: 32 hex chars (128-bit)
parentspanid: 16 hex chars (64-bit)
traceflags: 01 = sampled
No TRACEPARENT → no change
When TRACEPARENT is not set, behavior is identical to today (new root trace). Zero config change required.
Files to modify
packages/core/src/observability/otel-exporter.ts — Extract TRACEPARENT/TRACESTATE, create parent context
packages/core/package.json — @opentelemetry/core may already be a transitive dep; verify W3CTraceContextPropagator is available
- Tests — Verify child span has correct
traceId and parentSpanId when TRACEPARENT is set
Acceptance criteria
Use cases
- CI/CD correlation: GitHub Actions workflow runs multiple eval suites — all traces appear under the same pipeline span
- Multi-agent orchestration: An orchestrator launches
agentv eval as a subtask — the eval trace nests under the orchestrator's span
References
Testing Approach
Unit Tests (InMemorySpanExporter)
const exporter = new InMemorySpanExporter();
// Simulate TRACEPARENT env var
process.env.TRACEPARENT = '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01';
// Run eval with OTel export
// ...
const spans = exporter.getFinishedSpans();
const root = spans.find(s => s.name === 'gen_ai.eval');
const parentCtx = root.parentSpanId;
expect(parentCtx).toBe('b7ad6b7169203331');
expect(root.spanContext().traceId).toBe('0af7651916cd43dd8448eb211c80319c');
// Cleanup
delete process.env.TRACEPARENT;
Integration Test
# Verify trace shows up as child of CI span in Jaeger
docker run -d -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest
TRACEPARENT='00-abc123...-def456...-01' agentv eval ... --export-otel
# Open Jaeger — verify eval span appears under the parent trace ID
What to Assert
Context
AgentV's OTel exporter creates self-contained traces — each
agentv evalrun starts a new root span. There is no way to attach an eval trace to an existing parent span from a CI/CD pipeline or orchestrator.Braintrust's
trace-claude-codeplugin supports this viaCC_PARENT_SPAN_ID/CC_ROOT_SPAN_IDenvironment variables.Proposal
Use W3C
TRACEPARENTenvironment variable for trace composition. This is the industry standard (W3C Trace Context) and works automatically with any OTel-instrumented pipeline.Implementation
In
otel-exporter.ts, before creating the root span:TRACEPARENTformatversion: always00traceid: 32 hex chars (128-bit)parentspanid: 16 hex chars (64-bit)traceflags:01= sampledNo
TRACEPARENT→ no changeWhen
TRACEPARENTis not set, behavior is identical to today (new root trace). Zero config change required.Files to modify
packages/core/src/observability/otel-exporter.ts— ExtractTRACEPARENT/TRACESTATE, create parent contextpackages/core/package.json—@opentelemetry/coremay already be a transitive dep; verifyW3CTraceContextPropagatoris availabletraceIdandparentSpanIdwhenTRACEPARENTis setAcceptance criteria
TRACEPARENTenv var is set, the root eval span'straceIdmatches the provided trace IDTRACEPARENTenv var is set, the root eval span'sparentSpanIdmatches the provided span IDTRACEPARENTis not set, behavior is unchanged (new root trace)TRACESTATEis propagated when present--otel-backend langfuseand--otel-backend braintrustUse cases
agentv evalas a subtask — the eval trace nests under the orchestrator's spanReferences
packages/core/src/observability/otel-exporter.tsTesting Approach
Unit Tests (InMemorySpanExporter)
Integration Test
What to Assert