Repository navigation
Description
Disclosure: this issue was drafted by an AI agent (Claude) while testing kagent 1.x on Agent
Substrate, and reviewed by a human before filing.
Severity: Medium · tracing enabled, Claude harness with the real Anthropic API · no workaround found
What happens
As a user I turn on tracing and send a turn to an agent on the claude Harness. The trace holds only
the harness runtime's spans (invoke_agent and the A2A and gRPC spans around it). There is no
claude_code.* span, so the model calls and tool calls inside Claude Code are not traced (2 of 2
runs). The same setup on the kagent runtime has generate_content spans, and on the Codex harness
run_sampling_request spans.
The egress gateway log for the Claude actor during the turn shows that Claude Code never calls the
OTLP endpoint. Both Export calls come from the harness runtime's Go exporter:
2 api.anthropic.com /v1/messages?beta=true 200
2 api.anthropic.com /api/event_logging/v2/batch 200
1 api.anthropic.com /api/eval/sdk-… 200
1 api.anthropic.com /api/claude_code/metrics 200
2 jaeger.jaeger.svc.cluster.local /opentelemetry.proto.collector.trace.v1.TraceService/Export 200
user-agent of both Export calls: "OTel OTLP Exporter Go/1.45.0 grpc-go/1.83.2"
The collector is reachable from the actor, and Claude Code does send its own telemetry to
api.anthropic.com, but it sends no span to the configured collector.
Reproduce
kagent v1.0.0-alpha2 on Agent Substrate, the chart's otel.tracing pointed at an OTLP gRPC
collector (Jaeger http://jaeger.jaeger.svc.cluster.local:4317), a claude Harness, and an
AgentTemplate with an Anthropic ModelConfig (real API key). Send one turn, then list the span names
of its trace, and read
kubectl -n ate-system logs deploy/atenet-egress -c agentgateway | grep ai-<instance id>.
Expected vs actual
- Expected: the trace holds
claude_code.*spans for the model and tool calls, as the e2e test
requires. - Actual: only the harness runtime's spans; Claude Code makes no OTLP export.
Ask
Find why Claude Code does not export against the real API, and make the e2e test cover that path.
What kagent configures, and why the e2e test passes
The Claude process gets (go/core/internal/translator/claude/compiler.go, lines 97-99, plus the
shared trace environment):
CLAUDE_CODE_ENABLE_TELEMETRY=1
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
OTEL_TRACES_EXPORTER=otlp
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://jaeger.jaeger.svc.cluster.local:4317
OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc
OTEL_METRICS_EXPORTER=none
OTEL_LOGS_EXPORTER=none
KAGENT_PRE_RESPONSE_TRACE_FLUSH=true
go/core/test/e2e/tracing_test.go fails on "no claude_code.* span was exported before suspension",
but it runs Claude Code against a mock model at a custom Anthropic base URL
(createClaudeMockModel). Against the real API, the spans do not appear.
Candidate causes (none verified)
- Claude Code gates the enhanced-telemetry beta on a remote feature flag it fetches from
api.anthropic.com/api/eval/sdk-…; with a custom base URL that lookup may not happen. - Claude Code reads only the generic
OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_PROTOCOL,
not the per-signal…_TRACES_…variables. - Claude Code batches its spans, and the actor suspends before it flushes them;
KAGENT_PRE_RESPONSE_TRACE_FLUSHcovers only the harness runtime's exporter.
Scope
- Reproduced on kind with kagent
v1.0.0-alpha2, Agent Substrate0.2.0-beta5, harness image
ghcr.io/kagent-dev/kagent/claude-harness@sha256:6794f2d25be053766030dcd15aa0da58747a425bcf423e851ad0b6870d79d1b5
(Claude Code2.1.260). Code unchanged onmainatc61fad8b(2026-09-23). - Unaffected: the harness runtime's own spans on Claude; tracing on the kagent and Codex runtimes.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
krisztianfekete commentedon Sep 24, 2026
Thanks for opening this issue!
We have seen this working during adding support for this in #2805, and I also got this working locally before. Now I was able to reproduce it, but it was working in some cases, which makes me think if it could be a problem with the flushing mechanism.
@supreme-gg-gg, can you please take a look at this when you have some free cycles?
fix(harness): hold the Claude prompt until Claude Code can trace the …
fix(harness): hold the Claude prompt until Claude Code can trace the …