> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tracectrl.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Context Propagation

> Correlate traces across multiple services and agents

## Overview

When your agents span multiple processes or services (e.g., Agent A calls Agent B via HTTP), you need to propagate the trace context so all spans appear in the same trace.

TraceCtrl provides two helpers that wrap OpenTelemetry's W3C Trace Context propagators:

## Injecting Context (Outgoing Requests)

On the calling side, inject the `traceparent` header into your outgoing request:

```python theme={"dark"}
from tracectrl.context import inject_trace_headers

headers = inject_trace_headers()
# headers now contains {"traceparent": "00-abc123...-def456...-01"}

requests.post("http://agent-b/api", headers=headers, json=payload)
```

You can also inject into an existing headers dict — the function mutates and returns it:

```python theme={"dark"}
headers = {"Content-Type": "application/json", "Authorization": "Bearer ..."}
inject_trace_headers(headers)
# traceparent is added to the existing dict
```

## Extracting Context (Incoming Requests)

On the receiving side, extract the trace context from incoming headers:

```python theme={"dark"}
from tracectrl.context import extract_trace_headers

# In your FastAPI/Flask/Django handler:
ctx = extract_trace_headers(dict(request.headers))
# All spans created after this point belong to the caller's trace
```

`extract_trace_headers` returns an OpenTelemetry `Context` object. You don't normally need to use it directly — OpenTelemetry's propagator activates the extracted context for you.

## API Reference

### `inject_trace_headers(headers: dict | None = None) -> dict`

Injects W3C `traceparent` (and optionally `tracestate`) into the given headers dict. If no dict is provided, creates and returns a new one.

### `extract_trace_headers(headers: dict) -> Context`

Extracts the trace context from incoming headers. Returns the OpenTelemetry `Context` object.

## Full Example: Two-Service Strands Agent

The Strands instrumentor is the canonical, PyPI-published path. Two services, two `Agent` instances, trace propagated across the HTTP boundary.

```python title="agent_a.py" theme={"dark"}
import tracectrl
from tracectrl import tag_agent
from tracectrl.instrumentation.strands import StrandsInstrumentor
from tracectrl.context import inject_trace_headers
from tracectrl.session import new_session, current_session_id
from strands import Agent
from strands.models import BedrockModel
import requests

tracectrl.configure(service_name="agent-a")
StrandsInstrumentor().instrument()

agent_a = Agent(
    name="researcher",
    model=BedrockModel(model_id="anthropic.claude-3-5-haiku-20241022-v1:0"),
    system_prompt="You are a research agent.",
)
tag_agent(agent_a)

new_session()

# Call Agent B with trace context
headers = inject_trace_headers()
headers["X-TraceCtrl-Session"] = current_session_id()
response = requests.post(
    "http://localhost:5001/process",
    headers=headers,
    json={"task": "summarise the latest LLM safety papers"},
)
```

```python title="agent_b.py" theme={"dark"}
import tracectrl
from tracectrl import tag_agent
from tracectrl.instrumentation.strands import StrandsInstrumentor
from tracectrl.context import extract_trace_headers
from tracectrl.session import set_session_id
from strands import Agent
from strands.models import BedrockModel
from fastapi import FastAPI, Request

tracectrl.configure(service_name="agent-b")
StrandsInstrumentor().instrument()

agent_b = Agent(
    name="writer",
    model=BedrockModel(model_id="anthropic.claude-3-5-haiku-20241022-v1:0"),
    system_prompt="You are a writing agent.",
)
tag_agent(agent_b)

app = FastAPI()


@app.post("/process")
async def process(request: Request):
    extract_trace_headers(dict(request.headers))
    sid = request.headers.get("X-TraceCtrl-Session")
    if sid:
        set_session_id(sid)

    body = await request.json()
    return {"result": str(agent_b(body["task"]))}
```

<Note>
  This uses the standard W3C Trace Context specification (`traceparent` header). It works with any OpenTelemetry-compatible service, not just TraceCtrl agents.
</Note>
