Skip to lesson

AnthropicClaude Certified Architect – Professional2026-103.4 Analyze observability challenges and select monitoring strategies at scale

Connect agent work to downstream results

Completed by the knowledge check

Learning objective

Instrument traces that link requests, prompt and model versions, model calls, tool calls, subagent threads, and downstream effects.

Core idea

A useful trace answers which request caused an action, under which configuration, through which model and tool calls, and with what downstream result. A conversation identifier alone cannot answer those questions: one conversation can contain several turns, retries, branches, and external writes.

For an architect, trace design is an attribution decision across team boundaries. Use the Agent SDK’s documented parent relationships where available, add application-owned prompt and release references, and require the services behind tools to report their own execution outcomes. A generated statement that an action succeeded is not the downstream system’s receipt.

How it works

Establish the application parent

Create an application span for the business request before calling Agent SDK query(). The SDK automatically propagates active OpenTelemetry context into its Claude Code subprocess through TRACEPARENT and TRACESTATE. The CLI’s claude_code.interaction span then becomes a child of the application span.

An explicit TRACEPARENT in options.env overrides auto-injection. Interactive Claude Code sessions ignore inbound TRACEPARENT; the documented inbound propagation applies to the Agent SDK and non-interactive claude -p. Do not copy this integration design into an interactive terminal and assume the same parent relationship.

Enable the subprocess export with CLAUDE_CODE_ENABLE_TELEMETRY=1, OTEL_TRACES_EXPORTER=otlp, and CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1, plus the appropriate OTLP endpoint and protocol. Traces are beta, and their span names and attributes can change between releases. Validate your backend queries against the deployed CLI version rather than assuming a permanent schema.

Attach configuration provenance

The SDK’s claude_code.llm_request span exposes the model name, latency, and token counts. Add an application-owned prompt revision reference to the request span, together with a deployment revision and retrieval-index revision when those affect behavior. Name these as your own attributes; do not imply the API automatically assigns a prompt version to arbitrary prompt text.

Record the configured model identifier with the release configuration. If it is an alias, retain that fact rather than claiming immutable model-version provenance. Use an immutable artifact reference for the rendered prompt template and its approved configuration. A label such as “production” is insufficient if it points to different content after a release. Separate the template revision from request variables so provenance does not require placing customer content in searchable span attributes.

For API-support investigation, Claude Code’s monitoring reference documents request_id, derived from the response’s request-id header, on model-request spans and relevant events. This identifies one API request. Your application trace identifier links the larger business execution; retain both rather than replacing one with the other.

Represent tool and subagent execution

A claude_code.tool span surrounds a tool invocation. Its claude_code.tool.blocked_on_user and claude_code.tool.execution children distinguish permission waiting from execution. That distinction prevents a slow approval from being diagnosed as a slow downstream service.

Subagent model and tool spans nest under the parent’s launching tool span. For custom lifecycle instrumentation, Claude Code provides SubagentStart and SubagentStop; the Agent SDK hooks page lists both events as supported in Python and TypeScript. Register SDK callbacks through the hooks option. In TypeScript, agent_id and agent_type belong to the base input for every hook. In Python, they are optional on PreToolUse, PostToolUse, PostToolUseFailure, and PermissionRequest, and required on SubagentStart and SubagentStop. Shared tool-hook configuration belongs to 7.1.1.

SubagentStart input includes agent_id and agent_type, alongside common fields such as session_id and transcript_path. Use the event to open an application subagent span or execution segment. It also fires on subagent resume and each message handled by an in-process agent-team teammate, so agent_id alone is not a unique span identifier: allocate a segment identifier for each observed start. On claude_code.llm_request spans, agent_id joins a model call to its thread and hook segment; it is absent on the main session. parent_agent_id identifies the spawning agent, but is absent on the main session and agents spawned directly from it.

SubagentStop includes agent_id, agent_type, agent_transcript_path, stop_hook_active, and last_assistant_message. Its common transcript_path points to the main session; agent_transcript_path points to the subagent transcript. Store a restricted reference only if needed, rather than copying the file into telemetry.

A stop hook can keep the subagent running through decision: "block" and reason. Treat stop as a lifecycle observation, and close a completed execution segment when your lifecycle policy accepts termination. Account for repeated events and unmatched stops: Claude Code also emits SubagentStop for internal agents. Never manufacture an application assignment from every stop event. On Claude Code v2.1.271 or later, a subagent using SubagentHandback delivers its report in that tool’s message input; last_assistant_message then contains closing text, not necessarily the report.

Each observed SubagentStart opens its own execution segment, and a SubagentStop closes one only when your lifecycle policy accepts termination.

Each observed SubagentStart opens its own execution segment, and a SubagentStop closes one only when your lifecycle policy accepts terminationEvery observed SubagentStart, including a resume, opens an execution segment. A SubagentStop is a lifecycle observation. A stop hook's decision block keeps the subagent running and returns to the open segment. When your lifecycle policy accepts termination, the segment becomes a completed execution segment. An unmatched stop, such as one for an internal agent, opens no segment and ends without an application assignment.SubagentStartdecision blockpolicy accepts terminationExecution segmentSubagentStoplifecycleobservationCompletedexecution segmentUnmatched stop

Join the actual external effect

Extend the trace into the service behind a tool using the service’s instrumentation and supported context propagation. Claude Code sends traceparent on model requests and outbound HTTP MCP requests by default when ANTHROPIC_BASE_URL is unset or points to the Anthropic API; the header is not sent to third-party providers. Behind a custom ANTHROPIC_BASE_URL proxy, set CLAUDE_CODE_PROPAGATE_TRACEPARENT=1 to enable propagation. The same switch controls forwarding TRACEPARENT to Bash and PowerShell commands. A command emitting OpenTelemetry spans can then nest under claude_code.tool.execution.

That documented command behavior is not a guarantee that every remote integration forwards context automatically. Make each adapter’s propagation explicit. For an asynchronous job, store an application correlation reference on the accepted job and link the completion record back to the originating request. The downstream owner supplies the actual receipt, job status, or durable transaction reference.

See 3.2.5 for the access trail from proposal to backend receipt. Here, link the model request, tool attempt, and target receipt through the trace. A trace that records only the first can falsely attribute success after a dependency failure. Preserve uncertain outcomes when the connection fails before the target’s receipt arrives; tracing alone cannot settle whether a write committed.

Key distinctions and trade-offs

Session versus request: session.id groups activity across SDK calls in one session. A request span identifies the particular business operation and its parent-child execution.

API request ID versus trace ID: The first supports one provider request; the second connects application, agent, and downstream work.

Native spans versus application attributes: Native instrumentation supplies execution structure. Prompt revisions, business operation references, and downstream receipt associations remain your integration’s responsibility.

A single trace backend simplifies investigation, but requires common instrumentation ownership. Detached local logs are cheaper to introduce and expensive to reconcile after an incident. Agree on parent propagation and completion references before adding payload content.

Architecture / decision scenario

A retail platform offers a refund assistant with a 20-second response target. Support reports that the assistant announced refunds that never appeared in the payment system. The payments lead proposes storing only the assistant’s final message because full transcripts are sensitive.

The architect keeps content collection restricted but rejects final-message-only attribution. The application request span holds the prompt revision and order-operation reference. SDK spans identify model and refund-tool activity; the payment adapter records the payment system’s transaction receipt or unresolved submission status. A delegated policy checker gets lifecycle segments tied to its agent_id.

One trace shows 12 seconds waiting for approval and a later submission timeout without a receipt. The support owner receives an unresolved outcome rather than a confirmed refund. Payments owns receipt reconciliation; the platform team owns propagation and lifecycle joins. The design distinguishes a missing effect from a slow approval without requiring unrestricted conversation storage.

Common exam traps

  • Using one conversation ID as every request and span ID.
  • Assuming an API request ID correlates the entire tool workflow.
  • Treating SubagentStart as a once-only event for an agent’s lifetime.
  • Confusing transcript_path with agent_transcript_path.
  • Treating every SubagentStop as an accepted completed assignment.
  • Assuming inbound TRACEPARENT works in interactive Claude Code.

What to remember

Connect the business request, configuration provenance, model calls, tools, subagent segments, and actual downstream receipts. Native beta tracing supplies much of the execution tree; your application supplies the business meaning and validates propagation across each external boundary.

Knowledge check

References